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>
相关推荐
anyup10 小时前
🔥2026最推荐的跨平台方案:H5/小程序/App/鸿蒙,一套代码搞定
前端·uni-app·harmonyos
Ranger092915 小时前
鸿蒙开发新范式:Gpui
rust·harmonyos
Huang兄15 小时前
鸿蒙-深色模式适配
harmonyos·arkts·arkui
SummerKaze3 天前
为鸿蒙开发者写一个 nvm:hmvm 的设计与实现
harmonyos
在人间耕耘4 天前
HarmonyOS Vision Kit 视觉AI实战:把官方 Demo 改造成一套能长期复用的组件库
人工智能·深度学习·harmonyos
王码码20354 天前
Flutter for OpenHarmony:socket_io_client 实时通信的事实标准(Node.js 后端的最佳拍档) 深度解析与鸿蒙适配指南
android·flutter·ui·华为·node.js·harmonyos
HarmonyOS_SDK4 天前
【FAQ】HarmonyOS SDK 闭源开放能力 — Ads Kit
harmonyos
Swift社区4 天前
如何利用 ArkUI 框架优化鸿蒙应用的渲染性能
华为·harmonyos
特立独行的猫a4 天前
uni-app x跨平台开发实战:开发鸿蒙HarmonyOS影视票房榜组件完整实现过程
华为·uni-app·harmonyos·轮播图·uniapp-x
盐焗西兰花5 天前
鸿蒙学习实战之路-STG系列(5/11)-守护策略管理-添加与修改策略
服务器·学习·harmonyos