一、开篇:为什么你的APP需要“体内消化”网页?
大家好,我是码农老李,今天咱们聊个有意思的话题——用WebView在APP里加载HTML代码。你肯定遇到过这种场景:产品经理笑眯眯地凑过来说:“这个活动页用H5实现吧,方便迭代~” 然后你默默打开浏览器,看着密密麻麻的网页代码,思考人生三连:
- 难道要让用户跳转到浏览器?
- 体验割裂被骂怎么办?
- 如何优雅地“偷懒”?
别急,WebView就是你的“梦中情View”!它就像给APP塞了个迷你浏览器,既能直接显示网页,又能加载本地HTML代码。比如你收到后端甩来的一段富文本:“<h1>限时抢购</h1><p>点击就送<span style="color:red">SSR</span></p>”,用WebView就能轻松渲染成漂亮页面!
举个栗子�*:
某电商APP的商品详情页,上半部分是原生开发的图片轮播,下半部分直接用WebView展示商品介绍的HTML内容——这种“杂交”模式,既保留了原生流畅性,又享受了H5的灵活更新。
二、WebView初体验:从“Hello World”开始翻车
2.1 基础配置三连击
首先,别忘记给APP“开权限”!在AndroidManifest.xml加上网络权限(虽然加载本地HTML不需要,但加载在线资源时必备):
<uses-permission android:name="android.permission.INTERNET" />
接着在布局文件里塞入WebView控件:
<WebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
最后在Activity里搞点事情:
val webView = findViewById<WebView>(R.id.webview)
webView.loadUrl("https://www.baidu.com") // 经典操作
但是! 如果你直接这么写,很可能遇到两大经典翻车现场:
- 页面打开默认跳转系统浏览器(用户:我APP呢?)
- 加载http链接报错(Android 9以后默认禁止明文传输)
解决方案:
// 阻止跳转外部浏览器
webView.webViewClient = WebViewClient()
// 允许http链接(如果需要)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
webView.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
}
2.2 加载HTML的三种骚操作
方式一:直接加载HTML代码(重点!)
当你拿到一段HTML字符串时,可以这样搞:
val html = """
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
body { background: #f0f0f0; }
.highlight { color: red; }
</style>
</head>
<body>
<h1>我是本地HTML</h1>
<p class="highlight">红色重点内容</p>
<img src="https://example.com/image.jpg">
</body>
</html>
""".trimIndent()
webView.loadData(html, "text/html", "UTF-8")
注意坑位:如果HTML里包含特殊字符(比如#、%等),需要用loadDataWithBaseURL:
webView.loadDataWithBaseURL(
null, // 基础URL,用于解析相对路径
html,
"text/html",
"UTF-8",
null // 历史记录URL,一般传null
)
方式二:加载assets里的HTML文件
把HTML文件扔进app/src/main/assets文件夹,然后:
webView.loadUrl("file:///android_asset/local_page.html")
方式三:加载手机存储的HTML文件
webView.loadUrl("content://com.example.provider/local.html") // 需要ContentProvider
三、进阶玩法:让WebView变成“智能助理”
3.1 与JavaScript互相调情
想要WebView执行JS代码?先开启设置:
webView.settings.javaScriptEnabled = true
然后就可以愉快地调教JS了:
// 调用JS方法
webView.evaluateJavascript("javascript:showToast('Hello')") { result ->
// 处理JS返回值
}
// 让JS调用Java方法
webView.addJavascriptInterface(object {
@JavascriptInterface
fun nativeMethod(param: String) {
runOnUiThread {
Toast.makeText(this, "JS传参:$param", Toast.LENGTH_SHORT).show()
}
}
}, "AndroidBridge")
在HTML中这样调用:
<button onclick="window.AndroidBridge.nativeMethod('我是前端')">调用原生方法</button>
3.2 拦截页面请求实现“暗箱操作”
通过重写shouldOverrideUrlLoading,可以监听页面跳转:
webView.webViewClient = object : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
val url = request.url.toString()
if (url.contains("special://scheme")) {
// 拦截特定scheme,执行原生逻辑
handleSpecialScheme(url)
return true // 表示已处理,不继续加载
}
return false // 继续加载
}
}
3.3 性能优化:从“拖拉机”到“超跑”
开启缓存(避免重复加载):
webView.settings.cacheMode = WebSettings.LOAD_CACHE_ELSE_NETWORK
webView.settings.domStorageEnabled = true // 开启DOM存储
懒加载图片:
webView.settings.loadsImagesAutomatically = false // 禁止自动加载图片
// 在页面完成后手动加载图片
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
view.evaluateJavascript("document.images[0].src = document.images[0].getAttribute('data-src')") { }
}
}
四、避坑指南:那些年我们踩过的雷
4.1 安全漏洞三件套
漏洞一:任意命令执行
错误示范❌:
webView.addJavascriptInterface(someObject, "bridge") // 4.2以下系统有风险
正确姿势✅:
- 仅对Android 4.2以上系统使用
@JavascriptInterface注解 - 或使用
evaluateJavascript替代
漏洞二:明文传输
在AndroidManifest.xml中给Application添加:
android:usesCleartextTraffic="true"
(但更推荐全站HTTPS)
漏洞三:域控制不严
通过WebViewClient的onReceivedSslError处理SSL错误时,不要总是proceed!
4.2 内存泄漏终结方案
在Activity销毁时记得清理:
override fun onDestroy() {
webView?.apply {
loadDataWithBaseURL(null, "", "text/html", "utf-8", null)
clearHistory()
(parent as? ViewGroup)?.removeView(this)
destroy()
}
super.onDestroy()
}
4.3 加载进度条实现
// 在布局中加入ProgressBar
webView.webChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView, newProgress: Int) {
progressBar.progress = newProgress
if (newProgress == 100) progressBar.visibility = View.GONE
}
}
五、实战:打造一个富文本显示器
假设你要实现一个新闻详情页,后端返回的HTML可能包含视频、表格等复杂内容:
fun setupRichTextWebView(htmlContent: String) {
val styledHtml = """
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
body {
font-family: 'San Francisco';
line-height: 1.6;
padding: 20px;
}
img { max-width: 100%; height: auto; }
video { max-width: 100%; }
table { width: 100%; border-collapse: collapse; }
td, th { border: 1px solid #ddd; padding: 8px; }
</style>
</head>
<body>
$htmlContent
</body>
</html>
""".trimIndent()
webView.apply {
settings.let { s ->
s.javaScriptEnabled = true
s.loadWithOverviewMode = true
s.useWideViewPort = true
s.setSupportZoom(true)
}
loadDataWithBaseURL(null, styledHtml, "text/html", "UTF-8", null)
}
}
六、结语:WebView虽好,可不要贪杯哦
WebView就像APP开发的“瑞士军刀”——功能强大但需要谨慎使用。记住几个关键点:
- 简单展示用
loadData,复杂页面用loadDataWithBaseURL - 必设WebViewClient,防止跳转外部浏览器
- 安全配置要到位,避免被黑客钻空子
- 内存管理不能忘,否则APP变卡顿怪兽
最后送大家一句口诀:“权限客户端,缓存加安全,交互靠JS,销毁要彻底”。掌握了WebView,下次产品经理再提H5需求时,你可以优雅地回一句:“安排!”
166

被折叠的 条评论
为什么被折叠?



