HarmonyOS NEXT和通用JSBridge

JSBridge实现原生native和网页的双向通信。作为原生和网页沟通的桥梁,JSBridge是通用兼容的,不会单独为一个平台开发一套逻辑。这里记录一下HarmonyOS NEXT中的通用JSBridge的实现。

原生实现

page.etc

javascript 复制代码
import web_webview from '@ohos.web.webview'
import router from '@ohos.router'
import { JSBridgeBean } from '../data/JSBridgeBean';
import { deviceInfo } from '@kit.MDMKit';

@Entry
@Component
struct WebViewPage {
  //网页标题
  @State mTitle: string = (router.getParams() as Record<string, string>)['mTitle'];
  //网页地址
  @State mUrl: string = (router.getParams() as Record<string, string>)['mUrl'];
  controller: web_webview.WebviewController = new web_webview.WebviewController()

  build() {
    Column() {
      Web({ src: this.mUrl, controller: this.controller })
        .width('100%')
        .height('100%')
        .onPageEnd(() => {
          this.registerUnifiedJSBridge();
        })
    }.height('100%')
    .width('100%')
  }

  registerUnifiedJSBridge() {
    // 定义统一的 Bridge 对象
    const JSBridge = {
      // 网页调用此方法发起请求
      invoke: (command: string, paramsJson: string, callbackId: string): void => {
        console.log(`[JSBridge] Received command: ${command}, params: ${paramsJson}, cb: ${callbackId}`);
        //TODO 埋点
        try {
          const params :JSBridgeBean = JSON.parse(paramsJson || '{}');

          // 根据 command 分发处理
          switch (command) {
            case 'getDeviceInfo':
              this.handleGetDeviceInfo(callbackId);
              break;

            case 'showToast':
              this.handleShowToast(params.content, callbackId);
              break;

            case 'pickImage':
              this.handlePickImage(callbackId);
              break;

            default:
              this.sendCallback(callbackId, { success: false, error: 'Unknown command' });
          }
        } catch (e) {
          console.error('[JSBridge] Parse params failed:', e);
          this.sendCallback(callbackId, { success: false, error: 'Invalid params' });
        }
      },

      // 原生通过此方法回调(网页需实现 window.JSBridge.onCallback)
      onCallback: (callbackId: string, resultJson: string): void => {
        // 实际上这个方法由原生调用网页,此处可留空或用于调试
        console.log('[JSBridge] onCallback called (should be in web side)');
      }
    };

    // 只暴露 JSBridge 对象,方法列表包含 invoke(onCallback 通常不被网页主动调用)
    this.controller.registerJavaScriptProxy(
      JSBridge,
      'JSBridge',
      ['invoke'] // 注意:onCallback 是原生调网页,不需要在这里暴露给网页调用
    );
  }

  // 功能实现:获取设备信息
  handleGetDeviceInfo(callbackId: string): void {
    //TODO
    const deviceInfo:DeviceInfo  = new DeviceInfo("","","")
    this.sendCallback(callbackId, { success: true, data: deviceInfo });
  }

  // 功能实现:显示 Toast
  handleShowToast(message: string, callbackId: string): void {
    // TODO 实际可调用 @ohos.promptAction
    this.sendCallback(callbackId, { success: true, message: 'Toast shown' });
  }

  // 功能实现:选择图片(示例,需集成媒体库)
  handlePickImage(callbackId: string): void {
    // TODO 模拟异步操作
    setTimeout(() => {
      this.sendCallback(callbackId, {
        success: true,
        data: { uri: 'file://image1.jpg' }
      });
    }, 800);
  }

  // 统一回调方法:调用网页的 window.JSBridge.onCallback
  sendCallback(callbackId: string, result: any): void {
    const resultStr = JSON.stringify(result);
    const jsCode = `typeof window.JSBridge?.onCallback === 'function' ?
                    window.JSBridge.onCallback(${JSON.stringify(callbackId)}, ${resultStr}) :
                    console.warn('JSBridge.onCallback not found')`;

    this.controller.callJavaScript(jsCode, (error) => {
      if (error) {
        console.error('[JSBridge] Callback failed:', error);
        //TODO 埋点
      }
    });
  }
}

网页实现

html 复制代码
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8" />
  <title>Unified JSBridge</title>
</head>
<body>
  <button onclick="getDeviceInfo()">获取设备信息</button>
  <button onclick="showMyToast()">显示原生提示</button>
  <button onclick="selectImage()">选择图片</button>

  <div id="output"></div>

  <script>
    // 全局回调映射表(避免 callbackId 冲突)
    const callbacks = new Map();

    // 统一调用方法
    function invoke(command, params = {}) {
      return new Promise((resolve, reject) => {
        if (!window.JSBridge) {
          reject(new Error('JSBridge not available'));
          return;
        }

        const callbackId = 'cb_' + Date.now() + '_' + Math.random().toString(36).slice(2);
        callbacks.set(callbackId, { resolve, reject });

        window.JSBridge.invoke(command, JSON.stringify(params), callbackId);
      });
    }

    // 原生回调入口(必须挂载到 window.JSBridge)
    window.JSBridge = window.JSBridge || {};
    window.JSBridge.onCallback = function (callbackId, result) {
      const cb = callbacks.get(callbackId);
      if (cb) {
        callbacks.delete(callbackId);
        if (result.success) {
          cb.resolve(result.data || result);
        } else {
          cb.reject(new Error(result.error || 'Operation failed'));
        }
      }
    };

    // 使用示例
    async function getDeviceInfo() {
      try {
        const info = await invoke('getDeviceInfo');
        document.getElementById('output').innerText = JSON.stringify(info, null, 2);
      } catch (e) {
        alert('Error: ' + e.message);
      }
    }

    async function showMyToast() {
      await invoke('showToast', { message: 'Hello from Web!' });
      alert('Toast sent to native');
    }

    async function selectImage() {
      const result = await invoke('pickImage');
      console.log('Selected image:', result.uri);
    }
  </script>
</body>
</html>
相关推荐
南村群童欺我老无力.12 小时前
Flutter 框架跨平台鸿蒙开发 - 打造手写签名板应用
flutter·华为·harmonyos
哈哈你是真的厉害13 小时前
基础入门 React Native 鸿蒙跨平台开发:AnimatedXY 动画插值
react native·react.js·harmonyos
夜雨声烦丿14 小时前
Flutter 框架跨平台鸿蒙开发 - 游戏存档管理器应用开发教程
flutter·游戏·华为·harmonyos
2501_9445264215 小时前
Flutter for OpenHarmony 万能游戏库App实战 - 21点游戏实现
android·javascript·flutter·游戏·harmonyos
翰德恩咨询15 小时前
从战略制定到卓越执行—华为BLM/DSTE战略规划理念和实践
华为
木斯佳15 小时前
HarmonyOS实战(源码教学篇)— 深入浅出鸿蒙特性【跨端迁移-应用接续】
华为·harmonyos
智慧化智能化数字化方案15 小时前
华为项目管理——解读华为客户重大项目管理流程概述【附全文阅读】
华为·华为项目管理·华为产品战略规划·华为客户重大项目管理流程·华为项目管理高级培训·华为研发pmo的能力·战略级项目管理
哈哈你是真的厉害16 小时前
小白基础入门 React Native 鸿蒙跨平台开发:AnimatedSpring 弹簧动画
react native·react.js·harmonyos
哈哈你是真的厉害16 小时前
基础入门 React Native 鸿蒙跨平台开发:颜色选择器工具
react native·react.js·harmonyos
不爱吃糖的程序媛16 小时前
Flutter-OH生态再升级:兼容库数量翻倍,全面支持Flutter 3.27,聚焦开发者体验
华为·harmonyos