【关键字】
自定义弹框类 / JS / 前端 / 拉起 / 交互
【问题描述】
写了一个自定义弹框类,如下图所示。
写了一个和前端数据交互的类,如下图所示。
怎么在这个交互类让自定义弹框弹出?根本问题是前端在合适的场景拉起原生写的自定义弹框,例如版本更新提示弹框 (自定义样式的)。
【解决方案】
目前javaScriptProxy仅支持同步调用,异步调用无法获取执行结果。
问题可以这样解决。
对javaScriptProxy和runJavaScript封装,实现JSBridge通信方案。适用于H5调用原生侧函数。使用Web组件javaScriptProxy将原生侧接口注入到H5的window对象上,通过runJavaScript接口执行JS脚本到H5中,并在回调中获取脚本执行结果。
首先通过Web组件的javaScriptProxy属性,将JSBridgeHandle对象注册到H5的window上,作为H5调用原生的通道。当H5开始加载时,在onPageBegin生命周期中调用initJSBridge()方法初始化JSBridge。
// javaScriptProxy对象
public get javaScriptProxy() {
return {
object: {
call: this.call
},
name: "JSBridgeHandle",
methodList: ['call'],
controller: this.controller,
}
}
// 使用Web组件加载H5页面
@Component
struct JsProxy {
private controller: WebviewController = new WebView.WebviewController()
private jsBridge: JSBridge = new JSBridge(this.controller)
build() {
Column(){
Web({ src: $rawfile('index.html'), controller: this.controller })
.javaScriptProxy(this.jsBridge.javaScriptProxy)
.onPageBegin(() => {
this.jsBridge.initJSBridge()
})
}
}
}
在initJSBridge方法中,通过webviewControll.runJavaScript()将JSBridge初始化脚本注入H5执行。当H5调用时,生成window.callID标识回调函数,将callID与调用参数使用JSBridgeHandle.call传到原生侧。通过JSBridgeCallback接收原生侧执行的结果,根据callID找到对应callback执行并且释放内存。
// bridgeKey与bridgeMethod动态生成H5侧调用的入口
bridgeKey: string = 'JSBridge'
bridgeMethod: string = 'call'
// 初始化脚本注入H5侧
public initJSBridge() {
try {
this.controller.runJavaScript(`
// 接收原生侧结果,执行callback
function JSBridgeCallback(id, params){
window.JSBridgeMap[id](params)
};
// 声明调用入口
window.${this.bridgeKey} = {
${this.bridgeMethod}(method, params, callback){
window.JSBridgeMap[id] = callback || (() => {});
JSBridgeHandle.call(method, JSON.stringify(paramsObj));
},
}`)
}
}
JSBridgeHandle.call()是H5调用原生接口的统一入口,在该方法中根据H5调用的方法名,匹配到对应接口去调用。调用结束后通过this.callback()方法将调用结果返回H5。callback方法中使用webviewControll.runJavaScript()调用H5的JSBridgeCallback回传callID和调用结果。
// call方法调用原生侧方法,接收结果
private call = (fun, params) => {
try {
const paramsObj = JSON.parse(params)
const events = this.exposeManage.methodMap.get(fun)
const results = []
events.forEach(callFun => {
results.push(callFun(paramsObj.data))
})
Promise.all(results.filter(i => !!i)).then(res => {
this.callback(paramsObj.callID, res.length > 1 ? res : res[0])
})
}
}
// 通过runJavaScript调用JSBridgeCallback执行回调
private callback(id, data) {
this.controller.runJavaScript(`__JSBridgeCallback__("${id}", ${JSON.stringify(data)})`);
}