使用Chrome DevTools远程调试HarmonyOS 5上的Cordova应用

161 阅读3分钟

以下为 ​​使用Chrome DevTools远程调试HarmonyOS 5上Cordova应用的完整方案​​,包含调试协议适配、通信桥接和实操代码:


1. 调试架构设计

image.png


2. 核心调试模块

2.1 WebView调试启用

// webview-debug.ets
import web_engine from '@ohos.web.webview';

class WebViewDebugger {
  static enableDebugging(webView: web_engine.WebView): void {
    // 启用远程调试
    webView.setWebContentsDebuggingEnabled(true);
    
    // 注入调试桥接脚本
    webView.addJavascriptInterface(
      'nativeDebugBridge',
      this._handleNativeCall.bind(this)
    );

    // 设置前端调试端口
    webView.setDevToolsPort(9222);
  }

  private static _handleNativeCall(method: string, args: string): string {
    return NativeDispatcher.dispatch(method, JSON.parse(args));
  }
}

2.2 Chrome协议适配器

// chrome-protocol-adapter.ets
class ChromeProtocolAdapter {
  private static wsConnection: WebSocket;

  static async connect(port: number = 9222): Promise<void> {
    this.wsConnection = new WebSocket(`ws://localhost:${port}/devtools/page/1`);
    
    this.wsConnection.on('message', (data) => {
      this._handleCommand(JSON.parse(data));
    });
  }

  private static _handleCommand(command: ChromeCommand): void {
    switch (command.method) {
      case 'Runtime.evaluate':
        this._handleEvaluate(command);
        break;
      case 'DOM.getDocument':
        this._sendResponse({
          id: command.id,
          result: DOMSnapshot.capture()
        });
        break;
    }
  }
}

3. 调试桥接实现

3.1 JavaScript与原生通信

// js-native-bridge.ets
class JSNativeBridge {
  private static messageQueue: Message[] = [];

  static postMessage(message: Message): void {
    this.messageQueue.push(message);
    this._flushQueue();
  }

  private static _flushQueue(): void {
    const webView = getActiveWebView();
    webView.evaluateJavaScript(`
      window.__nativeBridge?.(${JSON.stringify(this.messageQueue.shift())});
    `);
  }
}

3.2 双向调用处理

// www/debug-bridge.js
window.__nativeBridge = (message) => {
  switch (message.type) {
    case 'callNative':
      const result = callNativeMethod(message.method, message.args);
      window.__sendToDevTools({
        type: 'nativeResult',
        callId: message.callId,
        result
      });
      break;
  }
};

function __sendToDevTools(data) {
  if (window.__devToolsSocket) {
    window.__devToolsSocket.send(JSON.stringify(data));
  }
}

4. 调试环境搭建

4.1 端口转发配置

# 在HarmonyOS设备上启用端口转发
hdc shell forward tcp:9222 localabstract:webview_devtools_remote

4.2 Chrome启动配置

// chrome-launcher.js
const chromeLauncher = require('chrome-launcher');

async function launchDebugger() {
  const chrome = await chromeLauncher.launch({
    startingUrl: 'chrome://inspect',
    userDataDir: false,
    port: 9222
  });
  
  console.log(`调试器已启动: http://localhost:${chrome.port}`);
}

5. 完整调试流程

5.1 初始化调试会话

// debug-session.ets
class DebugSession {
  static async start(): Promise<void> {
    // 1. 启用WebView调试
    WebViewDebugger.enableDebugging(getMainWebView());
    
    // 2. 启动协议适配器
    await ChromeProtocolAdapter.connect();
    
    // 3. 注入调试脚本
    this._injectDebugScripts();
    
    console.log('调试会话已建立');
  }

  private static _injectDebugScripts(): void {
    const webView = getMainWebView();
    webView.evaluateJavaScript(`
      // 注入前端调试脚本
      ${fs.readTextSync('./www/debug-bridge.js')}
      
      // 连接DevTools
      window.__devToolsSocket = new WebSocket('ws://localhost:9222/devtools/page/1');
    `);
  }
}

5.2 调试器连接示例

# 步骤1:启动设备调试服务
hdc shell start-debug-server

# 步骤2:端口转发
hdc forward tcp:9222 tcp:9222

# 步骤3:Chrome访问
chrome://inspect/#devices

6. 高级调试功能

6.1 性能分析集成

// performance-profiler.ets
class PerformanceProfiler {
  static startRecording(): void {
    getMainWebView().evaluateJavaScript(`
      window.performance.mark('debugStart');
      window.__performanceEntries = [];
      
      const observer = new PerformanceObserver(list => {
        window.__performanceEntries.push(...list.getEntries());
      });
      
      observer.observe({ entryTypes: ['measure', 'resource'] });
    `);
  }

  static stopRecording(): PerformanceEntry[] {
    return getMainWebView().evaluateJavaScript(`
      window.performance.mark('debugEnd');
      window.performance.measure('debugSession', 'debugStart', 'debugEnd');
      
      return JSON.stringify(window.__performanceEntries);
    `).then(JSON.parse);
  }
}

6.2 元素审查适配器

// dom-adapter.ets
class DOMAdapter {
  static getElementById(id: string): Promise<DOMNode> {
    return getMainWebView().evaluateJavaScript(`
      (function() {
        const el = document.getElementById('${id}');
        return {
          tagName: el.tagName,
          attributes: Array.from(el.attributes).map(attr => ({
            name: attr.name,
            value: attr.value
          })),
          children: el.children.length
        };
      })()
    `);
  }
}

7. 错误处理与日志

7.1 控制台日志拦截

// console-interceptor.ets
class ConsoleInterceptor {
  static install(): void {
    const webView = getMainWebView();
    webView.addJavascriptInterface('__consoleProxy', this._handleLog.bind(this));
    
    webView.evaluateJavaScript(`
      ['log', 'warn', 'error'].forEach(method => {
        const original = console[method];
        console[method] = (...args) => {
          window.__consoleProxy(method, args);
          original.apply(console, args);
        };
      });
    `);
  }

  private static _handleLog(method: string, args: any[]): void {
    LogServer.broadcast({
      type: 'console',
      method,
      messages: args,
      timestamp: Date.now()
    });
  }
}

7.2 调试错误捕获

// error-handler.js
window.addEventListener('error', (event) => {
  window.__devToolsSocket?.send(JSON.stringify({
    type: 'windowError',
    error: {
      message: event.message,
      stack: event.error?.stack,
      filename: event.filename,
      lineno: event.lineno
    }
  }));
});

8. 调试协议扩展

8.1 自定义协议命令

// custom-protocol.ets
class CustomProtocolHandler {
  static handle(command: string, params: any): any {
    switch (command) {
      case 'Cordova.getPlugins':
        return this._getInstalledPlugins();
      case 'Cordova.invokePlugin':
        return this._invokePluginMethod(params);
    }
  }

  private static _getInstalledPlugins(): string[] {
    return Object.keys(window.cordova.plugins);
  }
}

8.2 协议响应包装

// protocol-wrapper.ets
class ProtocolResponse {
  static success(id: number, result: any): ProtocolMessage {
    return { id, result };
  }

  static error(id: number, error: Error): ProtocolMessage {
    return { 
      id, 
      error: {
        code: -32000,
        message: error.message,
        data: error.stack
      }
    };
  }
}

9. 调试界面集成

9.1 Chrome插件扩展

// chrome-extension/content.js
chrome.devtools.panels.create(
  'Cordova',
  'icon.png',
  'panel.html',
  (panel) => {
    panel.onShown.addListener((window) => {
      window.postMessage({
        type: 'init',
        tabId: chrome.devtools.inspectedWindow.tabId
      });
    });
  }
);

9.2 设备状态监控

// device-monitor.ets
class DeviceMonitor {
  private static stats = {
    memory: 0,
    cpu: 0,
    webViews: 0
  };

  static start(): void {
    setInterval(async () => {
      this.stats = await this._collectStats();
      DevToolsServer.broadcast('deviceStats', this.stats);
    }, 1000);
  }

  private static _collectStats(): Promise<DeviceStats> {
    return DeviceInfo.getPerformanceMetrics();
  }
}

10. 完整调试示例

10.1 启动调试会话

# 步骤1:在设备上启动应用
hdc shell am start -n com.example.app/.MainAbility

# 步骤2:转发调试端口
hdc forward tcp:9222 localabstract:webview_devtools_remote

# 步骤3:打开Chrome调试器
chrome://inspect/#devices

10.2 调试流程代码

// main-debug.ets
import { startDebugSession } from '@harmony/debug-tools';

startDebugSession({
  webView: getMainWebView(),
  port: 9222,
  features: {
    domInspection: true,
    consoleInterception: true,
    performanceProfiling: true
  }
}).then(() => {
  console.log('调试会话已就绪');
});

关键调试能力对比

功能Chrome原生支持本方案实现
DOM审查
Console交互
网络请求监控⚠️部分
性能分析⚠️受限
原生插件调试

通过本方案可实现:

  1. ​完整DOM树​​ 审查与实时修改
  2. ​Console日志​​ 跨设备查看
  3. ​性能分析​​ 包含Web与原生调用
  4. ​插件方法​​ 直接调用调试