Android使用WebView实现与前端交互方式和一些避坑记录

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 10 天,点击查看活动详情

前言

以前做电商项目的时候经常和前端打交道,因为很多商品详情页面都是来自H5,避免不了使用WebView。今天就来说说当时如何使用WebView与前端做交互,有哪几种方式,并就使用中遇到的问题和一些功能的实现做一些说明,希望能帮助大家有效避坑。

既然打算做混合开发,那么一定提前了解过WebView这个控,这里我们就不提及那些基础的东西,直接来干货。

  • Webview中注入JS API

现在市面上很难找到基于Android4.2的机型了吧,所以我们不用再担心接口泄漏的情况。可直接使用addJavascriptInterface的方式,并在每个方法上添加@JavascriptInterface注解即可。这里需要注意的是addJavascriptInterface方法的第一个入参是该接口,第二个是自定义的实体名。在前端那边就需要使用windows.{自定义实体名}.{接口内方法},这样就达到了前端调用移动端的效果。

//移动端注册前端需要使用的接口
addJavascriptInterface(JsInterface(this), "test")

class JsInterface(private val mContext: Context) {
    
    //提供给前端调用的方法
    @JavascriptInterface
    fun back() {
       (mContext as WebActivity).finish()
    }
}

//前端调用移动端方法
windows.test.back()

那么移动端如何调用前端呢?,使用也很简单:

val json = "张三"
//移动端调用前端提供的onGetData方法,入参json
webView.loadUrl(
    "javascript:window.onGetData('"+ json+"')"
)

onGetData()方法就是前端接收的方法,需要注意的是loadUrl方法中因为传入的是字符串,在onGetData方法入参时需要使用单引号进行分割,否则编译器报错。

说到这里不得不说的就是传图片、视频等文件的功能,以往都是使用前端调用原生方法,通过api打开相机返回图片再以byte数字的方式返回给前端。但中途遇到一个情况就是前端的架构中使用的另外一种方式 openfile,以前没遇到没关系,其实就是使用Webview设置WebChromeClient,前端使用openfile的时候Android端就会在onShowFileChooser方法中收到回调,这时候需要外部申明并赋值中onShowFileChooser中传回的ValueCallback,并初始化打开相机获取图片信息。

private var valueCallback: ValueCallback<Array<Uri?>>? = null

webChromeClient =object :WebChromeClient(){
    override fun onShowFileChooser(
        p0: WebView?,
        filePathCallback: ValueCallback<Array<Uri?>>?,
        p2: FileChooserParams?
    ): Boolean {
        valueCallback = filePathCallback
        //初始化获取图片相关
        initPhoto()
        return true
    }
}

接着,使用刚刚得到的valueCallback传入得到的文件,这里文件最后的格式必须使用Uri形式提供。

fun initPhoto() {
       ......
       override fun onResult(result: List<Uri?>) {
              valueCallback?.onReceiveValue(result)
              valueCallback==null
        }
        override fun onCancel() {
              valueCallback?.onReceiveValue(null)
              valueCallback=null
        }

}

这样前端就能在对应的回调中拿到移动端传过去的文件,需要注意的是valueCallback用后需要回收,否则下次使用会出现问题。

一款三方混合开发工具,配置少,两端都需要接入该三方库,使用简单:

repositories {
    maven { url "https://jitpack.io" }
}

dependencies {
    compile 'com.github.lzyzsd:jsbridge:1.0.4'
}

需要注意的是,此时在Xml布局中要使用包名为:com.github.lzyzsd.jsbridge.BridgeWebView的webview,

//移动端提供test1方法
webView.registerHandler("test1", new BridgeHandler() {
    @Override
    public void handler(String data, CallBackFunction function) {
        function.onCallBack("submitFromWeb exe, response data from Java");
    }
});

//前端调用
WebViewJavascriptBridge.callHandler('test1', {'param': str1}, function(responseData) {
        document.getElementById("show").innerHTML = "send get responseData from java, data = " + responseData
    }
);

//前端注册test2方法
 WebViewJavascriptBridge.registerHandler("test2", function(data, responseCallback) {
        document.getElementById("show").innerHTML = ("data from Java: = " + data);
        var responseData = "Javascript Says Right back aka!";
        responseCallback(responseData);
    });
//移动端调用test2方法
webView.callHandler("test2", new Gson().toJson(user), new CallBackFunction() {
        @Override
        public void onCallBack(String data) {
        }
    });

这种方法还有一个优势就是前端不用考虑ios适配问题,只需要ios也接入该库就能满足仅需要一套代码就能适配两端的优点。

总结

Webview中注入JS API方式是官方控件提供的api,需要单独为前端注册一个接口用于前端访问,可接收返回值,前端需要针对Android端进行适配。使用JsBridge方式网上有好几个三方库都可实现,各个端口需要接入同一个三方库,库里已经封装好各方法,前端可以一套代码完成移动端的适配。

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 10 天,点击查看活动详情