在 Kotlin 中接入 WebView(通常是在 Android 应用中)是一个常见的需求。
1. 基础集成
添加网络权限
首先,在 AndroidManifest.xml 中添加网络权限:
<uses-permission android:name="android.permission.INTERNET" />
布局文件中添加 WebView
在 XML 布局文件中添加 WebView 组件:
<!-- activity_main.xml -->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<WebView
android:id="@+id/webView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
Kotlin 代码中的基本配置
// MainActivity.kt
import android.os.Bundle
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
private lateinit var webView: WebView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webView = findViewById(R.id.webView)
// 基础配置
setupWebView()
// 加载网页
webView.loadUrl("https://www.example.com")
}
private fun setupWebView() {
// 启用 JavaScript
webView.settings.javaScriptEnabled = true
// 启用 DOM 存储
webView.settings.domStorageEnabled = true
// 设置 WebViewClient 以确保链接在 WebView 内打开
webView.webViewClient = WebViewClient()
// 可选:启用缩放控制
webView.settings.setSupportZoom(true)
webView.settings.builtInZoomControls = true
webView.settings.displayZoomControls = false
}
}
2. 高级配置和功能
自定义 WebViewClient 处理页面加载
private fun setupWebView() {
webView.webViewClient = object : WebViewClient() {
// 在页面开始加载时调用
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
// 显示加载进度条
showLoadingProgress()
}
// 在页面加载完成时调用
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
// 隐藏加载进度条
hideLoadingProgress()
}
// 处理 URL 重定向(API 24+)
override fun shouldOverrideUrlLoading(
view: WebView?,
request: WebResourceRequest?
): Boolean {
request?.url?.let { url ->
// 在这里可以拦截特定 URL 进行处理
if (url.toString().startsWith("https://special-link.com")) {
// 处理特定链接,比如打开原生页面
handleSpecialLink(url.toString())
return true // 阻止 WebView 加载该 URL
}
}
return false // 允许 WebView 加载该 URL
}
// 兼容旧版本的处理方法
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
url?.let {
if (it.startsWith("https://special-link.com")) {
handleSpecialLink(it)
return true
}
}
return false
}
// 处理加载错误
override fun onReceivedError(
view: WebView?,
request: WebResourceRequest?,
error: WebResourceError?
) {
super.onReceivedError(view, request, error)
// 显示错误页面
showErrorPage()
}
}
}
配置 WebChromeClient 处理进度和对话框
private fun setupWebView() {
webView.webChromeClient = object : WebChromeClient() {
// 显示加载进度
override fun onProgressChanged(view: WebView?, newProgress: Int) {
super.onProgressChanged(view, newProgress)
updateProgressBar(newProgress)
}
// 处理 JavaScript 的 alert 对话框
override fun onJsAlert(
view: WebView?,
url: String?,
message: String?,
result: JsResult?
): Boolean {
AlertDialog.Builder(this@MainActivity)
.setMessage(message)
.setPositiveButton("OK") { _, _ -> result?.confirm() }
.setCancelable(false)
.create()
.show()
return true
}
// 处理 JavaScript 的确认对话框
override fun onJsConfirm(
view: WebView?,
url: String?,
message: String?,
result: JsResult?
): Boolean {
AlertDialog.Builder(this@MainActivity)
.setMessage(message)
.setPositiveButton("OK") { _, _ -> result?.confirm() }
.setNegativeButton("Cancel") { _, _ -> result?.cancel() }
.setCancelable(false)
.create()
.show()
return true
}
}
}
3. Kotlin 与 JavaScript 交互
从 Kotlin 调用 JavaScript 函数
// 调用无参 JavaScript 函数
fun callJavaScriptFunction() {
webView.evaluateJavascript("javascript:yourJavaScriptFunction()") { result ->
// 处理返回结果
println("JavaScript 返回: $result")
}
}
// 调用带参 JavaScript 函数
fun callJavaScriptWithParams() {
val param = "Hello from Kotlin"
webView.evaluateJavascript("javascript:yourFunction('$param')") { result ->
println("结果: $result")
}
}
// 加载页面后调用
webView.webViewClient = object : WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
// 页面加载完成后调用 JavaScript 函数
callJavaScriptFunction()
}
}
从 JavaScript 调用 Kotlin 函数
// 创建 JavaScript 接口类
class WebAppInterface(private val context: Context) {
// 使用 @JavascriptInterface 注解暴露给 JavaScript
@JavascriptInterface
fun showToast(message: String) {
Toast.makeText(context, message, Toast.LENGTH_SHORT).show()
}
@JavascriptInterface
fun getUserData(): String {
return "用户数据来自 Kotlin"
}
@JavascriptInterface
fun navigateToNativeScreen(screenName: String) {
// 处理从 JavaScript 发来的导航请求
when (screenName) {
"profile" -> startActivity(Intent(context, ProfileActivity::class.java))
"settings" -> startActivity(Intent(context, SettingsActivity::class.java))
}
}
}
// 在 WebView 设置中添加接口
private fun setupWebView() {
// 添加 JavaScript 接口
webView.addJavascriptInterface(WebAppInterface(this), "Android")
// 在 HTML/JavaScript 中可以通过 window.Android 调用这些方法
// 例如:window.Android.showToast("Hello from Web!");
}
JavaScript 端的对应代码
<!DOCTYPE html>
<html>
<head>
<title>WebView 示例</title>
</head>
<body>
<h1>WebView 与 Kotlin 交互示例</h1>
<button onclick="callKotlinFunction()">调用 Kotlin 函数</button>
<button onclick="getDataFromKotlin()">从 Kotlin 获取数据</button>
<script>
// 从 JavaScript 调用 Kotlin 函数
function callKotlinFunction() {
if (window.Android) {
window.Android.showToast("Hello from JavaScript!");
window.Android.navigateToNativeScreen("profile");
}
}
// 从 Kotlin 获取数据
function getDataFromKotlin() {
if (window.Android) {
const data = window.Android.getUserData();
alert("从 Kotlin 接收的数据: " + data);
}
}
// 供 Kotlin 调用的函数
function yourJavaScriptFunction() {
return "这是来自 JavaScript 的响应";
}
function yourFunction(param) {
console.log("收到 Kotlin 参数: " + param);
return "处理完成: " + param;
}
</script>
</body>
</html>
4. 处理返回键导航
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
// 检查是否是返回键并且 WebView 可以返回
if (keyCode == KeyEvent.KEYCODE_BACK && webView.canGoBack()) {
webView.goBack() // 在 WebView 内返回上一页
return true
}
// 否则执行默认的返回行为(退出 Activity)
return super.onKeyDown(keyCode, event)
}
5. 安全注意事项
安全的 JavaScript 接口实现
class SafeWebAppInterface(private val context: Context) {
@JavascriptInterface
fun processUserInput(input: String) {
// 始终在主线程执行
Handler(Looper.getMainLooper()).post {
// 验证和清理输入
val safeInput = input.trim().take(100) // 限制输入长度
// 执行 UI 操作
Toast.makeText(context, "安全处理: $safeInput", Toast.LENGTH_SHORT).show()
}
}
}
安全的 WebView 配置
private fun setupSecureWebView() {
val webSettings = webView.settings
// 启用必要的设置
webSettings.javaScriptEnabled = true
webSettings.domStorageEnabled = true
// 安全设置 - 根据需求调整
webSettings.allowFileAccess = false
webSettings.allowContentAccess = false
webSettings.allowFileAccessFromFileURLs = false
webSettings.allowUniversalAccessFromFileURLs = false
// 防止通过文件 scheme 加载敏感文件
webView.webViewClient = object : WebViewClient() {
override fun shouldInterceptRequest(
view: WebView?,
request: WebResourceRequest?
): WebResourceResponse? {
request?.url?.let { url ->
if (url.scheme == "file" && url.path?.contains("/data/") == true) {
// 阻止访问敏感文件路径
return WebResourceResponse(null, null, null)
}
}
return super.shouldInterceptRequest(view, request)
}
}
}
6. 加载本地 HTML 文件
// 加载 assets 文件夹中的 HTML 文件
fun loadLocalHtml() {
webView.loadUrl("file:///android_asset/local_page.html")
}
// 或者加载 raw 资源
fun loadRawHtml() {
val htmlContent = resources.openRawResource(R.raw.local_page)
.bufferedReader().use { it.readText() }
webView.loadDataWithBaseURL(
null,
htmlContent,
"text/html",
"UTF-8",
null
)
}
完整示例
class MainActivity : AppCompatActivity() {
private lateinit var webView: WebView
private lateinit var progressBar: ProgressBar
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
webView = findViewById(R.id.webView)
progressBar = findViewById(R.id.progressBar)
setupWebView()
webView.loadUrl("https://www.example.com")
}
private fun setupWebView() {
val webSettings = webView.settings
// 基础设置
webSettings.javaScriptEnabled = true
webSettings.domStorageEnabled = true
webSettings.setSupportZoom(true)
// 添加 JavaScript 接口
webView.addJavascriptInterface(WebAppInterface(this), "Android")
// 设置 WebViewClient
webView.webViewClient = object : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
progressBar.visibility = View.VISIBLE
}
override fun onPageFinished(view: WebView?, url: String?) {
progressBar.visibility = View.GONE
}
}
// 设置 WebChromeClient 处理进度
webView.webChromeClient = object : WebChromeClient() {
override fun onProgressChanged(view: WebView?, newProgress: Int) {
progressBar.progress = newProgress
if (newProgress == 100) {
progressBar.visibility = View.GONE
}
}
}
}
override fun onBackPressed() {
if (webView.canGoBack()) {
webView.goBack()
} else {
super.onBackPressed()
}
}
}
这些示例涵盖了 Kotlin 中接入 WebView 的主要方面,你可以根据具体需求进行调整和扩展。

2341

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



