Android与JavaScript相互调用桥梁JsBridge

什么是JSBridge

JSBridge:听其取名就是js和Native之前的桥梁,而实际上JSBridge确实是JS和Native之前的一种通信方式。简单的说,JSBridge就是定义Native和JS的通信,Native只通过一个固定的桥对象调用JS,JS也只通过固定的桥对象调用Native。JSBridge另一个叫法及大家熟知的Hybrid app技术。

项目地址:https://github.com/lzyzsd/JsBridge

整个库的结构也比较简单:一个用来注入的js文件,一个自定义的Webview(包括webViewClient),以及作为载体的BridgeHandler。

为什么要使用JsBridge

大多数人都知道WebView存在一个漏洞,见WebView中接口隐患与手机挂马利用,虽然该漏洞已经在Android 4.2上修复了,即使用@JavascriptInterface代替addJavascriptInterface,但是由于兼容性和安全性问题,基本上我们不会再利用Android系统为我们提供的addJavascriptInterface方法或者@JavascriptInterface注解来实现,所以我们只能另辟蹊径,去寻找既安全,又能实现兼容Android各个版本的方案。

JsBridge的使用

JsBridge库集成

  1. 使用作者推荐方式:
1
2
3
4
5
6
repositories {  
maven {url "https://jitpack.io"}
}
dependencies {
compile 'com.github.lzyzsd:jsbridge:1.0.4'
}
  1. 使用源码集成

下载源码,将源码拷贝至自己的工程内,作为工程的文件。

  1. 自定义Module

下载源码,新建Module,将源码导入Module,并将项目依赖自定义的Module

使用JsBridge库

提供操作给Js调用

1
2
3
4
5
6
webView.registerHandler("submitFromWeb", new BridgeHandler(){
@Override
public void handler(String data, CallBackFunction function){
function.onCallBack("submitFrom web exe, response data from java");
}
}

Js如果需要调用Java提供的方法时候,则需要调用这个Handler,而在注册时参数submitFromWeb将作为Js调用时使用的Key值。调用方式如下:

1
2
3
4
5
6
7
8
WebViewJavascriptBridge.callHandler(
'submitFromWeb',
{'param':str1},
function(responseData){
//这里打印的应该是上面Handler实现方法中的callback的入参:submitFrom web exe, response data from java
document.getElementById("show").innerHTML = "response data from java, data = "+responseData
}
)

另外,库也提供了一个简单的没有回调的调用方式:

webView.setDefaultHandler(new DefaultHandler());

Js调用的方式也可以简化为:

1
2
3
4
5
6
WebViewJavascriptBridge.send(
data,
function(responseData){
//java中DefaultHandler所实现的方法中callback所定义的入参
}
)

提供操作给Java调用

注册方法与Java雷同:

1
2
3
4
5
WebViewJavascriptBridge.registerHandler("functionInJs", function(data, responseCallback) {
document.getElementById("show").innerHTML = ("data from Java: = " + data);
var responseData = "Javascript Says Right back aka!";
responseCallback(responseData);
});

Java调用Handler时,也跟Js一样:

1
2
3
4
5
6
7
webView.callHandler("functionInJs", new Gson().toJson(user),
new CallBackFunction(){
@Override
public void onCallBack(String data){
}
}
);

同样的,在JS中也可以注册默认的Handler,以方便Java调用时,通过send方法发送数据

1
2
3
4
5
6
7
8
bridge.init(function(message, responseCallback) {
console.log('JS got a message', message);
var data = {
'Javascript Responds': 'Wee!'
};
console.log('JS responding with', data);
responseCallback(data);
});

java调用send方法:

1
webView.send("hello");

JsBridge使用原理

在讲JsBridge的实现之前,首先要讲下各个文件的作用:

WebViewJavascriptBridge.js

被注入到各个页面的js文件;提供初始化,注册Handler,调用Handler等方法。

WebViewJavascriptBridge.java

bridge接口文件,定义了发送信息的方法,由BridgeWebView来实现。

BridgeWebView.java

WebView的子类,提供了注册Handler,调用Handler等方法。

BridgeWebViewClient.java

WebViewClient的子类,重写了ShouldOverrideUrlLoading,onPageFinish,onPageStart等方法。

BridgeHandler.java

作为Java与Js交互的载体。Java&Js通过Handler的名称来找到响应的Handler来操作。

DefaultBridgeHandler.java

BridgeHandler的子类,不做任何操作。仅为Java提供默认的接收数据的Handler。

CallBackFunction.java

回调函数,Handler处理完成后,用来给Js发送消息。

Message.java

消息对象,用来封装与js交互时的json数据,callid,responseid等。

BridgeUtil.java

工具类,提供从Url中提取数据,获取回调方法,注入js等方法。

JsBridge调用过程

  1. Native初始化webview,注册Handler;加载页面完成后,将WebViewJavascriptBridge.js文件注入页面。查询消息队列是否有信息需要被接收。
  2. H5页面初始化,注册Handler,查询消息队列是否有信息需要别接收。
  3. 用户操作,H5调用本地功能:Js将消息内容放在sendMessageQueue中,并设置iframe的src为yy://QUEUE_MESSAGE/
  4. Webview设置的WebViewClient拦截到约定url,调用Webview的刷新消息队列的方法flushMessageQueue,此方法就是加载了一个url:javascript:WebViewJavascriptBridge._fetchQueue();,这也是Js中定义的方法,另外定义了一个回调;回调方法主要做了两件事:①判断Native是否为此返回数据保有响应回调操作,若有,则执行,若没有,则为判断callId,不为空时为这个callId初始化一个回调。②通过handlername判断是否为默认的Handler还是自定义的Handler,调用相应Handler的handler方法,入参为消息数据内容和第一步中定义的回调。【这段较为难消化,需要阅读代码来理解】
  5. Js中_fetchQueue设置了iframe的src,内容为:yy://return/_fetchQueue/+第二步中放入sendMessageQueue中的消息内容。
  6. WebViewClient拦截到url为yy://return/,调用WebView的handlerReturnData方法;通过url中定义的方法名,找到第四个步骤中定义的回调,并调用。回调方法走完后,删除此回调方法。
  7. 如果Js在调用Handler的时候设置了回调方法,也就是在第四步骤中的含有callId,就会调用queueMessage的方法,然后往下就是走Native给Js发送消息的步骤。
    Ps: Native给Js发送消息的步骤跟上述从第三步骤到第七步骤完全相同,只不过Native和Js对象调换位置即可。

JsBridge的核心

JsBridge之所以能实现Native与Js相互调用的功能,其核心实现其实就是:

  1. 拦截Url

  2. load url(“javascript:js_method()”);

先说第二点,Native调用Js,通过加载以javascript:开头的url即可实现调用Js的方法。这个很好理解,在web中也是通过这种方式调用Js的方法的。

然后细说下第一点的实现:

  1. 向body中添加一个不可见的iframe元素。通过拦截url的方法来执行相应的操作,但是页面本身不能跳转,所以改变一个不可见的iframe的src就可以让webview拦截到url,而用户是无感知的。
  2. 拦截url。通过shouldOverrideUrlLoading来拦截约定规则的Url,再做具体操作。
    Ps: 添加iframe是H5自身可实现的,但是如果H5来实现的话,需要每个页面实现,且耦合较高;因此放在库里,通过加载完成注入的方式,则会降低耦合

评论

Ajax Android AndroidStudio Animation Anroid Studio AppBarLayout Babel Banner Buffer Bulma ByteBuffer C++ C11 C89 C99 CDN CMYK COM1 COM2 CSS Camera Raw, 直方图 Chrome Class ContentProvider CoordinatorLayout C语言 DML DOM Dagger Dagger2 Darktable Demo Document DownloadManage ES2015 ESLint Element Error Exception Extensions File FileProvider Flow Fresco GCC Git GitHub GitLab Gradle Groovy HTML5 Handler HandlerThread Hexo Hybrid I/O IDEA IO ImageMagick IntelliJ Intellij Interpolator JCenter JNI JS Java JavaScript JsBridge Kotlin Lab Lambda Lifecycle Lint Linux Looper MQTT MVC MVP Maven MessageQueue Modbus Momentum MySQL NDK NIO NexT Next Nodejs ObjectAnimator Oracle VM Permission PhotoShop Physics Python RGB RS-232 RTU Remote-SSH Retrofit Runnable RxAndroid RxJava SE0 SSH Spring SpringBoot Statubar Style Task Theme Thread Tkinter UI UIKit UML VM virtualBox VS Code VUE ValueAnimator ViewPropertyAnimator Vue Vue.js Web Web前端 Workbench api apk bookmark by关键字 cli compileOnly computed css c语言 databases demo hexo hotfix html iOS icarus implementation init jQuery javascript launchModel logo merge methods mvp offset photos pug query rxjava2 scss servlet shell svg tkinter tomcat transition unicode utf-8 vector virtual box vscode watch webpack 七牛 下载 中介者模式 串口 临潼石榴 主题 书签 事件 享元模式 仓库 代理模式 位运算 依赖注入 修改,tables 光和色 内存 内核 内部分享 函数 函数式编程 分支 分析 创建 删除 动画 单例模式 压缩图片 发布 可空性 合并 同向性 后期 启动模式 命令 命令模式 响应式 响应式编程 图层 图床 图片压缩 图片处理 图片轮播 地球 域名 基础 增加 备忘录模式 外观模式 多线程 大爆炸 天气APP 太白山 头文件 奇点 字符串 字符集 存储引擎 宇宙 宏定义 实践 属性 属性动画 岐山擀面皮 岐山肉臊子 岐山香醋 工具 工厂模式 年终总结 开发技巧 异常 弱引用 恒星 打包 技巧 指令 指针 插件 插值 摄影 操作系统 攻略 故事 数据库 数据类型 数组 文件 新功能 旅行 旋转木马 时序图 时空 时间简史 曲线 杂谈 权限 枚举 架构 查询 标准库 标签选择器 样式 核心 框架 案例 桥接模式 检测工具 模块化 模板 模板引擎 模板方法模式 油泼辣子 泛型 洛川苹果 浅色状态栏 渲染 源码 源码分析 瀑布流 热修复 版本 版本控制 状态栏 状态模式 生活 留言板 相册 相对论 眉县猕猴桃 知识点 码云 磁盘 科学 笔记 策略模式 类图 系统,发行版, GNU 索引 组件 组合模式 绑定 结构 结构体 编码 网易云信 网格布局 网站广播 网站通知 网络 美化 联合 脚手架 膨胀的宇宙 自定义 自定义View 自定义插件 蒙版 虚拟 虚拟机 补码 补齐 表单 表达式 装饰模式 西安 观察者模式 规范 视图 视频 解耦器模式 设计 设计原则 设计模式 访问者模式 语法 责任链模式 贪吃蛇 转换 软件工程 软引用 运算符 迭代子模式 适配器模式 选择器 通信 通道 配置 链表 锐化 错误 键盘 闭包 降噪 陕西地方特产 面向对象 项目优化 项目构建 黑洞
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×