美文网首页
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