Android WebView 从入门到最佳实践

WebView 是什么?

WebView = 嵌在 App 内的浏览器

基于系统 Chromium 引擎,可渲染 HTML / CSS / JavaScript / 音视频。

适用业务:

  • H5 页面嵌入(活动页、产品介绍)

  • 混合开发(Hybrid)

  • 支付与登录授权页面

  • 文档/文章加载展示

WebView 整体架构

复制代码
┌───────────────────────────┐
│          WebView          │ ← 容器(渲染网页)
├───────────────────────────┤
│   WebViewClient           │ ← 加载/navigation 控制(内开/外跳/拦截)
├───────────────────────────┤
│   WebChromeClient         │ ← UI & 权限(进度、标题、上传、全屏)
└───────────────────────────┘

WebView负责显示

WebViewClient负责怎么加载(路由/网络)

WebChromeClient负责展示浏览器 UI & 权限

WebSettings:浏览器能力开关

Kotlin 复制代码
webView.settings.apply {
    javaScriptEnabled = true          // 必开(否则大多数 H5 白屏)
    domStorageEnabled = true          // 支持 localStorage / sessionStorage
    useWideViewPort = true            // 页面自适应
    loadWithOverviewMode = true
    cacheMode = WebSettings.LOAD_DEFAULT
}
CookieManager.getInstance().setAcceptCookie(true)

常用开关:

功能 设置
是否允许 JS javaScriptEnabled
LocalStorage/IndexedDB domStorageEnabled
混合内容(HTTPS + HTTP) mixedContentMode
自动播放视频 mediaPlaybackRequiresUserGesture = false

WebViewClient:控制页面"怎么打开"

职责:网络/导航/资源/错误控制

能力 方法
点击链接是否内开/外跳 shouldOverrideUrlLoading
页面生命周期 onPageStarted/onPageFinished
拦截资源请求 shouldInterceptRequest
错误处理 onReceivedError
SSL 证书错误 onReceivedSslError

⚠️ 没设置 WebViewClient → 点击链接会跳系统浏览器

Kotlin 复制代码
webView.webViewClient = object : WebViewClient() {
    override fun shouldOverrideUrlLoading(v: WebView, r: WebResourceRequest): Boolean {
        val url = r.url.toString()
        return if (url.startsWith("http")) false
        else { startActivity(Intent(Intent.ACTION_VIEW, r.url)); true }
    }
}

return false = WebView 内开
return true = 你处理(常见:跳外部 App,如微信/支付宝)

WebChromeClient:UI / 权限 / 上传

职责:浏览器 UI 和用户交互

功能 方法
进度条 onProgressChanged
网页标题 onReceivedTitle
JS 的 alert/confirm/prompt onJsAlert/onJsConfirm
上传图片 / 文件 onShowFileChooser
相机/麦克风权限 onPermissionRequest
视频全屏播放 onShowCustomView

示例(显示进度条):

Kotlin 复制代码
webView.webChromeClient = object : WebChromeClient() {
    override fun onProgressChanged(view: WebView, newProgress: Int) {
        progressBar.progress = newProgress
    }
}

文件上传、视频全屏、相机权限 都属于 WebChromeClient,不属于 WebViewClient。

JS ↔ Android 互调(JS Bridge)

✅ JS 调 Android(H5 调原生)

Kotlin 复制代码
class JsBridge {
    @JavascriptInterface
    fun toast(msg: String){ Toast.makeText(context, msg, Toast.LENGTH_SHORT).show() }
}
webView.addJavascriptInterface(JsBridge(), "Android")

JS 调用Android:

复制代码
Android.toast("Hello WebView") 

Android 调 JS :

Kotlin 复制代码
webView.evaluateJavascript("javascript:showDialog()") {}

离线包 / 本地资源加载(关键能力)

安全加载本地 H5,不用 file://

Kotlin 复制代码
val loader = WebViewAssetLoader.Builder()
    .addPathHandler("/assets/", WebViewAssetLoader.AssetsPathHandler(this))
    .build()

override fun shouldInterceptRequest(v: WebView, r: WebResourceRequest) =
    loader.shouldInterceptRequest(r.url)

H5 访问:

https://appassets.androidplatform.net/assets/index.html
WebViewAssetLoader = 最安全的离线包方案(支持 HTTPS,同源策略不会报错)


Kotlin 复制代码
val cm = CookieManager.getInstance()
cm.setAcceptCookie(true)
cm.setAcceptThirdPartyCookies(webView, true)

若不设置第三方 Cookie → 支付/登录无法回跳

WebView 销毁防止内存泄漏(必须写)

Kotlin 复制代码
override fun onDestroy() {
    (webView.parent as ViewGroup).removeView(webView)
    webView.stopLoading()
    webView.clearHistory()
    webView.removeAllViews()
    webView.destroy()
    super.onDestroy()
}

常见问题处理(实战)

问题 原因 解决方案
点击链接跳系统浏览器 没设置 WebViewClient 添加 shouldOverrideUrlLoading
上传图片没反应 没设置 WebChromeClient onShowFileChooser
JS 调原生不生效 未添加 @JavascriptInterface 加注释
H5 页面白屏 JavaScript 未开启 javaScriptEnabled = true
微信/支付宝不能回跳 Cookie 未开启第三方 setAcceptThirdPartyCookies

最终总结

模块 作用
WebSettings 开关能力(JS、缓存、localStorage)
WebViewClient 控制网络行为(内开/外跳、拦截资源、错误处理)
WebChromeClient UI 与权限(进度条、标题、上传、全屏视频)
JS Bridge JS 与原生互调
CookieManager 登录状态维持
WebViewAssetLoader 离线包

一句话记住:

WebViewControl = WebView + WebViewClient + WebChromeClient

下一篇:

WebView 最佳封装模板(BaseWebActivity + WebViewHelper)

相关推荐
STCNXPARM5 小时前
Android camera之硬件架构
android·硬件架构·camera
2501_944525546 小时前
Flutter for OpenHarmony 个人理财管理App实战 - 支出分析页面
android·开发语言·前端·javascript·flutter
松☆8 小时前
Dart 核心语法精讲:从空安全到流程控制(3)
android·java·开发语言
_李小白9 小时前
【Android 美颜相机】第二十三天:GPUImageDarkenBlendFilter(变暗混合滤镜)
android·数码相机
小天源12 小时前
银河麒麟 V10(x86_64)离线安装 MySQL 8.0
android·mysql·adb·麒麟v10
2501_9159214312 小时前
傻瓜式 HTTPS 抓包,简单抓取iOS设备数据
android·网络协议·ios·小程序·https·uni-app·iphone
csj5013 小时前
安卓基础之《(20)—高级控件(2)列表类视图》
android
JMchen12313 小时前
Android计算摄影实战:多帧合成、HDR+与夜景算法深度剖析
android·经验分享·数码相机·算法·移动开发·android-studio
恋猫de小郭15 小时前
Flutter 在 Android 出现随机字体裁剪?其实是图层合并时的边界计算问题
android·flutter·ios
2501_9159184115 小时前
把 iOS 性能监控融入日常开发与测试流程的做法
android·ios·小程序·https·uni-app·iphone·webview