Android客户端中经常会遇到js调用java代码的场景,例如一些Hybrid APP或H5等,JsBridge即通过js调用java或者通过java调用js函数。
java调用js
1. webview的loadUrl
1 | WebView.loadUrl("javascript:function()"); |
2. webview的evaluateJavascript
使用evaluateJavascript可以获得js函数的返回值1
2
3
4
5
6mWebView.evaluateJavascript("javascript:callJS()", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value) {
//此处为 js 返回的结果
}
});
js调用Java
Android中js调用java通常有以下几种做法:
1. 通过WebView的addJavascriptInterface()进行对象映射
定义一个与JS对象映射关系的Android类:AndroidtoJs,在Android里通过WebView设置Android类与JS代码的映射
java代码:1
2
3
4
5
6
7
8
9
10
11
12mWebView.addJavascriptInterface(new AndroidtoJs(), "test");
public class AndroidtoJs extends Object {
// 定义JS需要调用的方法
// 被JS调用的方法必须加入@JavascriptInterface注解
@JavascriptInterface
public void hello(String msg) {
System.out.println("JS调用了Android的hello方法");
}
}
js端代码:1
2
3
4
5
6<script>
function callAndroid(){
// 由于对象映射,所以调用test对象等于调用Android映射的对象
test.hello("js调用了android中的hello方法");
}
</script>
2. 通过 WebViewClient 的shouldOverrideUrlLoading ()方法回调拦截 url
实现逻辑如下:
- Android通过 WebViewClient 的回调方法shouldOverrideUrlLoading ()拦截 url
- 解析该 url 的协议
- 如果检测到是预先约定好的协议,就调用相应方法
java端代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26webview.setWebViewClient(new WebViewClient(){
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
String url="";
try{
if (Build.VERSION.SDK_INT > 21) {
url = request.getUrl().toString();
}
if(url.startsWith("m4bln://")){
// 实现自己代码
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);
return true;
}
}catch (Exception e){
return false;
}
view.loadUrl(url);
return true;
}
});
触发shouldOverrideUrlLoading的代码参照《Web调起App》
3. 通过 WebChromeClient 的onJsAlert()、onJsConfirm()、onJsPrompt()、onConsoleMessage()方法回调拦截JS对话框alert()、confirm()、prompt()、console.log()消息
常用的拦截是:拦截 JS的输入框(即prompt()方法)
因为只有prompt()可以返回任意类型的值,操作最全面方便、更加灵活;而alert()对话框没有返回值;confirm()对话框只能返回两种状态(确定 / 取消)两个值
1 | mWebView.setWebChromeClient(new WebChromeClient() { |
几种方法对比
JsBridge接口封装
实现简单的注册接口
1
JSBridge.register("ClassName",javaClass.class)
通过反射调用
1
2
3
4
5
6
7
8
9
10
11
12
13
14public static boolean callJavaMethod(String className, String methodName, Object... params) {
......
Method method = classNameLists.get(methodName);
......
try {
method.invoke(null, params);
return true;
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return false;
}避免混淆
为了避免混淆时class名字改变,所有的类可以注册一个空接口1
2public interface IBridge{
}
此时在混淆文件中加入以下代码,就可以1
2-keep public class * implements com.myapp.jsbridge.IBridge{*;}
-keepclasseswithmembernames public class * implements com.myapp.jsbridge.IBridge{*;}
参考sdk