前言:项目中经常用到h5和原生交互的情形, 在这里介绍一个非常好用的第三方库JsBrage,先附上GitHub链接:https://github.com/lzyzsd/JsBridge
与JS交互有两种方式:
1、h5调用我们原生代码,然后原生可以给他反馈
2、原生调h5代码,然后h5处理完之后给原生反馈。
一、引用
在项目的build.gradle里(这个之前讲过,直接引用GitHub上的项目要指定它)
repositories {
// ...
maven { url "https://jitpack.io" }
}
在app的build.gradle里
dependencies {
compile 'com.github.lzyzsd:jsbridge:1.0.4'
}
二、交互实例
1、demo中的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="library.mobilewcs.iscs.com.activity.custom_widget.jsbrage.JsBrageActivity"
android:orientation="vertical">
<Button
android:id="@+id/default_bt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="给js发送数据并获取反馈结果"
android:textColor="#000"
android:textSize="@dimen/common_dimen_dp20"
android:gravity="center"
android:layout_margin="@dimen/common_dimen_dp20"
/>
<Button
android:id="@+id/special_bt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="给js指定方法发送数据并获取反馈结果"
android:textColor="#000"
android:textSize="@dimen/common_dimen_dp20"
android:gravity="center"
android:layout_margin="@dimen/common_dimen_dp20"
/>
<com.github.lzyzsd.jsbridge.BridgeWebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="@dimen/common_dimen_dp300" />
</LinearLayout>
上面的布局中有两个按钮,一个BridgeWebView(注意这里要用第三方的,不能用原生的WebView),第一个按钮是通过默认方式给js发送数据,并获取反馈结果, 第二个按钮是给js指定的方法发送数据并获取反馈结果。
2、demo中的html例子:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script>
<!--注册事件监听,初始化-->
function setupWebViewJavascriptBridge(callback) {
if (window.WebViewJavascriptBridge) {
callback(WebViewJavascriptBridge)
} else {
document.addEventListener(
'WebViewJavascriptBridgeReady'
, function() {
callback(WebViewJavascriptBridge)
},
false
);
}
}
<!--回调函数,接收java发送来的数据-->
setupWebViewJavascriptBridge(function(bridge) {
//默认接收
bridge.init(function(message, responseCallback) {
document.getElementById("show").innerHTML = '默认接收到Java的数据: ' + message;
var responseData = 'js默认接收完毕,并回传数据给java';
responseCallback(responseData); //回传数据给java
});
<!--指定接收,参数functionInJs 与java保持一致-->
bridge.registerHandler("functionInJs", function(data, responseCallback) {
document.getElementById("show").innerHTML = '指定接收到Java的数据: ' + data;
var responseData = 'js指定接收完毕,并回传数据给java';
responseCallback(responseData); <!--回传数据给java-->
});
})
<!--js传递数据给java-->
function jsCallJavaDefault() {
var data = '发送数据给java默认接收';
window.WebViewJavascriptBridge.send(data, function(responseData) {
document.getElementById("show").innerHTML = responseData;
});
}
function jsCallJavaSpec() {
var data='发送数据给java指定接收';
<!--指定接收参数 submitFromWeb与java一致, function(responseData)处理java回传的数据-->
window.WebViewJavascriptBridge.callHandler('callFromWeb',data,function(responseData) {
document.getElementById("show").innerHTML = responseData;
});
}
</script>
</head>
<body>
<div>
<button onClick="jsCallJavaDefault()">js调用java,Java使用默认方式接收</button>
</div>
<br/>
<div>
<button onClick="jsCallJavaSpec()">js发送数据给java指定其某个方法接收</button>
</div>
<br/>
<div id="show">打印信息</div>
</body>
</html>
html中也有两个按钮,第一个是用默认方式给原生发送数据并获取反馈结果,第二个按钮是发送数据给原生指定的方法,并获取反馈数据, 最上面的js是初始化的,setupWebViewJavascriptBridge是注册接收数据的方法,里面有两个方法,第一个是默认接收,第二个原生可以通过functionInJs这个字符串调用到这个函数, 也可以根据业务添加更多这样的函数,原生可以通过第一个字符串调用到。最后两个方法jsCallJavaDefault()和jsCallJavaSpec()是两个html按钮的点击事件, 当用户点击第一个按钮的时候回通过默认的方式给原生发消息,点击第二个按钮的时候会调用前端以"callFromWeb"这个字符串注册的函数
3、原生代码
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import com.github.lzyzsd.jsbridge.BridgeHandler;
import com.github.lzyzsd.jsbridge.BridgeWebView;
import com.github.lzyzsd.jsbridge.CallBackFunction;
import library.mobilewcs.iscs.com.libraryproject.R;
public class JsBrageActivity extends Activity {
Button defaultBt;
Button specBt;
BridgeWebView mWebView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_js_brage);
defaultBt = findViewById(R.id.default_bt);
specBt = findViewById(R.id.special_bt);
mWebView = findViewById(R.id.webview);
OnButtonClick onButtonClick = new OnButtonClick();
defaultBt.setOnClickListener(onButtonClick);
specBt.setOnClickListener(onButtonClick);
// 加载Assert下的HTML文件
mWebView.loadUrl("file:android_asset/test.html");
// 注册js可以调用的方法, 一种是默认接收,一种是通过第一个参数指定接收
//默认接收
mWebView.setDefaultHandler(new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
String msg = "默认接收到js的数据:" + data;
Toast.makeText(JsBrageActivity.this, msg, Toast.LENGTH_LONG).show();
function.onCallBack("java默认接收数据,并回传数据给js"); //回传数据给js
}
});
//指定接收 submitFromWeb 与js保持一致
mWebView.registerHandler("callFromWeb", new BridgeHandler() {
@Override
public void handler(String data, CallBackFunction function) {
String msg = "指定接收到js的数据:" + data;
Toast.makeText(JsBrageActivity.this, msg, Toast.LENGTH_LONG).show();
function.onCallBack("java指定接收数据,并回传数据给js"); //回传数据给js
}
});
}
class OnButtonClick implements View.OnClickListener {
@Override
public void onClick(View view) {
if (view == defaultBt) {
// 给js以默认的方式传数据,并获取返回值
//默认接收
mWebView.send("java发送数据给js数据, 对方使用默认接收", new CallBackFunction() {
@Override
public void onCallBack(String data) { //处理js回传的数据
Toast.makeText(JsBrageActivity.this, data, Toast.LENGTH_LONG).show();
}
});
}
else if (view == specBt) {
// js注册了functionInJs, 然后Java指定它来接收这个数据
mWebView.callHandler("functionInJs", "发送数据给js指定接收", new CallBackFunction() {
@Override
public void onCallBack(String data) { //处理js回传的数据
Toast.makeText(JsBrageActivity.this, data, Toast.LENGTH_LONG).show();
}
});
}
}
}
}
这个是原生代码,进来加载webview,然后在onCreate里面注册了两个接收函数,第一个是默认接收,第二个是“callFromWeb”注册的,js可以根据这个字符串调用到这个方法。
点击原生的第一个按钮,调用mWebView.send()默认方式给js发送数据,通过回调onCallBack()来获取反馈结果。
点击第二个按钮调用mWebView.callHandler()来给js注册的"functionInJs"这个函数发送数据,并且通过onCallBack()获取返回结果。
三、替换成X5内核
JSBridge使用的是默认的webkit,如何换成X5WebView内核呢?
1、首先下载X5WebView的库,https://x5.tencent.com/tbs/sdk.html
2、直接复制库里面的jar包和so文件,放到自己的工程中, 然后复制Application里的初始化代码到自己的Application中,最后build.gradle里配置:
ndk { abiFilters "armeabi" }
最后运行看看Application里的初始化回调返回true表示成功,如果为false就初始化失败了,然后会自动切换到系统默认浏览器内核
3、下载JSBridge源码被主工程依赖,这里是重点,要把刚才的X5的jar和so库复制到JSBridge库里, ndk配置也在JSBridge的build.gradle里,否则引用不到。
4、把下面红框里的文件中的引用包的地方,都替换成x5库里的包:
通过以上步骤即可把JSBridge的内核替换成X5的内核
采坑注意:
1、对WebView设置的时候,依然要引用android.webkit.WebSettings
2、监听网页加载完成要继承BridgeWebViewClient,并且监听到完成后要延时500毫秒,不然有可能调不到后端方法,这个坑踩得好辛苦!!
mWebView.setWebViewClient(new MyWebViewClient(mWebView));
public class MyWebViewClient extends BridgeWebViewClient {
public MyWebViewClient(BridgeWebView webView) {
super(webView);
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
javaCallJs();
}
}, 500);
LogUtils.showLog("onPageFish()");
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
LogUtils.showLog("onReceivedError()");
}
}