ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

JS如何调用客户端方法 JS Bridge Hybrid

2021-10-28 15:04:36  阅读:346  来源: 互联网

标签:Bridge 请求 setLeftButton Hybrid JS window webview 客户端 native


JsBridge原理

Hybrid最核心的就是Navite和H5的双向通讯, 而通讯是完全依赖于native提供的webview容器,那native提供的这个webview容器有什么特点能支撑起h5和native的通讯呢?具体的通讯流程到底是什么样子呢?

首先说明有两种方式:

  • URL Schema, 客户端通过拦截webview请求来完成通讯
  • native向webview中的js执行环境, 注入API, 以此来完成通讯

一、URL Schema, 客户端拦截webview请求

  1. 原理

在webview中发出的网络请求,都会被客户端监听和捕获到。

这是我们本节课所有实现的基石。

  1. 定义自己的私有协议

上面说过, 所有网络请求都会被监听到, 网络请求最常见的就是http协议, 比如https://a.b.com/fetchInfo, 这是一个很常见的请求。

webview内的H5页面肯定有很多类似的http请求, 我们为了区别于业务请求, 需要定制一套h5和native进行交互的私有协议, 我们通常称呼为URL Schema。

比如我们现在定义协议头为 schema://xxx.xxx,

那么随后我们要在webview请求中都带上这个私有协议开头, 比如有一个请求是setLeftButton, 实际发出的请求会是schema://setLeftButton?params1=xxx&params2=xxx.

这里大家记住, 这个协议的名称是我们自定义的, 只要h5和native协商好即可。
但是如果公司旗下有多个app, 对于通用的业务一般会定义一个通用的协议头, 比如common://;对于每个app自己比较独立的业务, 基本每个app都会自己定义一套协议, 比如appa://, appb://, appc://.

  1. 请求的发送

对于webview请求的发送, 我们一般使用iframe的方式。也可以使用location.href的方式, 但是这种方式不适用并行发请求的场景。

const doc = window.document;
const body = window.document.body;
const iframe = doc.createElement('iframe');

iframe.style.display = 'none';
iframe.src = 'schema://setLeftButton?param1=12313123';

body.appendChild(iframe);
setTimeout(() => {
    body.removeChild(iframe);
}, 200)

而且考虑到安全性, 客户端中一般会设置域名白名单, 比如客户端设置了schema.com为白名单, 那么只有schema.com域下发出的请求, 才会被客户端处理。

这样可以避免自己app内部的业务逻辑, 被第三方页面直接调用。

  1. 客户端拦截协议请求

iOS和Android对webview请求的拦截方法不太相同。

  • iOS: shouldStartLoadWithRequest
  • Android: shouldOverrideUrlLoading

当客户端解析到请求的URL协议是约定要的schema://时, 便会解析参数, 并根据h5传入的方法名比如setLeftButton, 来进行相关操作(设置返回按钮的处理逻辑)。

  1. 请求处理完成后的回调

因为咱们webview的请求本质上还是异步请求的过程, 当请求完成后, 我们需要有一个callback触发, 无论是通知h5执行结果,还是返回一些数据, 都离不开callback的执行。

我们可以使用Js自带的事件机制,window.addEventListener和window.dispatchEvent这两个API。

还是这个例子, 比如咱们现在要调用setLeftButton方法, 方法要传入一个callback来得知是否执行成功了。

webview.setLeftButton({ params1: 111 }, (err) => {
    if (err) {
        console.error('执行失败');
        return;
    }
    console.log('执行成功');
    // 业务逻辑
})

JsBridge中具体的步骤应该是这样的:

  • 在H5调用setLeftButton方法时, 通过 webview_api名称+参数 作为唯一标识,注册自定义事件
const handlerId = Symbol();
const eventName = `setLeftButton_${handlerId}`;
const event = new Event(eventName);
window.addEventListener(eventName, (res) => {
    if (res.data.errcode) {
        console.error('执行失败');
        return;
    }
    console.log('执行成功');
    // 业务逻辑
});

JsBridge.send(`schema://setLeftButton?handlerId=${eventName}&params1=111`);
  • 客户端在接收到请求, 完成自己的对应处理后, 需要调用JsBridge中的dispatch, 携带回调的数据触发自定义事件。
event.data = { errcode: 0 };
window.dispatchEvent(event);

注入API

上述方式有个比较大的缺点, 就是参数如果太长会被截断。以前用这种方式主要是为了兼容iOS6, 现在几乎已经不需要考虑这么低的版本了。

所以现在主流的实现是native向js的执行环境中注入API.

具体怎么操作呢, 咱们分步骤来看:

  1. 向native传递信息

由于native已经向window变量注入了各种api, 所以咱们可以直接调用他们。

比如现在window.schemaWebview = { setLeftButton: (params) => {}} 就是native注入的对象api。

我们可以直接这样调用, 就可以传参数给native了

window.schemaWebview['setLeftButton'](params)

但是为了安全性, 或者为了不要乱码等问题, 我们一般会对参数进行编码, 比如转换为base64格式。

  1. 准备接收native的回调

咱们同样可以在window上声明接收回调的api

window['setLeftButton_Callback_1'] = (errcode, response) => {
    console.log(errcode);
}

同样为了安全性和参数传递的准确性, native也会将回调的数据进行base64编码, 咱们需要在回调函数里进行解析。

  1. native调用回调函数

native怎么知道哪个是这次的回调函数呢? 他们确实不知道, 所以我们需要在调用的时候就告诉native。

window.schemaWebview['setLeftButton'](params)

这个Params中, 我们会加入一个属性叫做trigger, 它的值是回调函数的名称, 比如

const callbackName = 'setLeftButton_Callback_1';
window.schemaWebview['setLeftButton']({
    trigger: callbackName,
    ...otherParams
});

window[callbackName] = (errcode, response) => {
    console.log(errcode);
}

同时为了保证callbackName的唯一性, 我们一般会加入各种Date.now() + id, 使其保证唯一。

标签:Bridge,请求,setLeftButton,Hybrid,JS,window,webview,客户端,native
来源: https://blog.csdn.net/KID963931445/article/details/121014401

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有