JSBridge小科普
做Hybird APP开发的同学,应该对JSBridge不陌生,它用于H5页面和Native(Android或者iOS)通信。常用的三方库如Dsbridge系列(https://github.com/wendux/DSBridge-Android)。那么,你知道JSBridge到底是如何在两端进行通信的吗?
下面的实例代码,Native端以Android为例。
1. Web调用Native能力
1.1 通过URI Schema请求(全局注册)
Native应用可以在移动端系统中注册一个Schema协议的URI,这个URI可以在系统的任意地方授权访问,用来调起一段原生方法,或者唤起一个原生界面。
于是,Native WebView控件中的H5页面,可以通过JS代码请求这个通用Schema协议。
比如,通过添加一个不可见的iframe,设置其src
属性,发送一个URI请求。
let iframe = document.createElement('iframe');
iframe.setAttribute('style', 'display:none');
document.body.appendChild(iframe);
iframe.setAttribute('src', 'myapp://className/method?args')
整个调用流程如下图。一旦系统捕获到注册表中的Schema URI,就会通过此URI地址执行该Schema协议定义的Native操作,执行一段Native代码或者打开APP的某个页面(如打开摄像头,唤起图片预览功能,跳转APP支付页面等)
jsBridge_native Schema.png
1.2 通过代码注入(针对webView组件)
以Android为例,可以通过addJavascriptInterface
方法将Native的一个对象注入到页面中,供JS调用。
/**
* 添加javascriptInterface
* 第一个参数:这里需要一个与js映射的java对象
* 第二个参数:该java对象被映射为js对象后在js里面的对象名,在js中要调用该对象的方法就是通过这个来调用
*/
webView.addJavascriptInterface(new JSInterface(), "android");
private final class JSInterface{
/**
* 注意这里的@JavascriptInterface注解, target是4.2以上都需要添加这个注解,否则无法调用
* @param text
*/
@JavascriptInterface
public void showToast(String text){
Toast.makeText(getApplicationContext(), text, Toast.LENGTH_SHORT).show();
}
}
--------------------------------------------------------------------
/**
* js中调用java方法
*/
android.showToast('toast');
Native会向webView全局作用域注入一个android
的全局对象,该对象上有showToast
的方法。
Android 4.2 之前注入对象的接口是 addJavascriptInterface
,但是由于安全原因慢慢不被使用(4.2以下版本,通过JS可以访问设备SD卡上面的任何内容,甚至是联系人信息,短信等。此为安全漏洞)。
现在,一般会通过拦截JS原生的window.confirm
或window.prompt
方法,从而达到H5向Native通信的目的。
如,在 Webview 上添加 onJsConfirm
或onJsPrompt
监听(其实,监听window.console
或者window.alert
也是可以的,但是这两个方法在JS coding中比较常用,所以为了避免不必要的事件触发,一般我们不会选择在客户端劫持它们)。代码如下:
webview.setWebChromeClient(new WebChromeClient());
public class JSBridgeWebChromeClient extends WebChromeClient {
@Override
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) {
String handledRet = parentEngine.bridge.promptOnJsPrompt(origin, message, defaultValue);
......
return true;
}
}
2. Native调用Web函数
反之,如果Native需要主动调用JS的方法,又该怎么做呢?
很简单,只要 H5 将 JS 方法暴露在 Window 上给 Native 调用即可。 是不是非常像客户端注册 Schema URI呢?
JS注册好函数,Native就可以调用了。
Android 4.4 以前,通过 loadUrl 方法,执行一段 JS 代码来实现(缺点是效率低,无法获得返回结果,且调用的时候会刷新 WebView):
/**
* js中声明全局函数
*/
<script>
function log(msg) {
console.log(msg);
}
</script>
--------------------------------------------------------------------
/**
* 设置与Js交互的权限
*/
webSettings.setJavaScriptEnabled(true);
private final class JSInterface{
@JavascriptInterface
public void showJsLog(String text){
webView.loadUrl("javascript:log('"+text+"')");
}
}
4.4 以后,可以使用 evaluateJavascript
方法实现(效率更高,可获取返回值,调用时候不刷新WebView)
String text = "hello world";
webView.evaluateJavascript("javascript:log('"+text+"')", new ValueCallback<String>() {
@Override
public void onReceiveValue(String value){
......
}
});
小结
Native和H5需要在接口设计上达成一致。只要API规定好,后续通信实现就不难了。
- 简单易学的机器学习算法——线性回归(2)
- Java基础-26(01)总结网络编程
- undo retention的思考(一)
- 优化算法——人工蜂群算法(ABC)
- 用GPU加速深度学习: Windows安装CUDA+TensorFlow教程
- 由报警邮件分析发现的备库oracle bug(r7笔记第12天)
- Python中的__init__()方法整理中(两种解释)
- 如何找到最优学习率?
- 简单易学的机器学习算法——Rosenblatt感知机
- 多级复制的数据不同步问题(r7笔记第11天)
- 简单易学的机器学习算法——Logistic回归
- Python 用OPEN读文件报错 ,路径以及r
- Oracle 12c PDB浅析(r9笔记第10天)
- merge语句导致的CPU使用率过高的优化(二) (r7笔记第9天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- golang string和[]byte的对比
- PHP中使用Redis长连接笔记
- 从外部设置传入Go变量
- 图解elasticsearch的_source、_all、store和index
- Stream API
- Lambda表达式
- ES的Query、Filter、Metric、Bucketing使用详解
- Golang的单引号、双引号与反引号
- CentOS配置docker和docker-compose
- 给Linux增加swap内存
- 网鼎杯2018-Fakebook
- 强网杯2019-高明的黑客
- CISCN2019华北赛区Day2-HackWorld
- ZJCTF-NiZhuanSiWei
- xxe漏洞学习