若是你们以为有用,更多的模块请点击查看javascript
系列文章html
点击访问demo前端
扫码访问vue
为何到了今天,还要提hybrid开发,就我所在团队从中得到的好处有:java
JSBridge是前端和客户端交互的核心概念,下面就分享一下咱们的经验,由于目前android设备通常都是4.4以上系统,故咱们直接废弃了protocol
自定义协议的交互方式,直接使用上下文方式,这点须要客户端开发人员注意。android
下面介绍一下vue-viewplus 一个简化Vue应用开发的工具库中的JSBridge桥接模块js-bridge-context.js:ios
js-bridge-context.js JSBridge桥接模块,用于简化前端和客户端(Android && IOS)直接的交互,配合Jiiiiiin/android-viewplus 一个安卓混合客户端开发库可让hybrid开发易如反掌 :)git
这个模块须要和客户端配合使用,有如下一些约束和条件:程序员
上下文对象
、一个接口
,由于模块再调用客户端时候会约定一个数据传输对象,来知足客户端的内容分发,如: android那边多是这样的:mWebView.addJavascriptInterface(new Object(){
@JavascriptInterface
public String event(String params) {
final JSONObject jsonObj = JSONObject.parseObject(params);
String event = jsonObj.getString("event");
String action = jsonObj.getString("action");
String callback = jsonObj.getString("callback");
String listener = jsonObj.getString("listener");
JSONObject rparams = jsonObj.getJSONObject("params");
switch (action) {
case "toast":
ToastUtils.showLong(rparams.getString("msg"));
// 模拟异步执行其余事情
new Thread(() -> {
// 异步通知前端,即java调用前端js
HANDLER.post(() -> mWebView.evaluateJavascript(listener + "('" + params + "');", null));
}).start();
// 同步返回标识请求成功或失败
HANDLER.post(() -> mWebView.evaluateJavascript(callback + "('seccuess');", null));
break;
default:
}
return params;
}
}, "ViewPlus");
复制代码
上面简单来讲就是,安卓客户端向浏览器暴露了一个window.ViewPlus#event(command)
,这样一个接口,而后经过解析command
这个字符串类型的json对象,来判断前端但愿客户端作什么,作完以后怎么处理;github
那么当前模块就是为了简化和客户端的交互,让每一次请求,就行完成一个ajax
操做同样,如:
this.$vp.fireEvent({
event: 'UIEvent',
action: 'toast',
params: {
msg: 'hello world'
}
}).then(res => {
console.log('请求成功,客户端返回的同步请求结果', res)
}).catch(err => {
console.log('请求出错,客户端返回的同步错误信息', res)
})
复制代码
使用模块提供的$vp.fireEvent
方法,咱们只须要经过传递一条command指令就能够获得一个{Promise}
,这里和util-http.js
模块的请求方法同样; command的含义:
{
// [*] event用来标识请求那个客户端的模块,方便客户端根据业务组织“内部JSBridge接口”
event: 'UIEvent',
// action标识请求对应模块的那个方法或者说交易,客户端据此去调用该方法
action: 'toast',
// 【可选】params用来传递对应action须要的参数
params: {
msg: 'hello world'
}
// 【可选】listener用来告诉客户端执行完(通常而言是异步操做)方法只会须要回调该方法通知前端
listener: ([客户端传递]) => {}
}
复制代码
至于同步消息的处理,由于ios和android的处理不一样,插件已经帮你磨平了,客户端程序员须要注意的是command中针对ios必定会有一个callback
参数, 标识action方法处理完成须要“立刻”调用反馈给前端,当前请求是否处理完成,而android则没有这个参数,是由于public String event(String params)
这个暴露的接口的返回值,就完成了这个需求;
还须要客户端程序员注意的是: ios,模块调用的是global.webkit.messageHandlers[name].postMessage(JSON.stringify(command))
来调用,这里的name是当前模块的context.name
配置项; android,模块调用的是global[name].event(JSON.stringify(command))
,这里的event是写死的!!!
因此这里推荐一个安卓类库,专门为当前插件而订制,帮你们完成了这一系列工做:android-viewplus一个安卓混合客户端开发库
哈哈哈,强行安利一波;
模拟前端调用客户端toast
打印一个'hello vplus'
<template>
<div id="JsBridgeContext">
<group title="使用$vp#fireEvent请求客户端弹出一个toast:" label-width="15em" class="bottom-group">
<box gap="10px 10px">
<x-button mini plain @click.native="doFireEvent" class="fl-right">运行</x-button>
</box>
</group>
</div>
</template>
<script type="text/ecmascript-6"> import demoMixin from './demo-mixin' export default { mixins: [demoMixin], methods: { doFireEvent() { try { this.$vp.fireEvent({ event: 'UIEvent', action: 'toast', params: { msg: 'hello vplus' } }).then(res => { this.$vp.uiDialog(res, { title: '桥接调用成功', showCode: true }) }).catch(err => { this.$vp.uiDialog(`桥接调用失败 ${err.message}`) }) } catch (e) { this.$vp.uiDialog(`桥接调用失败 ${e.message}`) } } } } </script>
复制代码
除了上面这种直白的交互,咱们针对客户端数据传输安全和前端跨域问题,也依赖当前模块集成了一个经过客户端代理前端发送请求的util-http.js模块,后期若有须要将会分享;
/** * [*] `$vp#onParseClientResp(res)` * 当客户端返回结果以后会回调该钩子,应用能够经过该函数来判断客户端返回的消息是否正确,意思就和`util-http.js`模块同样,这里的是否正确, * 是业务级别的; * return true 标识业务级别成功,不然为失败,这里的判断直接影响`$vp#fireEvent`返回的Promise是调用失败仍是成功处理流程,若是不定义该配置项,那么`$vp#fireEvent`将会直接返回成功 */
onParseClientResp
复制代码
/** * 客户端暴露给前端的全局对象名称 * [*] {String} * <p> * 模块安装的时候回检测当前运行环境中是否存在这样一个名称的上下文对象 */
name = 'ViewPlus'
复制代码
/** * 标识是否启用当前模块 * [可选] {Boolean} * <p> * + 有一种状况,应用但愿手动设置`$vp.runNative`标识,以便程序能够方便知道本身的运行环境,可是又不想使用当前模块,这种状况,就能够单独把这里配置为false * 固然若是`$vp.runNative`已经被设置为false,那么还须要这个模块干吗呢? */
enable = runNative
复制代码
/** * $vp.onParseClientResp() * 方便应用调用该方法判断`command#listener`的返回结果,直接代理到`js-bridge-context`配置项`onParseClientResp` * @returns {Boolean} true 标识业务级别成功,不然为失败 */
onParseClientResp() {
if (_.isFunction(_onParseClientResp)) {
return this::_onParseClientResp()
} else {
emitErr(new Error('on_parse_client_resp_func_not_config'))
}
}
复制代码
/** * $vp.fireEvent(command = null) * 应用能够直接调用该方法完成和客户端的交互 * <p> * 协议方式请求客户端 * command的格式: * const command = { * // [*] event用来标识请求那个客户端的模块,方便客户端根据业务组织“内部JSBridge接口” * event: 'UIEvent', * // action标识请求对应模块的那个方法或者说交易,客户端据此去调用该方法 * action: 'toast', * // 【可选】params用来传递对应action须要的参数 * params: { * // 自定义参数 * msg: 'hello world' * } * // 【可选】listener用来告诉客户端执行完(通常而言是异步操做)方法只会须要回调该方法通知前端 * listener: ([客户端传递]) => {} * } * <p> * @param {Object} [command=null] 客户端所需的调用消息 */
fireEvent(command = null)
复制代码
若是你们以为有用,更多的模块请点击查看