Flutter/OpenHarmony 三方库适配实战:device_info_plus 设备信息
设备信息是应用诊断、客服排障和兼容性判断经常依赖的数据。device_info_plus在 Android、iOS、Web 等平台已有统一入口,但 OHOS 的字段命名、返回类型和隐私边界并不完全相同。本次适配的目标是让业务继续使用DeviceInfoPlugin,同时为 OHOS 提供一个强类型模型,并明确不返回需要特殊权限的设备标识。
一、项目信息与适配目标
| 项目 | 内容 |
|---|---|
| 仓库名称 | device_info_plus |
| AtomGit 适配仓库 | https://atomgit.com/oh-flutter/device_info_plus |
| 上游版本 | 13.3.0 |
| OHOS 适配 TAG | 13.3.0-ohos-1.0.0-beta.1 |
| 适配分支 | main |
| 方法通道 | dev.fluttercommunity.plus/device_info |
| 原生模块 | OHOS HAR,入口类DeviceInfoPlusPlugin |
适配覆盖以下公开字段:
deviceType、manufacture、brand、marketName productSeries、productModel、productModelAlias softwareModel、hardwareModel、abiList bootloaderVersion、securityPatchTag osReleaseType、osFullName majorVersion、seniorVersion、featureVersion、buildVersion sdkApiVersion、firstApiVersion、versionId、buildType不返回serial、udid、diskSN等敏感或需要特殊授权的字段。设备型号也不是设备唯一标识,业务不能把它当作账号安全凭证。
环境搭建与版本
下面是本次适配实际使用的环境。环境搭建过程这里不再展开,直接看 Flutter OH 环境搭建指南。
| 项目 | 版本/说明 |
|---|---|
| Flutter OH | 3.44.9+ohos-0.0.1-canary1 |
| Dart | 3.12.2 |
| DevEco Studio | 26.0.0 |
| HarmonyOS SDK | API 26 |
| 目标仓库 | device_info_plus |
二、保留统一入口,新增 OHOS 强类型模型
跨平台业务可以继续调用DeviceInfoPlugin.deviceInfo(),它返回BaseDeviceInfo,原始 map 保存在data中:
import'package:device_info_plus/device_info_plus.dart';Future<void>printBaseInfo()async{finalDeviceInfoPlugindeviceInfo=DeviceInfoPlugin();finalBaseDeviceInfoinfo=awaitdeviceInfo.deviceInfo();print(info.data);}OHOS 业务如果需要明确字段,可以使用新增的OhosDeviceInfo:
Future<void>printOhosInfo()async{finalDeviceInfoPlugindeviceInfo=DeviceInfoPlugin();finalOhosDeviceInfoinfo=awaitdeviceInfo.ohosInfo;print(info.deviceType);print(info.manufacture);print(info.brand);print(info.marketName);print(info.productModel);print(info.osFullName);print(info.sdkApiVersion);}OhosDeviceInfo.fromMap对缺失字段提供稳定默认值,字符串使用'',整数使用0:
factoryOhosDeviceInfo.fromMap(Map<String,dynamic>data){returnOhosDeviceInfo._(data:data,deviceType:data['deviceType']asString???'',manufacture:data['manufacture']asString???'',brand:data['brand']asString???'',marketName:data['marketName']asString???'',productModel:data['productModel']asString???'',osFullName:data['osFullName']asString???'',sdkApiVersion:(data['sdkApiVersion']asnum?)?.toInt()??0,// 其余字段采用同样的安全默认值);}这样既保留了上游data兼容性,也让 OHOS 业务不必反复写字符串 key。
OHOS 工程目录创建
本次适配前,上游仓库没有ohos/目录。适配分支上按 Flutter OH 的插件工程约束创建平台目录,再把 ArkTS 入口接入pubspec.yaml:
gitswitch-c<your-ohos-adaptation-branch>flutter create--platformsohos.工程生成后至少保留以下边界:
ohos/ ├── index.ets ├── oh-package.json5 └── src/main/ ├── module.json5 └── ets/components/plugin/示例工程还需要生成example/ohos/,并在插件pubspec.yaml的flutter.plugin.platforms.ohos中声明pluginClass;只创建目录、没有注册入口,Dart 方法通道仍然不会工作。
三、Dart 注册类连接平台接口
主包中的 OHOS 注册类继承上游平台接口:
classDeviceInfoPlusOhosPluginextendsDeviceInfoPlatform{staticconstMethodChannelchannel=MethodChannel('dev.fluttercommunity.plus/device_info',);staticvoidregisterWith(){DeviceInfoPlatform.instance=DeviceInfoPlusOhosPlugin();}@overrideFuture<BaseDeviceInfo>deviceInfo()async{finalMap<Object?,Object?>result=awaitchannel.invokeMapMethod<Object?,Object?>('getDeviceInfo')??<Object?,Object?>{};returnOhosDeviceInfo.fromMap(result.cast<String,dynamic>());}}插件声明同时指定原生类和 Dart 类:
flutter:plugin:platforms:ohos:pluginClass:DeviceInfoPlusPlugindartPluginClass:DeviceInfoPlusOhosPlugin这里的pluginClass负责原生方法通道,dartPluginClass负责把平台 map 转成 Dart 模型。只配置其中一项,通常会出现 Dart 调用没有返回或注册了错误平台实现的问题。
四、ArkTS 层读取系统公共字段
原生入口只处理一个方法getDeviceInfo:
import{deviceInfo}from'@kit.BasicServicesKit';constCHANNEL='dev.fluttercommunity.plus/device_info';exportdefaultclassDeviceInfoPlusPluginimplementsFlutterPlugin,MethodCallHandler{privatechannel:MethodChannel|null=null;onAttachedToEngine(binding:FlutterPluginBinding):void{this.channel=newMethodChannel(binding.getBinaryMessenger(),CHANNEL,);this.channel.setMethodCallHandler(this);}onMethodCall(call:MethodCall,result:MethodResult):void{if(call.method!=='getDeviceInfo'){result.notImplemented();return;}result.success({deviceType:deviceInfo.deviceType,manufacture:deviceInfo.manufacture,brand:deviceInfo.brand,marketName:deviceInfo.marketName,productSeries:deviceInfo.productSeries,productModel:deviceInfo.productModel,softwareModel:deviceInfo.softwareModel,hardwareModel:deviceInfo.hardwareModel,abiList:deviceInfo.abiList,osReleaseType:deviceInfo.osReleaseType,osFullName:deviceInfo.osFullName,sdkApiVersion:deviceInfo.sdkApiVersion,firstApiVersion:deviceInfo.firstApiVersion,versionId:deviceInfo.versionId,buildType:deviceInfo.buildType,}asESObject);}}实现中没有调用序列号、UDID 或磁盘序列号接口。deviceInfo是 OHOS 公共服务字段,不需要在 HAR 中申请额外权限。
五、字段映射和隐私边界
| Dart 字段 | OHOS 来源 | 说明 |
|---|---|---|
deviceType | deviceInfo.deviceType | 手机、平板等设备类型 |
manufacture | deviceInfo.manufacture | 制造商 |
brand | deviceInfo.brand | 品牌 |
marketName | deviceInfo.marketName | 市场名称 |
productSeries | deviceInfo.productSeries | 产品系列 |
productModel | deviceInfo.productModel | 产品型号 |
softwareModel | deviceInfo.softwareModel | 软件型号 |
hardwareModel | deviceInfo.hardwareModel | 硬件型号 |
abiList | deviceInfo.abiList | ABI 列表 |
osFullName | deviceInfo.osFullName | 完整系统名称 |
sdkApiVersion | deviceInfo.sdkApiVersion | SDK API 版本 |
versionId | deviceInfo.versionId | 系统版本 ID |
buildType | deviceInfo.buildType | 构建类型 |
不同设备、发行版和系统版本可能返回空字符串,业务展示时应提供默认文案。示例页面使用ListView展示收到的字段,方便在模拟器上检查真实返回值。
适配过程 FAQ 与解决方案
为什么上游没有ohos/时不能只在 Dart 层补字段?
解决方案:Dart 层只能统一数据结构,无法读取@kit.BasicServicesKit的deviceInfo。先建立ohos/目录,再让注册类把 OHOS 公共字段映射为强类型模型,才能保证不同平台的字段语义一致。
为什么 OHOS 返回模型不能照抄 Android?
解决方案:OHOS 的品牌、型号、系统版本和设备类型字段命名不同,部分字段在模拟器或发行版中可能为空。适配时只读取公共字段,不把序列号、UDID 等隐私标识塞进返回 map。
字段全部为空时怎么定位?
解决方案:按“插件是否注册 ->getDeviceInfo是否返回 map -> ArkTS 日志是否打印字段 -> 示例页面是否刷新”逐层检查。不要先改 Dart 默认值,否则会把真实的原生通道问题掩盖掉。
模拟器截图可以证明什么?
解决方案:它能证明 HAP 安装、插件注册和字段展示链路已经跑通;设备品牌、型号和系统版本仍应在真机上采集,才能作为兼容性结论。
六、测试和真实截图
新增测试覆盖 OHOS map 解析、默认值和元数据声明:
fluttertest\test/model/ohos_device_info_test.dart\test/ohos_plugin_metadata_test.dart结果:All tests passed。
flutter analyze结果:无 error。
示例工程执行:
cdpackages/device_info_plus/device_info_plus/example flutter build hap--debughdcinstall-rohos/entry/build/default/outputs/default/entry-default-unsigned.hap hdc shell aa start-aEntryAbility-bcom.example.device_info_plus_example版本与提交基线
| 项目 | 版本/地址 |
|---|---|
| 上游包 | device_info_plus |
| 上游最新版本 | 13.3.0 |
| 文章目标基线 | 13.3.0-ohos-1.0.0-beta.1 |
| 当前已发布 TAG | 13.3.0-ohos-1.0.0-beta.1 |
| 适配分支 | main |
| 目标最新 TAG | 13.3.0-ohos-1.0.0-beta.1 |
| 最终提交 | e06bd04 |
版本号更新只代表文章和适配分支的基线已对齐;涉及上游 API 变更时,仍需在该 TAG 上重新运行 Dart 测试、ArkTS 编译、HAP 安装和真机回归。
参考资料和仓库地址
- 适配仓库主页
- 适配分支 main
- 当前已发布 TAG 13.3.0-ohos-1.0.0-beta.1
- 目标最新 TAG 13.3.0-ohos-1.0.0-beta.1
- 最终提交 e06bd04
- ArkTS 通道实现
- 鸿蒙适配说明
- pub.dev 包页面
- pub.dev 13.3.0 版本页
- 上游仓库
- Flutter 官方插件与平台通道文档
- Flutter OH 鸿蒙 SDK 仓库
- HarmonyOS 开发者官方文档
欢迎加入 CPF-Flutter 鸿蒙社区。
七、常见问题和排查顺序
- 返回的字段全部为空:检查原生通道是否注册、HAR 是否被应用工程依赖、
getDeviceInfo方法是否返回 map。 - Dart 编译找不到
OhosDeviceInfo:确认主包lib/device_info_plus.dart已导出 OHOS 模型。 - 页面没有标题:确认
TargetPlatform.ohos分支存在,示例标题会显示为OHOS Device Info。 - 不要把
productModel当唯一设备 ID:型号可能被多个设备使用,且字段可能为空。 - 不要在文档或日志中补写
serial、udid:首版明确不采集这些敏感标识。
社区
- OpenHarmony Flutter 社区:https://atomgit.com/oh-flutter
- CPF-Flutter 社区:https://atomgit.com/CPF-Flutter
- 本适配仓库讨论区:https://atomgit.com/oh-flutter/device_info_plus/issues
欢迎提交设备型号、系统版本、返回字段截图和 hilog 日志,一起完善 OHOS 设备信息适配。