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)

相关推荐
驰骋工作流8 小时前
流程时效考核的表结构:从待办时限到 WF_CH 考核结果驰骋BPM驰骋低代码低代码工作流引擎
android·低代码·rxjava
传奇开心果编程10 小时前
【Flutter踩坑排雷】第7课:巨型 build 函数坑|全部 UI 写在同一个 build,维护难、隐性异常
android·flutter·ios·移动开发·跨平台·dart·声明式ui
方白羽13 小时前
Android 双开环境底层剖析与风控检测落地
android·安全·app
weixin_5633714714 小时前
Android Studio 2024 版 Device Explorer 打开方法
android·ide·android studio
AIsoft_868917 小时前
职场音频文件怎么整理?录音APP有哪些用法
android·音视频
booboosui17 小时前
第一批个人 Agent 用户正在卸载,问题不在模型,在它住在哪儿
android
洞见前行17 小时前
点击图标到内容出现,你的 App 在这几秒里做了什么:Android 冷启动全链路优化实战
android·性能优化·android studio
凯基迪科技17 小时前
芯片UID绑定修改 加密与逆向修改思路分析
android
Liben18 小时前
Weex开发踩坑记录
android·前端·ios
救救孩子把20 小时前
结构化输出为何“格式正确、答案错误”?JSON Schema 的能力边界
android·java·json·agent·agent服务