Capacitor 插件鸿蒙化实战:@capacitor/device 从安装到模拟器验证全记录

Capacitor 插件鸿蒙化实战:@capacitor/device 从安装到模拟器验证全记录

本文聚焦插件层 :以 CPF-Ionic 鸿蒙化的 @capacitor/device 插件为例,完整走通"安装插件 → React 调用 → 构建签名 → 模拟器运行验证"全链路,所有步骤实测。


一、插件生态背景

1.1 CPF-Ionic 插件体系

Capacitor 的设备能力全部通过插件(@capacitor/xxx)提供。华为 CPF-Ionic 团队按"原插件包名不变、原生实现替换为 OHOS "的原则完成了 29 个官方插件 + 14 个 Ionic 三方插件的鸿蒙化,完整清单见 ionic-readme(已同步至 AtomGit,组织主页 https://atomgit.com/cpf-ionic ):

  • Capacitor 官方插件:app、browser、camera、device、filesystem、keyboard、barcode-scanner、app-launcher、clipboard、geolocation、haptics、push-notifications、network、share、status-bar、text-zoom、action-sheet、dialog、screen-reader、splash-screen、toast、file-transfer、file-viewer、inappbrowser、local-notifications、motion、preferences、privacy-screen、screen-orientation
  • Ionic 三方插件 (@ionic-native/xxx 对应):status-bar、splash-screen、file、in-app-browser、device、file-transfer、app-version、camera、clipboard、file-opener、keyboard、network、android-permissions、pdf-generator

1.2 鸿蒙化插件的双包结构

每个鸿蒙化插件由两个 npm 包组成:

包 角色 安装位置
@capacitor/device(官方原包) Web/API 层:TS 类型定义 + Promise API,Web 层调用的入口 前端工程 node_modules
@capacitor-ohos/device OHOS 原生实现:ArkTS + C++(Device.ets / Device.cpp / Device.h) 由 hionic 拷入 openharmony/capacitor/ 参与编译

Web 层调用 Device.getInfo() 时代码与 Android/iOS 完全一致------插件鸿蒙化的全部意义就在于此:API 契约不变,原生实现替换。

1.3 插件接入鸿蒙工程需要做的四件事

查看插件的 plugin.xml 可知,一个 OHOS Capacitor 插件接入壳工程需要四处修改:

  1. 插件注册表 :entry/src/main/resources/rawfile/capacitor.plugins.json 加 {"pkg": "@capacitor/device", "classpath": "Device"};
  2. CMake 编译 :capacitor/src/main/cpp/CMakeLists.txt 加 add_subdirectory(Device) 并链入 Device 库;
  3. 源码拷贝 :C++(Device.h/.cpp/CMakeLists.txt)→ cpp/Device/,ArkTS(Device.ets)→ ets/components/Device/;
  4. ArkTS 编译范围 :capacitor/build-profile.json5 的 buildOption.arkOptions.runtimeOnly.sources 加入 Device.ets。

好消息:这四步 hionic 全部自动化,一条命令搞定(见下文)。


二、环境

延续上一篇的 capacitorMyApp 项目(hionic 2.1.16 / Capacitor 8.5.2 / @capacitor-ohos/ohos 8.0.2 / openssl 已集成 / 模拟器 127.0.0.1:5555 在线)。


三、逐步操作过程

第 1 步:安装插件

bash 复制代码
hionic plugin add @capacitor/device

一条命令,hionic 自动完成了上面第一节的全部四件事,关键输出:

复制代码
log: ✓ Added runtimeOnly source: ./src/main/ets/components/Device/Device.ets
log: Installing CMakeLists configuration to: src/main/cpp/CMakeLists.txt
log: Updated CMakeLists.txt: src/main/cpp/CMakeLists.txt
log:   - add_subdirectory(Device)
log: Installing config-json to: src/main/resources/rawfile/capacitor.plugins.json
log: Successfully added plugin: @capacitor/device

验证四处修改都已落盘:

bash 复制代码
# ① 注册表
$ cat openharmony/entry/src/main/resources/rawfile/capacitor.plugins.json
[
  { "pkg": "@capacitor/CapacitorPlugin", "classpath": "CapacitorPlugin" },
  { "pkg": "@capacitor/device", "classpath": "Device" }        ← 新增
]

# ② CMake
$ grep Device openharmony/capacitor/src/main/cpp/CMakeLists.txt
add_subdirectory(Device)     ← 第 20 行
    Device                   ← target_link_libraries 中链入

# ③ 源码
$ ls openharmony/capacitor/src/main/cpp/Device/
CMakeLists.txt  Device.cpp  Device.h
$ ls openharmony/capacitor/src/main/ets/components/Device/
Device.ets

# ④ npm 双包
$ grep device package.json
"@capacitor-ohos/device": "^8.0.2"   ← 鸿蒙原生实现
"@capacitor/device": "^8.0.3"        ← 官方 API 层

卸载 同样一条命令:hionic plugin remove @capacitor/device。

第 2 步:React 层调用插件

修改 src/App.jsx(与 Android/iOS 上的写法完全一致):

jsx 复制代码
import { useState, useEffect } from 'react'
import { Device } from '@capacitor/device'

function App() {
  const [device, setDevice] = useState(null)

  useEffect(() => {
    const load = async () => {
      try {
        const [info, id, battery, lang] = await Promise.all([
          Device.getInfo(),
          Device.getId(),
          Device.getBatteryInfo(),
          Device.getLanguageTag(),
        ])
        setDevice({ info, id, battery, lang })
        console.log('Device info:', info)
        console.log('Device id:', id)
      } catch (e) {
        console.error('Device plugin error:', e)
      }
    }
    load()
  }, [])

  // ... 渲染部分追加设备信息区块
  return (
    <>
      {/* 原有 UI */}
      {device && (
        <div className="device-info">
          <h2>Device Info (Capacitor OHOS)</h2>
          <ul>
            <li>name: {device.info.name}</li>
            <li>model: {device.info.model}</li>
            <li>platform: {device.info.platform}</li>
            <li>operatingSystem: {device.info.operatingSystem}</li>
            <li>osVersion: {device.info.osVersion}</li>
            <li>manufacturer: {device.info.manufacturer}</li>
            <li>isVirtual: {String(device.info.isVirtual)}</li>
            <li>memUsed: {device.info.memUsed} bytes</li>
            <li>identifier (ODID): {device.id.identifier}</li>
            <li>batteryLevel: {device.battery.batteryLevel ?? 'N/A'}</li>
            <li>isCharging: {String(device.battery.isCharging)}</li>
            <li>languageTag: {device.lang.value}</li>
          </ul>
        </div>
      )}
    </>
  )
}

一次并发调用四个 API,覆盖插件的全部五类能力中的四类(getInfo / getId / getBatteryInfo / getLanguageTag)。

第 3 步:构建 → 同步 → 编译 HAP

Capacitor 标准三连(注意每次改完前端都要重新 buildui + sync):

bash 复制代码
hionic buildui                       # vite build → dist/(233KB JS)
hionic sync openharmony              # dist → rawfile/www/,同时刷新插件注册

# 编译鸿蒙工程
cd openharmony
export DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk
export PATH=".../tools/hvigor/bin:.../tools/node/bin:.../tools/ohpm/bin:$PATH"
hvigorw assembleHap --mode module -p module=entry@default -p product=default \
  -p requiredDeviceType=phone --no-daemon

输出:

复制代码
> hvigor Finished :entry:default@SignHap... after 917 ms
> hvigor BUILD SUCCESSFUL in 4 s 896 ms
41 tasks in total: 32 executed, 9 up-to-date

注意这次编译比上次多了 Device.cpp 的 NAPI 编译任务(32 executed vs 上次 26),签名配置沿用 DevEco 自动签名,直接产出 signed HAP。

第 4 步:安装到模拟器并运行

bash 复制代码
hdc list targets                # 127.0.0.1:5555
hdc install -r openharmony/entry/build/default/outputs/default/entry-default-signed.hap
# [Info] install bundle successfully

hdc shell aa start -a EntryAbility -b com.nutpi.MyApp
# start ability successfully.

第 5 步:验证

日志验证 (hdc shell hilog -x | grep ARKWEB-CONSOLE)------插件调用真实发生并返回:

复制代码
ARKWEB-CONSOLE: "Device info: [object Object]"   ← Device.getInfo() 成功
ARKWEB-CONSOLE: "Device id: [object Object]"     ← Device.getId() 成功

截图验证 (hdc shell snapshot_display -f /data/local/tmp/cap_device.jpeg + hdc file recv):

页面完整渲染出设备信息:

字段 模拟器返回值 说明
name / model emulator
platform / operatingSystem HarmonyOS 插件正确上报鸿蒙平台
osVersion OpenHarmony-7.0.0.105 模拟器 ROM 版本
manufacturer HUAWEI
isVirtual true 正确识别模拟器(真机应为 false)
memUsed 336972 bytes 应用内存占用

四、桥接链路解析

一次 Device.getInfo() 调用的完整数据流:

复制代码
React (App.jsx)
  │  Device.getInfo()  ← @capacitor/device 官方 API 层,跨平台一致
  ▼
capacitor.js / native-bridge.js  ← rawfile/www/ 下的桥接脚本
  │  JSON 消息 {plugin:"Device", method:"getInfo"}
  ▼
ArkWeb Web 组件拦截 → ArkTS 容器层
  ▼
capacitor.plugins.json 注册表 → 找到 classpath "Device"
  ▼
Device.ets(ArkTS)→ Device.cpp(C++/NAPI,编译进 libcapacitor.so)
  │  调用 OpenHarmony 系统 API(@ohos.deviceInfo / batteryInfo / i18n)
  ▼
结果 JSON 回传 → Promise resolve → React setState → 页面渲染

关键点:

  • API 契约不变 :getId() 在 OHOS 上返回 ODID(OpenHarmony 设备标识),Android 返回 GUID,iOS 返回 UIDevice identifier------语义等价,Web 层无感;
  • 注册表驱动 :capacitor.plugins.json 的 pkg/classpath 映射是插件查找的依据,这就是为什么手动接入时漏掉第①步会导致插件调用无响应;
  • 编译双链 :ArkTS 文件要进 runtimeOnly.sources,C++ 要进 CMake,漏一个都会在运行时报 "plugin not found" 或编译期报符号缺失。

五、踩坑复盘

本项目插件环节很顺利(hionic 自动化程度高),但有几个易错点值得记录:

# 易错点 现象 规避方法
1 改了前端忘记 sync 模拟器上跑的还是旧页面 每次 buildui 后必须 hionic sync openharmony,再重新 hvigorw 编译
2 混淆 hionic 插件安装方式 以为要按 README"手动引入"四步走 命令行安装(hionic plugin add)会自动完成四步,手动引入仅用于 hionic 无法处理的特殊插件
3 console.log 看不到输出 ArkWeb 的 console 走 hilog 用 `hdc shell hilog -x
4 截图时机 应用启动有加载过程 aa start 后 sleep 3 秒再 snapshot_display
5 前置条件 Device.cpp 编译失败 确认上一篇的 openssl(libs + 头文件)已集成------capacitor 原生库与插件共享同一 CMake 工程

六、总结

在鸿蒙上给 Capacitor 应用装插件,核心路径可以概括为三步走:

复制代码
1. 一条命令 ── hionic plugin add @capacitor/xxx,四项工程修改全自动
2. 零改动   ── React 层 import 原包调用,API 与 Android/iOS 完全一致
3. 三连循环 ── buildui → sync → hvigorw,hilog + snapshot 验证

以 @capacitor/device 为样板验证后,CPF-Ionic 清单里的其余 40+ 插件(camera、geolocation、filesystem......)都可按同样路径接入。唯一需要留意的差异是各插件 README 中标注的权限要求(如 geolocation 需在 module.json5 声明定位权限及 reason)------device 插件无需权限,是最适合作为首个验证的插件。


参考文档

相关推荐
2501_919749037 小时前
华为鸿蒙免费记账与生活统计APP—小羊统计
华为·生活·harmonyos·鸿蒙
Fate_I_C7 小时前
Capacitor 应用鸿蒙化实战:用 hionic 把 React 应用跑在 OpenHarmony 上
react.js·华为·harmonyos
SuperHeroWu77 小时前
华为云码道接入 DevEco CLI 鸿蒙应用开发AICoding
华为·华为云·harmonyos
ChinaDragonDreamer8 小时前
HarmonyOS:User Authentication Kit简介
华为·harmonyos
m0_738185828 小时前
Flutter 鸿蒙化实战:qrcode_flutter 适配 OpenHarmony,二维码生成与识别
数码相机·flutter·华为·harmonyos·鸿蒙
万物智能信息科技8 小时前
血氧心跳传感器MAX30100芯片驱动开发—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
人工智能·驱动开发·华为·开源·harmonyos·鸿蒙
老陈说编程8 小时前
1. 鸿蒙 (HarmonyOS) 2012 至 2026 年的发展历程
分布式·华为·个人开发·harmonyos·鸿蒙·鸿蒙系统·程序员创富
m0_738185829 小时前
Flutter 鸿蒙化实战:open_app_settings 适配 OpenHarmony,一键跳转系统设置
flutter·华为·harmonyos·鸿蒙
Fate_I_C9 小时前
拆解一个鸿蒙化插件:CPF-Ionic 是如何把 43 个 Capacitor 插件搬上 OpenHarmony 的
华为·harmonyos