关于 JsBridge 的通信原理,现在主流的技术方案有 拦截 URL 和 对象注入 两种,我们分别看一下如何在鸿蒙上实现。
拦截 URL
在安卓上,拦截 URL 这个技术方案的代表作一定是 GitHub - lzyzsd/JsBridge: android java and javascript bridge, inspired by wechat webview jsbridge ,相信有不少小伙伴都使用了这个开源库。
我这里就以该开源库为例,介绍一下如何在鸿蒙上无缝迁移。
首先,在页面加载完成后注入通信需要的 JS 代码。在 Android 中,是 WebViewClient.onPageFinished(),在鸿蒙中对应 Web组件的 onPageEnd()方法。
Web({ src: this.url, controller: this.controller }) .onPageEnd(() => { this.onPageEnd() BridgeUtil.webViewLoadLocalJs(getContext(), this.controller, BridgeUtil.toLoadJs) })
鸿蒙中本地资源文件放在 resouce/rawfile 目录下,通过以下代码读取:
rawFile2Str(context: Context, file: string): string { try { let data = context.resourceManager.getRawFileContentSync(file) let decoder = util.TextDecoder.create("utf-8") let str = decoder.decodeWithStream(data, { stream: false }) return str } catch (e) { return "" } }
读取到的 JS 代码,通过系统能力动态执行。在 Android 中,通过 WebView.loadUrl() 或者 WebView.evaluateJavaScript() 来实现。在鸿蒙中,对应的是 WebviewController.runJavaScriptExt() 。
webViewLoadLocalJs(context: Context, controller: WebviewController, path: string) { let jsContent = BridgeUtil.rawFile2Str(context, path) controller.runJavaScriptExt(BridgeUtil.JAVASCRIPT_STR + jsContent, (err, result) => { ... }) }
JS 代码注入完成后,就是核心的拦截 URL 了。在 Android 中,通过 WebViewClient.shouldOverrideUrlLoading() 实现,看一下具体的代码:
@Override public boolean shouldOverrideUrlLoading(WebView view, String url) { try { url = URLDecoder.decode(url, "UTF-8"); } catch (UnsupportedEncodingException e) { e.printStackTrace(); }
if (url.startsWith(BridgeUtil.YY_RETURN_DATA)) { webView.handlerReturnData(url); return true; } else if (url.startsWith(BridgeUtil.YY_OVERRIDE_SCHEMA)) { // webView.flushMessageQueue(); return true; } else { return super.shouldOverrideUrlLoading(view, url); } }
拦截到所有的 URL,判断是否是 H5 通过 iFrame.src 发送的指定特征的 URL,来完成通信流程。
在鸿蒙中,对应的是 Web 组件的 onInterceptRequest()方法。
Web({ src: this.url, controller: this.controller }) .onInterceptRequest((event) => { if (event) { let url = event.request.getRequestUrl() if (url.startsWith(BridgeUtil.YY_RETURN_DATA)) { this.ytoJsBridge.handlerReturnData(url) } else if (url.startsWith(BridgeUtil.YY_OVERRIDE_SCHEMA)) { this.ytoJsBridge.flushMessageQueue() } else { return null } } return null })
核心逻辑就这样,剩下的工作量就是苦逼的翻译代码。好在代码量并不大,大概五六个文件。
移植过程中,也踩了一些坑,印象最深的是 ArkTs 中关于接口的写法。
export interface CallBackFunction { onCallBack(data: string): void }
这是在 Java/Kotlin 中很常见的一种写法,顺手在 ArkTs 也这么写,但是在使用过程中尝试去写实现的时候就犯了难。如果直接按照传统的前端写法:
let responseFunction: CallBackFunction if (callBackId != undefined) { responseFunction = { onCallBack: (data: string): void => { ... } } }
你会得到一个 lint 错误 Object literal must correspond to some explicitly declared class or interface (arkts-no-untyped-obj-literals) 。
你可以使用箭头函数来解决这个问题。
export interface CallBackFunction { onCallBack: (data: string) => void // onCallBack(data: string): void }
这也是 ArkTs 目前比较割裂的地方,基于 TS,但是禁用了很多特性。
设想一下如果可以继续兼容 Java/Kotlin,那么这篇文章都不会存在了,压根不存在迁移成本,海量移动端类库无缝衔接......
对象注入
对象注入在 Android WebView 中的实现是 WebView.addJavascriptInterface(Object object, String name) 方法 。
addJavascriptInterface(JsBridge(this@MainActivity, webView), "JsBridge")
class JsBridge(private val activity: Activity, private val webView: WebView) {
@JavascriptInterface
fun webCallNative(message: String) {
Log.e("JsBridge", "webCallNative: ${Thread.currentThread().name}")
Toast.makeText(activity, message, Toast.LENGTH_SHORT).show()
}
}
在鸿蒙中,可以通过 Web 组件的 javaScriptProxy() 方法,或者 WebviewController.registerJavaScriptProxy() 方法。
Web({ src: this.url, controller: this.controller }) .javaScriptAccess(true) .javaScriptProxy({ object: this.testObj, name: "objName", methodList: ["test", "toString"], controller: this.controller, })
这种方式只支持注入一个对象,如果需要注入多个对象,要用 WebviewController.registerJavaScriptProxy()。
this.controller.registerJavaScriptProxy(this.testObjtest, "objName", ["test", "toString", "testNumber", "testBool"]); this.controller.registerJavaScriptProxy(this.webTestObj, "objTestName", ["webTest", "webString"]);
这个方法的调用时机需要注意,必须发生在 controller 和 Web 组件绑定之后,建议放在 Web.onPageEnd()。注册之后需要调用 WebviewController.refresh() 才会生效。
最后
有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(HarmonyOS NEXT)资料用来跟着学习是非常有必要的。
这份鸿蒙(HarmonyOS NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了(**ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony****多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(HarmonyOS NEXT)**技术知识点。
希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!
如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员,可以直接领取这份资料
获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料****
鸿蒙(HarmonyOS NEXT)最新学习路线
- HarmonOS基础技能
- HarmonOS就业必备技能
- HarmonOS多媒体技术
- 鸿蒙NaPi组件进阶
- HarmonOS高级技能
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!