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)

相关推荐
来来走走9 小时前
kotlin学习 基础知识一览
android·开发语言·kotlin
雨白14 小时前
StateFlow 与 SharedFlow:在协程中管理状态与事件
android·kotlin
WAsbry16 小时前
NFC开发系列专栏 - 第三篇:无界面NFC后台服务方案
android·程序员·架构
消失的旧时光-194316 小时前
WebView 最佳封装模板(BaseWebActivity + WebViewHelper)
android·webview
WAsbry16 小时前
NFC开发系列-第一篇:NFC开发基础与实战入门
android·程序员
WAsbry16 小时前
NFC开发系列 - 第二篇:NFC企业级架构设计与最佳实践
android·程序员·架构
feibafeibafeiba17 小时前
Android 14 关于imageview设置动态padding值导致图标旋转的问题
android
tangweiguo0305198718 小时前
ProcessLifecycleOwner 完全指南:优雅监听应用前后台状态
android·kotlin
介一安全19 小时前
【Frida Android】基础篇15(完):Frida-Trace 基础应用——JNI 函数 Hook
android·网络安全·ida·逆向·frida