HarmonyOS 鸿蒙Next中web组件注入js,让前端调用并返回数据
HarmonyOS 鸿蒙Next中web组件注入js,让前端调用并返回数据 场景:web组件加载前端页面,并通过javaScriptProxy注入对象提供相应方法给前端调用。
前端使用的方法:
window.testObjName && window.testObjName({
name:"test",
onSuccess: function(res){
console.log('成功回调:' + JSON.stringify(res));
},
onFail: function(err){
console.log('失败回调:' + JSON.stringify(err));
},
})
应用侧官方提供的方法:
Web({
src: this.url,
controller: this.controller,
})
.javaScriptAccess(true)
.domStorageAccess(true)
.fileAccess(true)
.mixedMode(MixedMode.All)
.javaScriptProxy({
object: this.jsObject,
name: "testObjName",
methodList: ["test"],
controller: this.controller,
})
官方的方式,在前端中无法被调用,这种前端使用方式,应该怎么写?
更多关于HarmonyOS 鸿蒙Next中web组件注入js,让前端调用并返回数据的实战教程也可以访问 https://www.itying.com/category-93-b0.html
App端:通过注入一个 Proxy 对象来做方法调用
import { webview } from '@kit.ArkWeb';
class JSObject {
test(options: ESObject) {
options?.onSuccess({ msg: '成功调用了', name: options.name })
// 失败?
// options?.onFail({ msg: '失败了', name: options.name })
}
}
@Entry
@Component
struct Index {
controller = new webview.WebviewController()
jsObject: JSObject = new JSObject()
js = `;(function setupProxy() {
const originalObj = window.testObjName
function proxyTarget(...args) {}
Object.keys(originalObj).forEach(key => {
proxyTarget[key] = originalObj[key]
})
const proxyHandler = {
get: function (target, property) {
return target[property]
},
apply: function (target, thisArg, argumentsList) {
const options = argumentsList[0]
const methodName = options && options.name
if (methodName && typeof originalObj[methodName] === 'function') {
return originalObj[methodName].apply(originalObj, argumentsList)
}
return originalObj.test.apply(originalObj, argumentsList)
}
}
const proxy = new Proxy(proxyTarget, proxyHandler)
proxy.__isProxied = true
window.testObjName = proxy
return proxy
})`
scripts: Array<ScriptItem> = [
{ script: this.js, scriptRules: ["*"] }
];
build() {
RelativeContainer() {
Web({
src: $rawfile('index.html'),
controller: this.controller,
})
.runJavaScriptOnDocumentStart(this.scripts)
.javaScriptProxy({
object: this.jsObject,
name: "testObjName",
methodList: ["test"],
controller: this.controller,
})
}
.height('100%')
.width('100%')
}
}
H5端:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JS交互测试</title>
<script>
// 页面加载完成
//setupProxy(){...如果需要将setupProxy()放到 H5端...}
window.addEventListener('DOMContentLoaded', () => {
// setupProxy()
document.getElementById('testButton').addEventListener('click', () => {
window.testObjName({
name: 'test',
onSuccess: function(res) {
console.log('成功回调:', res)
document.getElementById('result').textContent = JSON.stringify(res)
},
onFail: function(err) {
console.log('失败回调:', err)
document.getElementById('result').textContent = JSON.stringify(err)
}
})
})
})
</script>
</head>
<body>
<h1>JS交互测试</h1>
<button id="testButton">点击测试</button>
<div id="result"></div>
</body>
</html>
测试结果:
 方法可放 App端,也可以放 H5端。上面代码是放到App端进行注册调用,这样你们H5的代码可以完全不用修改。
以前也写过一个库,使用 Proxy 来处理原生与H5交互问题。有兴趣的可以看下:
juejin.cn/post/7359084920595873830
更多关于HarmonyOS 鸿蒙Next中web组件注入js,让前端调用并返回数据的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
应用侧代码调整:
// 注入包含响应式方法的对象
class JsBridgeObject {
test(params: string, callback: (res: string) => void) {
try {
// 业务逻辑处理
const result = { data: "处理结果" };
callback(JSON.stringify(result));
} catch (error) {
callback(JSON.stringify({ error: error.message }));
}
}
}
// Web组件配置
Web({
src: $rawfile('index.html'),
controller: this.controller
})
.onControllerAttached(() => { // 确保在组件绑定阶段注入
this.controller.registerJavaScriptProxy(
new JsBridgeObject(),
"testObjName",
["test"]
);
})
前端调用修正:
// 正确调用姿势
if (window.testObjName && window.testObjName.test) {
window.testObjName.test(
JSON.stringify({ name: "test" }),
(response) => {
const res = JSON.parse(response);
if (res.error) {
console.error('操作失败:', res.error);
} else {
console.log('操作成功:', res.data);
}
}
);
}
不知是否可行,试一下吧
https://developer.huawei.com/consumer/cn/blog/topic/03171307462611086这种比较简单一些,官网还有一种方法,可以去官网看一下
在HarmonyOS Next中,Web组件通过WebViewController
的executeJs
方法注入JS代码并获取返回值。前端通过addJsProxy
注册回调方法,使用callNative
调用原生方法。示例代码:
// 前端注册回调
window.callbackName = (data) => {
console.log(data)
}
// 原生调用JS
webviewController.executeJs('window.callbackName("response data")')
// 前端调用原生
window.callNative('methodName', {param: 'value'}, (res) => {
console.log(res)
})
需在Web组件初始化时通过setJavaScriptProxy
启用JS桥接能力。
在HarmonyOS Next中,使用Web组件与前端交互的正确方式如下:
- 应用侧需要先定义一个JS代理对象:
class JsObject {
test(param: string): void {
console.log('收到前端调用:' + param);
// 处理逻辑后回调
const res = {result: 'success'};
param.onSuccess(res);
}
}
- Web组件配置应确保JS代理正确注入:
Web({
src: this.url,
controller: this.controller,
})
.javaScriptAccess(true)
.javaScriptProxy({
object: new JsObject(), // 使用上面定义的类实例
name: "testObjName",
methodList: ["test"], // 暴露的方法名
controller: this.controller,
})
- 前端调用方式需要调整为:
if (window.testObjName && window.testObjName.test) {
window.testObjName.test({
name: "test",
onSuccess: function(res) {
console.log('成功回调:', res);
},
onFail: function(err) {
console.log('失败回调:', err);
}
});
}
关键点:
- 确保methodList中声明的方法名与实际类方法名一致
- 前端调用时需要访问注入对象的具体方法(test),而不是直接调用对象
- 回调函数通过参数传递,由Native侧主动调用
这种方式能确保前端正确调用到注入的Native方法,并接收回调数据。