JS与Android交互方式addJavascriptInterface遇到的坑

2,025 阅读1分钟

背景

设备测试流程系统,页面由h5(react)编写,外面套个安卓的壳。h5代码存储在安卓项目的assets静态资源目录下,安卓端Java代码中通过loadUrl方式加载index.html静态页面,如下:

private var url: String = "file:////android_asset/dist/index.html"
...
webView.loadUrl(url)

当h5页面中有http请求时,会报跨域问题,提示错误: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. 原因是file和http是两种协议,属于跨协议的跨域问题。

安卓端解决办法

参考1:android——webview开发:跨域请求问题的解决方式之一

参考2:大体意思是允许file文件进行跨域请求任意源的数据 WebSettings.AllowUniversalAccessFromFileURLs Property

下面是kt代码,对安卓不是很了解,懂的可以看下

 val webSettings: WebSettings = webView.settings
        webSettings.allowUniversalAccessFromFileURLs = true
        webSettings.allowFileAccess = false
        webSettings.setSupportZoom(false)
        webSettings.useWideViewPort = true
        webSettings.javaScriptEnabled = true
        webSettings.databaseEnabled = true
        webSettings.domStorageEnabled = true
        webSettings.loadWithOverviewMode = true
        webSettings.loadsImagesAutomatically = true
        webSettings.defaultTextEncodingName = "UTF-8"
        webView.loadUrl(url)
        webView.webChromeClient = WebChromeClient()
        Log.i("webView", "before:${LazyUtil.toJson(deviceInfoDTO)}")
        webView.addJavascriptInterface(JSInterface(LazyUtil.toJson(deviceInfoDTO)), "launcher")//定义laucher名称

前端如何通过jsInterface方式与安卓交互

本人比较懒,直接附上代码,(#^.^#)

 if (window.launcher) { // 判断 launcher 对象是否存在
            // 此处的 launcher 要和 安卓端定义的 launcher名称保持一致
            // JS 调用 Android 的方法
            // launcher.callAndroid(params);
            let info =      window.launcher.getDeviceInfo() //调用安卓的getDeviceInfo方法
           
            callBack(info)

        } else {
            alert("launcher not found!");
        }

构建项目时需要调整的地方

(1)修改publicPath

因为这里的前端项目是放在本地的,所以前端用webpack在生产(production)环境打包时,output的publicPath不能是相对路径(直接打开index.html会报错),解决办法改成绝对路径,如下。

(2)修改输出路径

目的是直接将dist包放到安卓项目预期目录下,如下:

output: {
       path: getDir(['../app/src/main/assets/dist']),
        publicPath: process.env.NODE_ENV === 'development' ? '/' : './',
        filename: ...,
        chunkFilename: ...,
    ...
    }