HarmonyOS 鸿蒙Next ArkWeb网页组件如何与JS交互?Web组件开发指南

HarmonyOS 鸿蒙Next ArkWeb网页组件如何与JS交互?Web组件开发指南

  • HarmonyOS 5.0,DevEco Studio 5.0
  • 需要在应用中嵌入网页,并实现原生与JS的双向通信
  • 不清楚如何调用网页中的JS方法
  • 希望网页能调用原生的功能

希望了解HarmonyOS ArkWeb组件的使用方法,包括网页加载、JS注入和双向通信

3 回复

1. 基础Web组件使用

import { webview } from '@kit.ArkWeb'

@Entry
@Component
struct WebPage {
  @State url: string = 'https://example.com'
  @State progress: number = 0
  @State isLoading: boolean = true

  controller: webview.WebviewController = new webview.WebviewController()

  build() {
    Column() {
      // 加载进度条
      if (this.isLoading) {
        Progress({ value: this.progress, total: 100 })
          .width('100%')
          .height(2)
          .color('#36e27b')
      }

      // Web组件
      Web({ src: this.url, controller: this.controller })
        .width('100%')
        .layoutWeight(1)
        .onProgressChange((event) => {
          if (event) {
            this.progress = event.newProgress
            this.isLoading = event.newProgress < 100
          }
        })
        .onPageBegin(() => {
          this.isLoading = true
        })
        .onPageEnd(() => {
          this.isLoading = false
        })
        .onErrorReceive((event) => {
          console.error('网页加载错误:', event?.error?.getErrorInfo())
        })
    }
  }
}

2. 原生调用JS方法

@Entry
@Component
struct WebJSPage {
  controller: webview.WebviewController = new webview.WebviewController()

  // 调用网页中的JS方法
  callJSFunction(): void {
    // 执行JS代码
    this.controller.runJavaScript('showAlert("来自原生的消息")')

    // 带返回值的调用
    this.controller.runJavaScript('getData()')
      .then((result) => {
        console.info('JS返回值:', result)
      })
      .catch((err: Error) => {
        console.error('JS执行失败:', err)
      })
  }

  // 调用带参数的JS方法
  callJSWithParams(name: string, age: number): void {
    const script = `updateUserInfo("${name}", ${age})`
    this.controller.runJavaScript(script)
  }

  build() {
    Column() {
      Row({ space: 12 }) {
        Button('调用JS')
          .onClick(() => this.callJSFunction())

        Button('传递参数')
          .onClick(() => this.callJSWithParams('张三', 25))
      }
      .padding(12)

      Web({ src: $rawfile('test.html'), controller: this.controller })
        .layoutWeight(1)
    }
  }
}

3. JS调用原生方法

import { webview } from '@kit.ArkWeb'

@Entry
@Component
struct WebNativePage {
  @State message: string = ''
  controller: webview.WebviewController = new webview.WebviewController()

  aboutToAppear(): void {
    // 注册JS可调用的原生方法
    webview.WebviewController.setWebDebuggingAccess(true)
  }

  build() {
    Column() {
      // 显示来自JS的消息
      if (this.message) {
        Text(this.message)
          .padding(12)
          .backgroundColor('#36e27b20')
          .borderRadius(8)
          .margin(12)
      }

      Web({ src: $rawfile('callback.html'), controller: this.controller })
        .layoutWeight(1)
        .javaScriptAccess(true)
        .javaScriptProxy({
          object: {
            // 定义JS可调用的方法
            showToast: (msg: string) => {
              this.message = msg
              console.info('JS调用了showToast:', msg)
            },
            getUserInfo: () => {
              return JSON.stringify({
                name: '养鱼达人',
                level: 5
              })
            },
            openNativePage: (pageName: string) => {
              console.info('打开原生页面:', pageName)
              // router.pushUrl({ url: `pages/${pageName}` })
            }
          },
          name: 'NativeBridge',  // JS中通过此名称调用
          methodList: ['showToast', 'getUserInfo', 'openNativePage'],
          controller: this.controller
        })
    }
  }
}

4. HTML文件示例

<!-- resources/rawfile/callback.html -->
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>JS交互测试</title>
  <style>
    body { padding: 20px; font-family: sans-serif; }
    button { padding: 10px 20px; margin: 5px; }
  </style>
</head>
<body>
  <h2>JS与原生交互测试</h2>

  <button onclick="callNativeToast()">调用原生Toast</button>
  <button onclick="getNativeUserInfo()">获取用户信息</button>
  <button onclick="openPage()">打开原生页面</button>

  <div id="result"></div>

  <script>
    // 调用原生方法显示Toast
    function callNativeToast() {
      NativeBridge.showToast('Hello from JavaScript!');
    }

    // 获取原生返回的数据
    function getNativeUserInfo() {
      const userInfo = NativeBridge.getUserInfo();
      document.getElementById('result').innerText = '用户信息: ' + userInfo;
    }

    // 打开原生页面
    function openPage() {
      NativeBridge.openNativePage('FishDetail');
    }

    // 供原生调用的方法
    function showAlert(msg) {
      alert(msg);
    }

    function getData() {
      return JSON.stringify({ status: 'ok', data: [1, 2, 3] });
    }

    function updateUserInfo(name, age) {
      document.getElementById('result').innerText = `姓名: ${name}, 年龄: ${age}`;
    }
  </script>
</body>
</html>

5. Web组件常用配置

Web({ src: this.url, controller: this.controller })
  .javaScriptAccess(true)           // 允许执行JS
  .domStorageAccess(true)           // 允许DOM存储
  .fileAccess(true)                 // 允许文件访问
  .imageAccess(true)                // 允许加载图片
  .mixedMode(MixedMode.All)         // 允许混合内容
  .cacheMode(CacheMode.Default)     // 缓存模式
  .userAgent('CustomUA/1.0')        // 自定义UA
  .zoomAccess(false)                // 禁止缩放
  .verticalScrollBarAccess(false)   // 隐藏滚动条

6. 常用控制方法

// 刷新页面
this.controller.refresh()

// 后退
if (this.controller.accessBackward()) {
  this.controller.backward()
}

// 前进
if (this.controller.accessForward()) {
  this.controller.forward()
}

// 停止加载
this.controller.stop()

// 清除缓存
this.controller.removeCache(true)

// 获取当前URL
const currentUrl = this.controller.getUrl()

// 获取标题
const title = this.controller.getTitle()

关键点: javaScriptProxy中的methodList必须包含所有要暴露给JS的方法名

更多关于HarmonyOS 鸿蒙Next ArkWeb网页组件如何与JS交互?Web组件开发指南的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


ArkWeb通过WebMessagePort实现双向通信

在ArkTS侧使用createWebMessagePort()创建端口,通过postWebMessage()发送消息给JS。

JS侧通过message事件监听接收消息,使用postMessage()回传数据。

支持基本数据类型和对象传输。

在HarmonyOS Next中,ArkWeb组件通过@ohos.web.webview提供网页与ArkTS原生应用的双向交互能力。以下是核心实现方法:

1. 网页加载

使用WebController加载网页:

import { webview } from '@ohos.web.webview';

@Entry
@Component
struct WebComponent {
  controller: webview.WebviewController = new webview.WebviewController();

  build() {
    Column() {
      // 加载远程或本地网页
      Web({ src: 'https://example.com', controller: this.controller })
        .onPageEnd(() => {
          console.info('页面加载完成');
        })
    }
  }
}

2. 原生调用JS方法

通过runJavaScript执行JS代码并获取返回值:

// 调用无返回值方法
this.controller.runJavaScript('window.jsMethod()');

// 调用有返回值方法
this.controller.runJavaScript('window.getData()', (error, result) => {
  if (!error) {
    console.info('JS返回值:', result);
  }
});

3. JS调用原生方法

步骤1:注册JS桥接对象

// 定义原生对象
class NativeBridge {
  static showToast(message: string) {
    // 调用原生UI能力
    prompt.showToast({ message });
  }
}

// 注册到Web
this.controller.registerJavaScriptProxy(
  new NativeBridge(), // 桥接对象
  'nativeBridge',     // JS中对象名
  ['showToast']       // 暴露的方法列表
);

步骤2:JS中调用原生方法

// 网页JS代码
if (window.nativeBridge) {
  window.nativeBridge.showToast('来自网页的消息');
}

4. 双向通信完整示例

// ArkTS侧
@Entry
@Component
struct WebDemo {
  controller: webview.WebviewController = new webview.WebviewController();
  
  aboutToAppear() {
    // 注册JS可调用的方法
    this.controller.registerJavaScriptProxy(
      {
        sendToNative: (data: string) => {
          console.info('收到JS数据:', data);
          return 'ArkTS已收到';
        }
      },
      'arkBridge',
      ['sendToNative']
    );
  }
  
  callJS() {
    // 调用JS方法
    this.controller.runJavaScript(`
      if (window.receiveFromNative) {
        window.receiveFromNative('原生数据');
      }
    `);
  }

  build() {
    Column() {
      Button('调用JS').onClick(() => this.callJS())
      Web({ 
        src: $rawfile('index.html'), 
        controller: this.controller 
      })
    }
  }
}
<!-- 网页侧 index.html -->
<script>
// 接收原生调用
window.receiveFromNative = function(data) {
  console.log('收到原生数据:', data);
  document.getElementById('msg').innerText = data;
};

// 调用原生方法
function callNative() {
  if (window.arkBridge) {
    const result = window.arkBridge.sendToNative('来自网页的数据');
    console.log('原生返回:', result);
  }
}
</script>

关键注意事项:

  • 使用registerJavaScriptProxy注册的方法必须是同步的
  • runJavaScript回调在主线程执行,避免耗时操作
  • 本地网页资源放在resources/rawfile目录
  • 通过onConsole可捕获网页console日志

这种设计实现了ArkTS与JavaScript的完全双向通信,支持复杂数据类型的传递。

回到顶部