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>
相关推荐
cz追天之路5 小时前
华为机考 ------ 识别有效的IP地址和掩码并进行分类统计
javascript·华为·typescript·node.js·ecmascript·less·css3
航Hang*6 小时前
第五章:网络系统建设与运维(中级)——生成树协议
运维·服务器·网络·笔记·华为·ensp
航Hang*10 小时前
第三章:网络系统建设与运维(中级)——交换技术
运维·笔记·计算机网络·华为·ensp·交换机
l1340620823511 小时前
Flutter Geocoding 在鸿蒙上的使用指南
flutter·华为·harmonyos
无人装备硬件开发爱好者11 小时前
华为海思 BS21E (H2821E) 星闪组网测距定位 技术可行性方案
华为·最小二乘法·星闪·测距定位
俩毛豆11 小时前
【毛豆工具集】【UI】【多设备适配】实现与屏幕密度等倍的图片加载
华为·harmonyos
l1340620823512 小时前
344.在鸿蒙上使用 animations Flutter 包的指南
flutter·华为·harmonyos
灯前目力虽非昔,犹课蝇头二万言。13 小时前
HarmonyOS笔记12:生命周期
笔记·华为·harmonyos
Random_index14 小时前
#HarmonyOS篇:学习UI规范基本语法&&学习UI范式装填管理V1&&学习UI范式装填管理V2&&学习UI范式渲染控制
harmonyos