JSBridge框架解决通信问题实现移动端跨平台开发
一、跨平台开发是趋势
目前主流的移动端平台主要是Android和iOS,为了尽可能复用代码和节省开发成本,各大巨头都开发了自己的跨平台框架,比如Facebook的React-Native、阿里的Weex、Cordova,以及今年Google开发者大会上介绍的Flutter框架。这些框架各有优缺点,但是到目前为止都没有大规模地推广开来,在我看来主要有以下几个原因:
1、开发者生态圈还不够成熟
RN是三大跨平台框架中关注人最多、生态最活跃的框架,但是到目前为止也没有到1.0版本(最新的release是0.57.8),更别说作为后来者的Weex和Flutter了。生态不成熟,意味着开发文档少,可以使用的开源控件少,比如在RN上想做一个最基本的下拉刷新和上拉加载更多的listview都比较费劲。Weex已经贡献给Apache,很久没有更新release了。Flutter现在还在beta版本,其发展还有待观察。
2、性能问题
虽然这几大框架都对渲染性能做了优化,但是相比原生还是差一些,RN和weex都自己实现了一个浏览器内核(JSCore),因此多了一层js解析,渲染较慢。比如RN的listview,如果数据量太大就会出现卡顿。Flutter虽然自带绘制引擎,但是跟原生比起来还是有一些距离。
3、兼容问题
虽然这三大平台的初衷都是为了跨平台(Write/Learn once, run everywhere),但在实际应用中还是需要耗费很多的精力去兼容和适配,比如RN在Android低端机器上表现就不尽如人意,连曾经RN的坚实拥护者Airbnb都宣布放弃使用RN了。
4、开发集成成本
三个框架都需要学习新的语言React/vue/dart,weex的最大优势就是入门简单,但是版本迭代慢,RN上手门槛高,开发调试难度大,集成RN和weex框架还会加入很多so文件,增加安装包的大小(至少在10M左右),这还不包括第三方的library。Flutter因为刚出来,应用的人还不多,其效果还有待观察。
总结:虽然上述自主研发的跨平台框架都或多或少地存在问题,但是移动开发的跨平台是大势所趋,可以节省开发成本,提高开发效率,迅速响应业务变化,现在主流的应用还是使用H5和原生的通信来实现跨平台的开发。Android和iOS平台都有自己内置的浏览器内核webkit框架,跨平台的本质就是用H5/JS编写的代码能够分别运行在Android和IOS的WebView中,从而实现一套代码两个平台都能运行的目的。
二、安卓跨平台开发实践
在Android平台上要实现Native和JS的通信主要通过WebViewClient和WebChromeClient两个类来实现。
WebViewClient的作用是帮助WebView处理各种通知、事件请求,其主要的方法有:onLoadResource、onPageStart、onPageFinished、onReceiveError、shouldOverrideUrlLoading等;
WebChromeClient处理JS页面的事件响应,比如网页中的对话框、网页图标、网站标题、网页的加载进度等事件,对应的响应方法有onJsAlert、onJsConfirm、onJsConsole、onProgressChanged、onReceiveIcon、onReceiveTitle等。
要实现Java和JS通信就要:
解决Java调JS;
JS调Java。
Java调用JS通过loadUrl和evaluateJavaScript两个方法。
通过webview.loadUrl(“javascript:alert(‘hello world’)”),可以在android平台将js代码注入到html页面,loadUrl方法可以直接调用js中定义的函数,也可以把android本地的assets目录下的js文件以字符串的形式注入到html页面中,但是这个注入时机一定要等到html页面加载完毕才能做,即在WebViewClient.onPageFinished的回调函数中调用,这样就相当于在html页面中直接引用了js资源文件。对于客户端来说,java调用js本质上是一个拼接js字符串的过程,但是调用loadUrl不能直接获取js函数的返回值,而要实现Java调用js函数后。
获取js函数的返回值可以使用webview.evaluateJavaScript方法,但是该方法只有在android4.4及以上的版本才可以使用。其他用法和loadUrl一致。
JS调用Java可以分为三种:对象映射、URL拦截、JS方法拦截。
对象映射是通过webview.addJavascriptInterface(new JSObject(), “javaObject”),这样可以js代码中可以直接调用javaObject对象,从而实现JS调用Java的功能,但是这个方法在android4.2以下会有安全漏洞,利用反射机制调用Android API getRuntime执行shell命令进行攻击,比如遍历sdcard、发送短信、安装木马APK等。
URL拦截是指在html页面通过iframe.src、window.open、documention.location或者href,这四种方法都可以在html页面中打开一个连接,从而会触发Java中的WebViewClient.shouldOverrideUrlLoading方法。例如在js中执行
在shouldOverrrideUrlLoading中可以根据约定的协议格式(Scheme)和协议名(Authority)获取从JS中传输过来的数据(Data)。
在JS中调用alert、console、prompt、confirm等方法就会触发WebChromeClient的onJsAlert、onConsoleMessage、onJsPrompt、onJsConfirm方法的回调。比如在js中可以调用
在onJsPrompt的message中可以获取prompt的内容,然后根据约定的协议格式可以获取数据。
三、JSBridge框架
为了解决JS和Native的通信问题,需要使用一个JSBridge框架(https://github.com/lzyzsd/JsBridge)用来负责H5和Java之间的通信,此时需要解决以下两个问题:
1)JS互相Java调用后如何回调,将responseData传递回去;
2)JS调用Java有三种方法,如果选择哪一种方法比较合适。
针对问题1,可以在java端和js端定义一个数据结构: Message={callbackId:xxx, handleName:xxx,responseData:xxx,responseId:xxx}。将回调函数保存在callbackId中,当JS或者Java处理完数据回调的时候再将保存在callbackId的回调函数存放在responseId,相应的回调的数据存放在responseData中,这样就能响应JS或者Java调用后的回调消息。
Js调用Java的方法虽然有三种,但是addJavaScriptInterface存在安全性问题一般不建议使用,JS中的alert、console方法都会在Html页面比较常用,confirm和prompt虽然不常用但是某些手机系统版本上会有对话框弹出,不通用,所以比较好的选择是url拦截,可以通过iframe.src触发shouldOverrideUrlLoading。
JsBridge框架的使用主要分为:
在H5页面加载完毕注入一个本地的js文件;
Java代码中注册BridgeHandler,用来处理JS发送过来的消息;
在本地注入的js文件中定义_handleMessageFromNative,用来接收java传递过来的消息;
因为客户端注入js是异步的,所以需要在js文件中注册Event监听器,成功后通知H5。
Native调用JS,例如通过
webview.loadUrl(
"javascript:WebViewJavascriptBridge._handleMessageFromNative('{
\"callbackId\":\"JAVA_CB_2_559\",\"data\":\"just data from java\"
}')");
这样就可以调用JS的handleMessageFromNative方法,传递的数据格式是Message,callBackId响应js的回调,发送前会存储到HashMap中,js回调的时候根据JAVA_CB_2_559找到对应的的回调函数处理js的响应数据,具体流程如下:
Js调用Java,通过sendMessageQueue将传递的信息转换成
Message= {data: {…}, callbackId: "cb_1_1234"}
其中callbackId是js的回调函数。然后通过
iframe.src=’yy://return/_fetchQueue/[{"data":"xxxx","callbackId":"cb_1_4321"}]’,
触发shouldOverrideUrlLoading方法,java处理完js传递过来的data后,将回调函数cb_1_4321设置到
Message={responseId: cb_1_4321, responseData:XXX},
这样在js中就能处理回调函数。具体的流程图如下:
JsBridge框架提供两种Handler方法,registerHandler方法需要传入handler的名字,这样需要iOS、Android、H5三方约定这个名字,因为H5开发的的业务需求变化比较快,而且H5调用原生的方法也是随机的,所以每次都用registerHandler约定名字需要使用全局变量存放这些handler方法名不便于扩展,所以实际开发中使用defaultHanlder,H5调用原生方法的的时候约定一个cmd,即约定data={cmd:xxx,time:data:{…}},只要在原生代码中对cmd命令有对应的功能,那么H5页面就可以随时调用原生的方法。
JSBridge的改进建议,由于webview调用js方法的时候必须在主线程才能生效,所以偶然会出现java调用js失败。另外,Js调用Java偶尔也会失败,因为iframe机制不能保证每次都能触发shouldOverrideUrlLoading回调。
目前JSBridge采用的是url scheme的方式,如果不考虑Android4.2以下,iOS7以下,可以采用的交互,比如直接使用addJavaScriptInterface在JS页面注入一个Native对象,将之前触发u步骤变为使用这个Native对象向Native发送消息。这种方法只是一个可行的方案,实际使用过程中目前的JSBridge方案基本上满足业务需求了。
作者:周智
来源:宜信技术学院
JSBridge框架解决通信问题实现移动端跨平台开发的更多相关文章
- React03 移动端跨平台开发
目录 React-day03 RN移动端开发 了解React-Native 了解React-Native工作流程 创建第一个React-Native项目 * 了解React-Native项目及结构 开 ...
- 移动端跨平台方案对比:React Native、weex、Flutter
跨平台一直是老生常谈的话题,cordova.ionic.react-native.weex.kotlin-native.flutter等跨平台框架百花齐放,颇有一股推倒原生开发者的势头. 为什么我们需 ...
- 最火移动端跨平台方案盘点:React Native、weex、Flutter
1.前言 跨平台一直是老生常谈的话题,cordova.ionic.react-native.weex.kotlin-native.flutter等跨平台框架的百花齐放,颇有一股推倒原生开发者的势头. ...
- (十)整合 JWT 框架,解决Token跨域验证问题
整合 JWT 框架,解决Token跨域验证问题 1.传统Session认证 1.1 认证过程 1.2 存在问题 2.JWT简介 2.1 认证流程 2.2 JWT结构说明 2.3 JWT使用方式 3.S ...
- MindSpore联邦学习框架解决行业级难题
内容来源:华为开发者大会2021 HMS Core 6 AI技术论坛,主题演讲<MindSpore联邦学习框架解决隐私合规下的数据孤岛问题>. 演讲嘉宾:华为MindSpore联邦学习工程 ...
- 《物联网框架ServerSuperIO教程》-22.Web端对传感器实时监测与控制。附:v3.6.8版本,支持WebSocket
1.ServerSuperIO v3.6.8更新内容 1.1 增加WebSocket服务端功能,支持自控模式.并发模式.单例模式,不支持轮询模式1.2 接收数据缓存与现有的IO实例分离.1.3 优化代 ...
- 跨平台移动端APP开发---简单高效的MUI框架
MUI是dcloud(数字天堂)公司旗下的一款跨平台开发移动APP的框架产品,在学习MUI框架之前,最先接触了Hbuilder代码编辑器,它带给我的第一感觉是快,这是HBuilder的最大优势,通过完 ...
- 异步tcp通信——APM.Core 服务端概述
为什么使用异步 异步线程是由线程池负责管理,而多线程,我们可以自己控制,当然在多线程中我们也可以使用线程池.就拿网络扒虫而言,如果使用异步模式去实现,它使用线程池进行管理.异步操作执行时,会将操作丢给 ...
- 解决ios、微信移动端的position: fixed; 支持性不好的问题 && 禁用下拉暴露黑底的功能
解决ios.微信移动端的position: fixed; 支持性不好的问题 在chrome中的多个部分使用了position: fixed之后,都可以正常的布局,但是放在微信上却出现了不能正常显示的问 ...
随机推荐
- Sass编译css/Grunt压缩文件
Sass安装(mac) $ sudo gem install sass scss编译成css文件 $ sass ui.scss ui.css CLI安装 $ npm install -g grunt- ...
- Nginx详细的安装教程(linux)
转:https://blog.csdn.net/u013641234/article/details/73838472 Nginx作为一个web服务器,目前使用最多的就利用其负载均衡,本篇着重讲解的是 ...
- Spring LDAP
LDAP Spring LDAP 使用 - Sayi像秋天一样优雅 - 开源中国社区 http://docs.spring.io/spring-ldap/docs/current/reference/ ...
- jni集成第3方third party动态库libwebrtc_audio_preprocessing.so时android.mk的编写
现在要调用一个第3方库libwebrtc_audio_preprocessing.so 最终布局如下: 即创建2个文件夹,将第3方库放进去. include目录放第3方库的头文件 其中lib目录如下 ...
- MFC学习之Radio---MFC Radio按钮组的使用例子
首先我们要完成一个功能,在一个添加新用户的场景里,通过Radio按钮来判断用户选择的是管理员还是普通用户. 要使用Radio组的功能首先我们必须作如下设置: 1.2个Radio按钮的ID号不同,但是他 ...
- 模式匹配之尺度空间---scale space
转载:http://www.cnblogs.com/cfantaisie/archive/2011/06/14/2080917.html 主要步骤 1).尺度空间的生成: 2).检测尺度 ...
- Java面向对象编程(一)
由于常常将Java和C++面向对象编程的原则搞乱,所以这次把相关要点分别总结一下,本文主要总结Java面向对象编程. 面向对象编程的三大特性是:继承性(inheritance), 多态性(polymo ...
- db2 命令
很久没有些博客了.把以前用到的操作 DB2 的命令发表下可能有很多人已经发布了.就当是自己做下功课吧,以备有用之需. 1. 打开命令行窗口 #db2cmd 2. 打开控制中心 # db2cmd db2 ...
- vs添加对dll的引用
我们在使用vs进行开发调试的时候经常会遇到一个问题,就是当我们的主工程引用到其他工程更新的dll(我们经常采用copy到工程目录的方法).亦或者当我们的多个工程引用到同一个dll文件的时候,我们怎么来 ...
- 微信小程序开发:学习笔记[8]——页面跳转及传参
微信小程序开发:学习笔记[8]——页面跳转及传参 页面跳转 一个小程序拥有多个页面,我们可以通过wx.navigateTo推入一个新的页面.在首页使用2次wx.navigateTo后,页面层级会有三层 ...