Android WebView 从入门到最佳实践
WebView 是什么?
WebView = 嵌在 App 内的浏览器
基于系统 Chromium 引擎,可渲染 HTML / CSS / JavaScript / 音视频。
适用业务:
-
H5 页面嵌入(活动页、产品介绍)
-
混合开发(Hybrid)
-
支付与登录授权页面
-
文档/文章加载展示
WebView 整体架构
┌───────────────────────────┐
│ WebView │ ← 容器(渲染网页)
├───────────────────────────┤
│ WebViewClient │ ← 加载/navigation 控制(内开/外跳/拦截)
├───────────────────────────┤
│ WebChromeClient │ ← UI & 权限(进度、标题、上传、全屏)
└───────────────────────────┘
WebView负责显示,
WebViewClient负责怎么加载(路由/网络),
WebChromeClient负责展示浏览器 UI & 权限。
WebSettings:浏览器能力开关
webView.settings.apply {javaScriptEnabled = true // 必开(否则大多数 H5 白屏)domStorageEnabled = true // 支持 localStorage / sessionStorageuseWideViewPort = true // 页面自适应loadWithOverviewMode = truecacheMode = 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 → 点击链接会跳系统浏览器
webView.webViewClient = object : WebViewClient() {override fun shouldOverrideUrlLoading(v: WebView, r: WebResourceRequest): Boolean {val url = r.url.toString()return if (url.startsWith("http")) falseelse { 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 |
示例(显示进度条):
webView.webChromeClient = object : WebChromeClient() {override fun onProgressChanged(view: WebView, newProgress: Int) {progressBar.progress = newProgress}
}
文件上传、视频全屏、相机权限 都属于 WebChromeClient,不属于 WebViewClient。
JS ↔ Android 互调(JS Bridge)
✅ JS 调 Android(H5 调原生)
class JsBridge {@JavascriptInterfacefun toast(msg: String){ Toast.makeText(context, msg, Toast.LENGTH_SHORT).show() }
}
webView.addJavascriptInterface(JsBridge(), "Android")
JS 调用Android:
Android.toast("Hello WebView")
Android 调 JS :
webView.evaluateJavascript("javascript:showDialog()") {}
离线包 / 本地资源加载(关键能力)
安全加载本地 H5,不用 file://:
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,同源策略不会报错)
Cookie / 登录 / SSO / 支付回跳
val cm = CookieManager.getInstance()
cm.setAcceptCookie(true)
cm.setAcceptThirdPartyCookies(webView, true)
若不设置第三方 Cookie → 支付/登录无法回跳
WebView 销毁防止内存泄漏(必须写)
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)
