开启掘金成长之旅!这是我参与「掘金日新计划 · 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 天,点击查看活动详情