React PWA与Android WebView原生Wrapper双向通信问题求助
解决React PWA与Android WebView双向通信的可行方案
针对你遇到的addJavascriptInterface未生效的问题,下面提供几个经过验证的双向通信实现方案,附具体代码示例:
方案一:修复addJavascriptInterface配置问题
很多时候该方案失效是因为配置遗漏,按以下步骤检查并实现:
Android端配置
- 创建供JS调用的接口类,必须添加
@JavascriptInterface注解:
class AndroidBridge(private val context: Context) { // 供JS调用的方法 @JavascriptInterface fun sendLocationToPWA(lat: Double, lng: Double) { Log.d("AndroidBridge", "位置信息已传递给PWA: $lat, $lng") } @JavascriptInterface fun showToast(message: String) { Toast.makeText(context, message, Toast.LENGTH_SHORT).show() } }
- 配置WebView,启用JS并注入接口:
webView.settings.javaScriptEnabled = true // 注入接口,"AndroidBridge"是JS中访问的全局对象名 webView.addJavascriptInterface(AndroidBridge(this), "AndroidBridge") // 若PWA为HTTPS、本地资源为HTTP,需开启混合内容支持 webView.settings.mixedContentMode = WebSettings.MIXED_CONTENT_ALWAYS_ALLOW
React PWA端调用Android方法
在React组件中直接通过全局对象调用:
// 调用Android的showToast方法 window.AndroidBridge?.showToast("来自PWA的消息") // 接收Android主动传递的位置信息(Android端通过evaluateJavascript触发) window.receiveLocation = (lat, lng) => { console.log("从Android获取到位置:", lat, lng) // 更新React组件状态 setLocation({ lat, lng }) }
注意事项:
- 接口类方法必须为public,且必须添加
@JavascriptInterface注解- 避免在接口方法中直接操作UI,需通过
runOnUiThread切换到主线程- Android 4.2及以上版本才支持该注解,低版本存在安全风险
方案二:使用evaluateJavascript + WebChromeClient实现双向通信
该方案兼容性更好,且规避了addJavascriptInterface的安全隐患:
Android端实现
- 设置
WebChromeClient拦截JS的prompt请求,用于JS调用Android:
webView.webChromeClient = object : WebChromeClient() { override fun onJsPrompt( view: WebView?, url: String?, message: String?, defaultValue: String?, result: JsPromptResult? ): Boolean { // 约定消息格式为"action:params",解析后处理 if (message?.startsWith("pwa:") == true) { val parts = message.split(":") val action = parts[1] val params = parts.getOrNull(2) when (action) { "requestLocation" -> { // 调用原生位置服务获取坐标 val lat = 39.9042 val lng = 116.4074 // 调用PWA的JS方法返回结果 webView.evaluateJavascript("window.handleLocationResult($lat, $lng)", null) result?.confirm() return true } "showToast" -> { params?.let { Toast.makeText(this@MainActivity, it, Toast.LENGTH_SHORT).show() } result?.confirm() return true } } } return super.onJsPrompt(view, url, message, defaultValue, result) } } // Android主动调用PWA方法 fun sendDataToPWA(data: String) { webView.evaluateJavascript("window.handleAndroidData('$data')", null) }
React PWA端实现
// JS调用Android方法,通过prompt传递指令 const callAndroidMethod = (action, params) => { const message = `pwa:${action}:${params}` prompt(message) } // 接收Android传递的数据 window.handleAndroidData = (data) => { console.log("从Android收到数据:", data) } // 接收Android返回的位置结果 window.handleLocationResult = (lat, lng) => { console.log("位置结果:", lat, lng) setLocation({ lat, lng }) } // 使用示例 callAndroidMethod("requestLocation", "") callAndroidMethod("showToast", "Hello from PWA")
方案三:使用WebMessagePort(Android 7.0+)
这是Android官方推荐的现代双向通信方式,支持消息通道:
Android端配置
webView.settings.javaScriptEnabled = true webView.webViewClient = object : WebViewClient() { override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) // 创建消息通道 val channel = webView.createWebMessageChannel() // 向PWA发送端口(需指定PWA域名) webView.postWebMessage(WebMessage("init", arrayOf(channel[1])), Uri.parse("你的PWA域名")) // 监听PWA发送的消息 channel[0].setWebMessageCallback(object : WebMessagePort.WebMessageCallback() { override fun onMessage(port: WebMessagePort?, message: WebMessage?) { val data = message?.data if (data == "requestLocation") { // 返回位置信息 port?.postMessage(WebMessage("{\"lat\":39.9042, \"lng\":116.4074}")) } } }) } }
React PWA端实现
// 监听Android发送的消息通道 window.addEventListener("message", (event) => { if (event.data === "init") { const port = event.ports[0] window.androidPort = port // 监听端口消息 port.onmessage = (e) => { const location = JSON.parse(e.data) console.log("通过WebMessagePort获取位置:", location) setLocation(location) } } }) // 向Android发送消息 const sendMessageToAndroid = (message) => { window.androidPort?.postMessage(message) } // 使用示例 sendMessageToAndroid("requestLocation")
内容的提问来源于stack exchange,提问作者Abubakar Rafi
相关产品推荐
相关产品推荐

