美文网首页
Native与JS通信模型

Native与JS通信模型

作者: 大成小栈 | 来源:发表于2024-03-19 19:57 被阅读0次

在Android和iOS两端Native与JS通信一般会使用开源的Bridge:
https://github.com/marcuswestin/WebViewJavascriptBridge

该Bridge工作机制的大致描述:

协议与接口
  1. wvjbscheme://__BRIDGE_LOADED__:JS触发,通知Native加载WebViewJavascriptBridge.js
  2. wvjbscheme://__WVJB_QUEUE_MESSAGE__:JS触发,通知Native有调用消息(可以调用接口4获取了)
  3. wvjbscheme://return/_fetchQueue/:JS触发,向Native发送调用消息(附加在_fetchQueue/后面)
  4. WebViewJavascriptBridge._fetchQueue():Native调用,通知JS发送调用消息(JS执行协议3)
  5. WebViewJavascriptBridge._handleMessageFromNative('%s'):Native调用,向JS发送回应数据

实现:

  • Native拦截loadUrl和onJsPrompt, 收取协议消息;
  • JS通过动态创建并设置iframe的src属性,或者调用window.prompt发送协议消息。
  • WebViewJavascriptBridge.js暴露_fetchQueue()_handleMessageFromNative()接口供Native调用。
注册及回调
  1. WebViewJavascriptBridge.registerHandler():注册Native调用JS时对应处理程序的回调??,这个回调可以向Native发送消息
  2. WebViewJavascriptBridge.callHandler():调用处理程序,�以通过发送消息的方式触发Native执行操作
Native与JS通信模型在移动端的差异
Native与JS通信模型
  • iOS同步完成API注册,Android异步完成API注册,因此小程序调用同步API在Android上会导致UI冻结
  • iOS和Android在注册完API,都会另外调用JS,传回响应;iOS返回API数据,Android只返回成功状态
Native与JS通信模型在两个移动端的差异

小程序的运行时机制

启动机制

小程序的启动方式分为两种:

  • 首次加载小程序的冷启动;
  • 一定时间内重新打开小程序的热启动。

名词解释:

  • 冷启动: 通常是用户首次打开小程序,或者在客户端主动销毁了小程序之后,用户又重新打开了小程序,在这两种情况下,小程序都会初始化启动;
  • 热启动: 用户已经访问过该小程序,短暂退出后,又重新回到小程序。这时客户端不会销毁该小程序,而只是控制小程序的显隐。

销毁机制

客户端主动触发小程序销毁的场景:

  • 当用户退出小程序超过 5 分钟后;
  • 打开小程序数量超过系统支持上限 6 个(系统按照小程序被打开的先后顺序进行销毁)。

更新机制

基础包下载/更新

流程

  • 在 APP 启动后合适时机(打开小程序之前),加载框架的 json 文件
  • 对比 json 文件返回的版本号与本地缓存的版本号
  • 如果版本号不一致,则根据 url 字段下载小程序框架包(zip)
  • 框架包下载完成后,校验 md5 是否与 json 文件中 md5 字段值一致
  • 解压 zip 包,将里面的 html 文件缓存起来(连同版本号一起缓存)

json 文件

url 为: https://im.qihoo.net:8282/fed/miniapp/miniapp.jsonhost 后续会变动,当前为临时地址。数据格式为:

{
    version: "0.1.2",
    fid: "5efc6851ee9eac3fbb45c508",
    md5: "884530f116d0011066215a052f19911e",
    url: "https://im.qihoo.net:8282/fed/miniapp/0.1.2.zip"
}

发布新的版本

将公共库zip包上传到织语测试服,方法为:在Web版聊天界面上传公共库包,抓upload接口返回结果,里面有fid:https://im.qihoo.net:8282/fed/web-module

上传后更新上述JSON的全部字段,然后将JSON文件覆盖发布到测试服。

小程序包下载/更新

流程

  • 首次打开小程序时(本地无缓存),小程序包基于fid由Native直接下载。fid作为版本控制机制,更新zip包,fid随之更新,appId不变。
  • 本地缓存有缓存时,直接使用本地版本启动小程序。后台异步去下载,更新后的小程序下次打开才会生效。

问题:小程序包可能缺少 app zip 的MD5验证机制。

流程图

[图片上传失败...(image-319638-1710936634081)]

https://www.processon.com/view/link/5f277a885653bb7fd262919c

执行/渲染机制

业界模式

微信/百度等小程序的做法一般是将 JS 放在一个独立的逻辑层来处理(iOS 用 JavaScriptCore,安卓用 V8),在逻辑层执行时就没有 BOM 环境了,也就是 JS 里不能再包含 window/document 之类的代码了。UI 层是通过 webview 来进行的,一个页面用一个独立的 webview 渲染。

逻辑层和 UI 层的数据交互是通过 setData 和事件来传递的,类似:

[图片上传失败...(image-10a1b1-1710936634082)]

逻辑执行 JS 后最终都会变成数据的变更,然后通过 setData 将数据传递到 UI 层来渲染,UI 层将用户响应的事件传递到逻辑层,从而达到二边交互的逻辑。

临时方案

由于 PC 小程序是基于 Vue 框架来弄的,所以如果用微信/百度小程序的方案,就需要改造 Vue 框架的 runtime/compiler 等部分,改造成本比较高,并且这种会影响 Vue 的组件(如果组件里用了一些 DOM 的操作就会有问题)

所以临时方案为还是用多个 webview 的机制,JS 的执行也是放在 webview 里执行的,这样就可以完全使用 Vue 的功能了。但这个模式会带来另外一个问题,就是多个 webview 之间的数据同步(因为 App 是单例的,小程序生命周期内只会执行一次)。

为了处理多个 webview 数据同步的问题,引用一个隐藏的 webview 来执行 app.js,页面用单独的 webview 来执行

  • 小程序初次打开时,Native 打开一个隐藏的 webview 加载 app.html,同时打开一个 webview 来渲染 page.html;
  • 后续 tabBar/页面 点击打开新页面时直接用 webview 打开 page.html;
  • Native 需要管理页面的 webview(就是打开 page.html 的 webview)。

多个 webview 页面的数据同步通过 Native 提供的 getSessionStorageSync/setSessionStorageSync 来执行,并且限定全局数据放在 app.globalData 上,app.globalData 通过 defineProperty 来实现

getSessionStorageSync/setSessionStorageSync 方法是在当前小程序的生命周期内生效的,也就是当小程序销毁时,这个接口下面的数据也跟随销毁。

冷启动过程

  1. 根据小程序 id,去下载或者从本地缓存中读取小程序代码(app.jsonapp.jspage.jsapp.css),并复制基础库(app.htmlpage.html)到小程序目录。
  2. 打开隐藏的 Webview,加载 app.html。在小程序运行期间,保持该 Webview 一直处于打开状态。
  3. 打开一个新的 Webview ,并加载 page.html。如果有指定的页面 path,需要在页面 URL 后面添加 #页面路径,比如 #/pages/home/index

页面跳转

在页面中可以使用 navigateTonavigateBackredirectTo 方法跳转到指定页面。

  • navigateTo:新打开一个 Webview,并加载 page.html#页面路径。如果此时该小程序已经打开了 10 个 Webview,则不再新打开 Webview,而是直接将当前页面替换为 page.html#页面路径
  • navigateBack: 销毁当前 Webview,并展示之前的 Webview。
  • redirectTo:当前 Webview 的页面替换为 page.html#页面路径

页面关闭

如果用户点击右上角的关闭按钮,小程序应该切换到后台,打开的 Webview 依旧保留。

切换到后台的小程序,只会保留 5 分钟。超过 5 分钟后,小程序将会退出。

小程序退出

如果用户主动杀掉进程,或者进行被系统杀掉,都将退出。小程序退出时,所有 Webview 都会销毁。

生命周期方法

客户端可以通过 webview.loadUrl("javascript:onShow()") 调用 Webview 中的函数。

小程序级别的生命周期方法

  • onLoad:app.html 在打开后会自动调用,不需要客户端调用。
  • onShow:已经在后台运行的小程序,被切换到前台后,需要客户端调用 app.html 中的 onShow 函数。
  • onHide:正在运行中的小程序被切换到后台时需要客户端调用 app.html 中的 onHide 函数。
  • onUnload:小程序被销毁时(比如切换到后台超过5分钟),需要调用 app.html 中的 onUnload 函数。

页面级别的生命周期方法

  • onLoad:page.html 在打开后会自动调用,不需要客户端调用。
  • onHide:当前正在展示的页面,被隐藏起来的时候,需要调用 page.htmlonHide 函数。比如小程序被切换到后台,或者打开了新的 Webview。
  • onShow:之前被隐藏的页面,被切换到前台后,需要客户端调用 page.html 中的 onShow 函数。
  • onUnload:页面被销毁时,需要调用该页面的 onUnload 方法。

相关文章

网友评论

      本文标题:Native与JS通信模型

      本文链接:https://www.haomeiwen.com/subject/wppttjtx.html