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

5 回复

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>

测试结果:

![Screenshot_20250703205656564.jpeg](data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAAAAAAAD/2wBDAAoHBwkHBgoJCAkLCwoMDxkQDw4ODx4WFxIZJCAmJSMgIyIoLTkwKCo2KyIjMkQyNzs…

setupProxy() 方法可放 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组件通过WebViewControllerexecuteJs方法注入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组件与前端交互的正确方式如下:

  1. 应用侧需要先定义一个JS代理对象:
class JsObject {
  test(param: string): void {
    console.log('收到前端调用:' + param);
    // 处理逻辑后回调
    const res = {result: 'success'};
    param.onSuccess(res);
  }
}
  1. Web组件配置应确保JS代理正确注入:
Web({
  src: this.url,
  controller: this.controller,
})
.javaScriptAccess(true)
.javaScriptProxy({
  object: new JsObject(),  // 使用上面定义的类实例
  name: "testObjName",
  methodList: ["test"],  // 暴露的方法名
  controller: this.controller,
})
  1. 前端调用方式需要调整为:
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方法,并接收回调数据。

回到顶部