Hybird框架搭建
栏目: JavaScript · 发布时间: 5年前
内容简介:也是现在大家普遍认知的,Hybrid就是一种给 WebView 增加一些js通信可以调用原生API的方式
狭义Hybrid
也是现在大家普遍认知的,Hybrid就是一种给 WebView 增加一些js通信可以调用原生API的方式
广义Hybrid
我能否认为,只要是前端的开发思路与客户端原生的开发思路相结合,就认为他是一种 Hybrid?
我能否认为,通过原生的配合,把原本js or 前端开发做不到的事情做到了,用原生的方式增强了原本的前端技术能力,是否就是一种 Hybrid?
我能否认为,无论是 WebView+Bridge 也好,RN类似的原生渲染框架也好,小程序也好,某种意义上讲,他们都算 Hybrid?
因为Hybrid本是一个面向业务服务的东西,如果业务的野心足够大,WebView 容器的想象空间应该是在能力上与RN/小程序看齐的,没错,WebView 在 Hybrid 的支持下,不单纯是设计几个 Bridge 调用几个原生 API 的事,我其实在不少聊天群里深度聊过这个话题,泛前端动态化这个方向上,各种技术轮子都是一脉相承通着的,所以你看RN or 小程序是一个大厂新做的重型轮子?在我看来他们都是一回事,完全可以拆解RN中的每个环节,把RN号称比 WebView 好的原生渲染/原生组件拆解融入 WebView,我也可以学习小程序保持 Html/CSS/JS 的开发方式(当然我知道小程序是WXML/WXSS),而非RN那样统一用JSX开发。我甚至还能把RN与小程序都没有的动态bridge融入到Hybrid容器中去,What’s more? 还有更多可以开放的脑洞。
这种拆解不是说可以做到把所有框架优点塞在一个大而全的框架里就完事的,各种优化方案的选择背后一定带来的是一些取舍。谁来决定取舍,业务决定,如果自己能深度把握这里面的设计思想,就不用在乎什么新的轮子新的框架,取其设计优点(优点一定带来取舍,如果选择这个有点意味着也要选择他的取舍),融入自己的业务之中。
一个标准的WebView容器要具备哪些基础的功能需求,来满足常规的 hybrid-webview 开发呢?
- 良好的 JS 与原生通信交互能力
- 灵活的业务模块扩展能力
- UserAgent 管理
- Cookies 管理
- 本地加载 JS 管理
通信交互设计
Android 调用 JS 有两种方式,都是通过
WebView
的方法:
webview.loadUrl() webview.evaluateJavascript()
二者区别:
-
loadUrl()
会刷新页面,evaluateJavascript()
则不会使页面刷新,所以evaluateJavascript()
的效率更高 -
loadUrl()
得不到 js 的返回值,evaluateJavascript()
可以获取返回值 -
evaluateJavascript()
在 Android 4.4 之后才可以使用在
methods
中定义一个供 Android 调用的方法callJsFunction(str)
, 并可接收一个参数str
,然后改变页面中的文字。如果只是在
methods
中定义方法,原生调用会找不到这个方法。所以要在页面加载的时候将方法挂载在window
上,这样WebView
就可以拿到此方法了。注意,这步很重要一定要写!loadUrl() 实现:tbsWebView.loadUrl("javascript:callJsFunction('soloname')");
evaluateJavascript() 实现:
tbsWebView.loadUrl("javascript:callJsFunction('soloname')");
- JS主动调用原生:
最基础功能,WebView 各种想要调用原生能力都通过这个设计来通知原生,无论是打开新页面新路由,还是弹个 Tips 框,还是执行 IAP 购买,还是打开摄像头等等。
对于JS调用Android代码的方法有3种:
-
通过
WebView
的addJavascriptInterface()
进行对象映射 -
通过
WebViewClient
的shouldOverrideUrlLoading()
方法回调拦截 url -
通过
WebChromeClient
的onJsAlert()
、onJsConfirm()
、onJsPrompt()
方法回调拦截JS对话框alert()
、confirm()
、prompt()
消息 -
新建类
JsJavaBridge
public class JsJavaBridge { private Activity activity; private WebView webView; public JsJavaBridge(Activity activity, WebView webView) { this.activity = activity; this.webView = webView; } @JavascriptInterface public void onFinishActivity() { activity.finish(); } @JavascriptInterface public void showToast(String msg) { ToastUtils.show(msg); } } 复制代码
然后通过
WebView
设置Android
类与 JS 代码的映射tbsWebView.addJavascriptInterface(new JsJavaBridge(this, tbsWebView), "$App"); 复制代码
这里将类
JsJavaBridge
在 JS 中映射为了$App
,所以在 Vue 中可以这样调用$App.showToast("哈哈,我是js调用的")
。
- JS主动调用原生后回调:
还是在基础功能之上,如果 WebView 是想要获取一些只有原生才有的数据,比如读原生数据库,查看原生设备网络/磁盘等硬件状况,需要在上面的功能下还额外回调给 WebView。
对JS消息体进行改造,增加用于处理回调相关的数据字段 callbackId 与 callbackFunction
- callbackId:对每一次消息需要发起回调都会生成一个唯一ID,用来当回调发生时,找到最初的发起调用的 JS Callback
- callbackFunction:客户端主动 Call JS 的唯一函数入口,客户端会用这个字符串来拼接回调注入的 JS 头,一般设计下,每个消息这个值都应该不变,不过也可以灵活处理(本来这个值可以不需要传递,写死在客户端,只要前端客户端约定好,但如果这个值不写死,而由前端可控操作,那么灵活性会更大,不必担心前端大规模修改 Call JS 唯一入口的时候,还得等客户端发版)
- Params:就是客户端要回调的数据体,可以为空
对 callbackId 与 callbackFunction 进行赋值,callbackId 是一个保证每次通信都唯一的一个id值 getNextCallbackID ,大概思路可以是用时间戳+一定程度的随机小数来进行生成,思路不深入展开了。 callbackFunction 这里我们先写 window.callbackDispatcher
后面会提到这个入口是怎么操作的。
这里有一步最最重要的操作就是, this.msgCallbackMap[callbackid] = callback;
会把 JS 业务的回调函数,保存在一个全局可处理的回调字典之中,而 Key 就是这个唯一ID callbackId,这样当 客户端发起回调的时候,你才能找到对应的 JS Function
我们会按着下面这种方式去拼接 JS 然后用 evaluateJavaScript:
来注入调用JS,在客户端拼接出一段 JS 代码,但如果 params 这个数据中存在一定特殊字符比如 \r \n \f
等等,这些特殊字符会破坏 JS 的代码结构,打破原本的 JS 语法,这块要非常小心,尤其是你要传递大型嵌套字典数据的时候,简单的测试数据这个问题是无法暴露出来的,如果 JS 代码结构被破坏,那么所有通信 JS 的方法就失效了。Native会把 callbackId callbackFuction ResultString 拼接成如下 JS 代码,注入回 WebView
window.callbackDispatcher('12345callbackid','{\'result\':\'result\'}');复制代码
那么前端要做的就是准备好对应的函数,在window的对象上,挂上 callbackDispatcher 这个函数,这就是为啥我一开始说 callbackFunction 写死 window.callbackDispatcher
的原因,客户端用这个字符串,拼出了 JS 代码,这个 JS 代码执行的时候,就刚好window下有这么一个函数接着
window.callbackDispatcher: function (callbackId, resultjson) { var handler = this.msgCallbackMap[callbackId]; if (handler && typeof (handler) === 'function') { console.log(resultjson); var resultObj = resultjson ? JSON.parse(resultjson) : {}; handler(resultObj); }}复制代码
当Native已经成功回调到 JS 了,那么就用 callbackId 在刚才保存的回调字典里找到要回调的方法,然后把传过来的 resultjson 用 JS 的 JSON.parse 反序列化成字典,然后用找到的回调方法把数据传递进去。@
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- React后台框架搭建
- Android组件化框架搭建
- Flask框架(一):介绍与环境搭建
- 搭建一个最简单的Demo框架
- 你的前端知识框架,该如何搭建?
- Spring Boot快速搭建Spring框架
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。