前言
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
本文将通过简洁明了的步骤,帮助开发者在5分钟 内快速上手apple_product_name库,实现在OpenHarmony设备上获取友好的产品名称 。对于初次接触该库的开发者来说,快速上手指南能够帮助你在最短的时间内理解库的核心功能并跑通第一个示例程序。本文将从添加依赖开始,逐步引导你完成库的集成、API调用和界面展示,每个步骤都配有项目中的真实代码和详细说明。
本文是apple_product_name OpenHarmony适配系列的第3篇,共30篇,带你从零到一跑通第一个设备名称查询示例。
一、快速上手三步走
1.1 整体流程概览
快速上手只需三个核心步骤:
- 添加依赖 :在
pubspec.yaml中声明Git依赖 - 安装依赖 :执行
flutter pub get拉取代码 - 调用API :导入库文件,调用
getProductName()
整个过程不超过5分钟,下面逐步详解每个步骤。
1.2 前置条件
在开始之前,请确认以下环境已就绪:
| 环境项 | 最低版本 | 验证命令 |
|---|---|---|
| Flutter OHOS | 3.35.7-dev | flutter --version |
| Dart SDK | 3.5.0 | dart --version |
| DevEco Studio | 6.0.2 Release | 打开IDE查看版本 |
| OpenHarmony SDK | API 20 | DevEco Studio中查看 |
| 真机设备 | ROM 6.0.0.130 SP8 | 设备设置→关于手机 |
提示 :如果环境尚未搭建,请先阅读第2篇:环境搭建与依赖配置完成准备工作。
二、第一步:添加依赖
2.1 配置pubspec.yaml
在项目的pubspec.yaml文件中添加apple_product_name的Git依赖:
yaml
dependencies:
flutter:
sdk: flutter
apple_product_name:
git:
url: https://gitcode.com/oh-flutter/flutter_apple_product_name.git
ref: main
由于OpenHarmony适配版本尚未发布到pub.dev官方仓库,需要通过Git依赖 引入。url指向GitCode平台上的适配仓库,ref: main指定使用主分支最新代码。
2.2 库自身的依赖声明
以下是库的pubspec.yaml中的真实版本约束(来自项目根目录):
yaml
name: apple_product_name
description: Library for translating Apple machine identifiers into Apple product names (e.g. 'iPhone17,1' to 'iPhone 16 Pro')
version: 3.7.0
homepage: https://github.com/kyle-seongwoo-jun/flutter_apple_product_name
environment:
sdk: ">=3.5.0 <4.0.0"
flutter: ">=3.22.0"
dependencies:
flutter:
sdk: flutter
device_info_plus: ">=10.0.0 <12.0.0"
库当前版本3.7.0 ,依赖device_info_plus获取Apple设备信息。鸿蒙平台不使用device_info_plus,而是通过自己的MethodChannel 和deviceInfo系统API实现。
2.3 鸿蒙平台插件声明
yaml
flutter:
plugin:
platforms:
ohos:
pluginClass: AppleProductNamePlugin
pubspec.yaml中通过flutter.plugin.platforms.ohos声明了鸿蒙平台的插件入口类为AppleProductNamePlugin。Flutter框架在应用启动时会根据这个配置自动加载并注册原生插件。
三、第二步:安装依赖
3.1 执行安装命令
bash
# 获取依赖包
flutter pub get
# 验证依赖是否安装成功
flutter pub deps | grep apple_product_name
执行flutter pub get后,Flutter会自动从Git仓库拉取代码并完成依赖解析。安装成功后,可以通过flutter pub deps查看依赖树,确认apple_product_name已正确安装。
3.2 安装结果验证
安装成功后,项目中会出现以下变化:
pubspec.lock文件中新增了apple_product_name的版本锁定记录.dart_tool/package_config.json中新增了包路径映射- 可以在代码中正常导入库文件
注意 :如果安装过程中遇到网络超时,可以配置国内镜像源后重试,详见第2篇:环境搭建与依赖配置。
四、第三步:调用API
4.1 导入库文件
dart
import 'package:apple_product_name/apple_product_name_ohos.dart';
这是OpenHarmony平台专用的API入口文件,其中定义了OhosProductName 类。注意导入路径是apple_product_name_ohos.dart而非apple_product_name.dart,后者是Apple设备专用的。
4.2 获取设备产品名称
dart
// 获取当前设备的友好产品名称
final productName = await OhosProductName().getProductName();
print(productName); // 输出: "HUAWEI Mate 60 Pro"
一行代码即可获取设备的友好名称。getProductName()是异步方法,需要使用await等待结果。内部会通过MethodChannel 调用原生层,在HUAWEI_DEVICE_MAP映射表中查找型号对应的产品名称。
4.3 获取设备型号标识符
dart
// 获取当前设备的型号标识符
final machineId = await OhosProductName().getMachineId();
print(machineId); // 输出: "ALN-AL00"
getMachineId()返回设备的原始型号标识符,这个值来自系统API deviceInfo.productModel。型号标识符在日志记录、问题排查等场景中非常有用。
4.4 查询任意型号
dart
// 查询任意型号的产品名称
final name = await OhosProductName().lookup('CFR-AN00');
print(name); // 输出: "HUAWEI Mate 70"
// 查询未收录的型号
final unknown = await OhosProductName().lookup('XXX-XX00');
print(unknown); // 输出: "XXX-XX00"(返回原始型号)
lookup()方法允许查询任意型号标识符对应的产品名称,不限于当前设备。如果映射表中未收录该型号,会返回原始的型号字符串作为兜底。
| 方法 | 返回类型 | 未找到时返回 | 使用场景 |
|---|---|---|---|
getProductName() |
Future<String> |
"Unknown" | 展示当前设备名称 |
getMachineId() |
Future<String> |
"Unknown" | 获取型号标识符 |
lookup(id) |
Future<String> |
原始id | 查询任意型号 |
lookupOrNull(id) |
Future<String?> |
null | 区分已知/未知设备 |
五、示例应用完整代码
5.1 项目真实示例代码
以下是项目中example/lib/main.dart的真实源码,展示了跨平台的使用方式:
dart
import 'dart:io';
import 'package:apple_product_name/apple_product_name.dart';
import 'package:apple_product_name/apple_product_name_ohos.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
Future<String> _loadProductName() async {
if (Platform.isIOS) {
final info = await DeviceInfoPlugin().iosInfo;
return info.utsname.productName;
} else if (Platform.isMacOS) {
final info = await DeviceInfoPlugin().macOsInfo;
return info.productName;
} else {
// 鸿蒙平台
try {
return await OhosProductName().getProductName();
} catch (e) {
return 'Unknown';
}
}
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Apple Product Name'),
),
body: FutureBuilder<String>(
future: _loadProductName(),
builder: (context, snapshot) {
final productName = snapshot.data ?? 'Loading...';
return Center(
child: Text(
productName,
style: Theme.of(context)
.textTheme
.headlineSmall!
.copyWith(color: Colors.black),
),
);
},
),
),
);
}
}
这段代码的核心逻辑:
- 通过
Platform.isIOS和Platform.isMacOS判断当前平台 - iOS/macOS使用device_info_plus获取设备信息
- 鸿蒙平台使用
OhosProductName().getProductName() FutureBuilder处理异步加载状态,数据未返回时显示"Loading..."
跨平台设计:示例代码展示了如何在同一个应用中同时支持iOS、macOS和OpenHarmony三个平台,通过平台判断分别调用不同的API。
5.2 示例工程依赖配置
示例工程的example/pubspec.yaml中的真实依赖:
yaml
name: apple_product_name_example
description: Demonstrates how to use the apple_product_name plugin.
publish_to: "none"
environment:
sdk: ">=3.5.0 <4.0.0"
dependencies:
flutter:
sdk: flutter
apple_product_name:
path: ../
cupertino_icons: ^1.0.2
device_info_plus: ^11.0.0
示例工程使用path: ../引用父目录的库源码,这是Flutter插件开发中的标准做法。device_info_plus: ^11.0.0用于iOS/macOS平台的设备信息获取。
六、原生层工作原理简析
6.1 插件入口
当Dart层调用API时,请求通过MethodChannel 传递到原生层。插件入口文件ohos/index.ets:
typescript
import AppleProductNamePlugin from './src/main/ets/components/plugin/AppleProductNamePlugin';
export default AppleProductNamePlugin;
export { AppleProductNamePlugin };
6.2 getProductName的原生实现
以下是AppleProductNamePlugin.ets中getProductName方法的真实源码:
typescript
private getProductName(result: MethodResult): void {
try {
const model = deviceInfo.productModel;
// 先从映射表查找
let productName = HUAWEI_DEVICE_MAP[model];
// 如果映射表没有,使用系统的 marketName
if (!productName) {
productName = deviceInfo.marketName || model;
}
result.success(productName);
} catch (e) {
const errorMsg = e instanceof Error ? e.message : String(e);
result.error("GET_PRODUCT_NAME_ERROR", errorMsg, null);
}
}
这是一个两级查找策略:
- 通过
deviceInfo.productModel获取型号标识符(如"ALN-AL00") - 在
HUAWEI_DEVICE_MAP映射表中查找友好名称 - 映射表未收录时,回退到系统
marketName字段 - 最后兜底返回原始型号
6.3 数据流转全链路
用户调用 OhosProductName().getProductName()
→ Dart层: _channel.invokeMethod('getProductName')
→ MethodChannel序列化消息
→ ArkTS层: onMethodCall() 路由到 getProductName()
→ 读取 deviceInfo.productModel
→ 查找 HUAWEI_DEVICE_MAP[model]
→ result.success(productName)
→ Dart层 Future<String> 完成
→ UI展示设备名称
整个链路通常在毫秒级完成,用户几乎感知不到延迟。
七、自己动手写一个完整页面
7.1 设备信息展示页面
基于项目示例代码,我们来写一个更完整的设备信息展示页面:
dart
import 'package:flutter/material.dart';
import 'package:apple_product_name/apple_product_name_ohos.dart';
class DeviceInfoPage extends StatefulWidget {
@override
_DeviceInfoPageState createState() => _DeviceInfoPageState();
}
class _DeviceInfoPageState extends State<DeviceInfoPage> {
String _productName = '加载中...';
String _machineId = '加载中...';
bool _isLoading = true;
@override
void initState() {
super.initState();
_loadDeviceInfo();
}
Future<void> _loadDeviceInfo() async {
try {
final ohos = OhosProductName();
final productName = await ohos.getProductName();
final machineId = await ohos.getMachineId();
setState(() {
_productName = productName;
_machineId = machineId;
_isLoading = false;
});
} catch (e) {
setState(() {
_productName = '获取失败';
_machineId = '获取失败';
_isLoading = false;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('设备信息')),
body: Center(
child: _isLoading
? const CircularProgressIndicator()
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('产品名称: $_productName',
style: Theme.of(context).textTheme.headlineSmall),
const SizedBox(height: 16),
Text('型号标识: $_machineId',
style: Theme.of(context).textTheme.bodyLarge),
],
),
),
);
}
}
这个页面使用StatefulWidget 管理状态,_isLoading标志控制加载指示器的显示。try-catch确保即使获取失败也不会崩溃。

上图展示了设备信息页面在华为手机上的实际运行效果。
八、使用FutureBuilder简化代码
8.1 FutureBuilder方式
对于简单场景,可以使用FutureBuilder进一步简化代码:
dart
class SimplePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('设备名称')),
body: FutureBuilder<String>(
future: OhosProductName().getProductName(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text('错误: ${snapshot.error}'));
}
return Center(
child: Text(
snapshot.data ?? 'Unknown',
style: Theme.of(context).textTheme.headlineMedium,
),
);
},
),
);
}
}
FutureBuilder根据异步操作的不同状态自动构建UI:
| 状态 | 说明 | UI展示 |
|---|---|---|
ConnectionState.waiting |
等待中 | 圆形进度指示器 |
snapshot.hasError |
发生错误 | 错误信息文本 |
snapshot.hasData |
数据就绪 | 设备名称文本 |
8.2 两种方式对比
| 对比项 | StatefulWidget | FutureBuilder |
|---|---|---|
| 代码量 | 较多 | 较少 |
| 状态管理 | 手动管理 | 自动管理 |
| 灵活性 | 高(可控制刷新时机) | 中(绑定Future生命周期) |
| 适用场景 | 复杂交互页面 | 简单数据展示 |
| 错误处理 | try-catch | snapshot.hasError |
建议:简单的设备信息展示用FutureBuilder,需要手动刷新或复杂交互的场景用StatefulWidget。
九、错误处理最佳实践
9.1 防御性编程
在生产环境中,建议对所有API调用进行完善的错误处理:
dart
import 'package:flutter/services.dart';
import 'package:apple_product_name/apple_product_name_ohos.dart';
Future<String> safeGetProductName() async {
try {
return await OhosProductName().getProductName();
} on PlatformException catch (e) {
// 原生侧执行出错(如插件未注册)
print('平台异常: ${e.code} - ${e.message}');
return 'Unknown Device';
} on MissingPluginException {
// 插件未注册
print('插件未注册,请检查GeneratedPluginRegistrant');
return 'Unknown Device';
} catch (e) {
// 其他未知异常
print('未知异常: $e');
return 'Unknown Device';
}
}
推荐的异常处理层级:
- PlatformException:原生侧执行出错,包含错误码和错误信息
- MissingPluginException:插件未注册,需检查注册链路
- 通用catch:兜底处理所有其他异常
9.2 常见错误及解决方案
| 错误类型 | 错误信息 | 原因 | 解决方案 |
|---|---|---|---|
| MissingPluginException | No implementation found | 插件未注册 | 检查GeneratedPluginRegistrant.ets |
| PlatformException | GET_PRODUCT_NAME_ERROR | 原生层执行异常 | 查看hdc hilog日志 |
| TimeoutException | Future timed out | MethodChannel超时 | 检查设备连接状态 |
十、构建与运行
10.1 构建HAP包
bash
# 构建debug版本
flutter build hap --debug
# 构建release版本
flutter build hap --release
# 查看详细构建日志
flutter build hap --debug --verbose
flutter build hap会执行完整的编译和打包流程,生成可安装的HAP文件(Harmony Ability Package)。
10.2 安装到设备
bash
# 查看已连接的设备
hdc list targets
# 安装HAP包
hdc install ./build/outputs/default/entry-default-signed.hap
# 查看插件相关日志
hdc hilog | grep "AppleProductNamePlugin"
hdc是OpenHarmony的设备连接工具,类似Android的adb。安装成功后,在设备上打开应用即可看到设备名称。
10.3 运行效果验证
运行成功后,应用界面应显示类似以下内容:
┌─────────────────────────┐
│ Apple Product Name │
├─────────────────────────┤
│ │
│ HUAWEI Mate 60 Pro │
│ │
└─────────────────────────┘
如果显示"Unknown"或"Loading..."停留不动,请按以下步骤排查:
- 检查
GeneratedPluginRegistrant.ets是否注册了插件 - 检查
EntryAbility.ets是否调用了registerWith - 查看
hdc hilog日志中是否有错误信息
十一、支持的设备映射表预览
11.1 部分设备映射
HUAWEI_DEVICE_MAP映射表中收录了**90+**华为/荣耀设备,以下是部分示例:
typescript
const HUAWEI_DEVICE_MAP: Record<string, string> = {
// Mate 70 系列
"CFR-AN00": "HUAWEI Mate 70",
"CFS-AN00": "HUAWEI Mate 70 Pro",
"CFT-AN00": "HUAWEI Mate 70 Pro+",
"CFU-AN00": "HUAWEI Mate 70 RS 非凡大师",
// Mate 60 系列
"BRA-AL00": "HUAWEI Mate 60",
"ALN-AL00": "HUAWEI Mate 60 Pro",
"GGK-AL10": "HUAWEI Mate 60 Pro+",
// Pura 70 系列
"HBN-AL00": "HUAWEI Pura 70",
"DUA-AL00": "HUAWEI Pura 70 Pro",
"HBK-AL00": "HUAWEI Pura 70 Ultra",
// nova 系列
"FOA-AL00": "HUAWEI nova 13",
"FNA-AL00": "HUAWEI nova 13 Pro",
// 荣耀系列
"PGT-AN00": "Honor Magic6 Pro",
"BVL-AN00": "Honor Magic6",
// ... 共90+个型号映射
};
11.2 设备系列覆盖
| 设备系列 | 代表型号 | 映射数量 |
|---|---|---|
| Mate系列 | Mate 70/60/X5/X3 | 22个 |
| Pura系列 | Pura 70/P60 | 12个 |
| nova系列 | nova 13/12/11 | 14个 |
| Pocket系列 | Pocket 2/Pocket S | 4个 |
| MatePad系列 | MatePad Pro/Air | 10个 |
| 荣耀Magic | Magic6/Magic5 | 8个 |
| 荣耀数字 | Honor 200/100 | 8个 |
| 华为手表 | WATCH GT/Ultimate | 12个 |
映射表会随新设备发布持续更新,社区开发者也可以通过提交Pull Request贡献新设备数据。
十二、进阶用法预告
12.1 更多API能力
除了本文介绍的基础用法,该库还提供了更多进阶能力:
dart
// lookupOrNull:区分已知设备和未知设备
final name = await OhosProductName().lookupOrNull('ALN-AL00');
if (name != null) {
print('已知设备: $name');
} else {
print('未知设备,映射表未收录');
}
lookupOrNull与lookup的区别在于:未找到映射时返回null而非原始machineId。这在需要区分"已知设备"和"未知设备"的场景中非常有用。
12.2 系列文章导航
本系列共30篇文章,推荐阅读路线:
| 阶段 | 篇章 | 主题 |
|---|---|---|
| 入门篇 | 第1-3篇 | 库简介、环境搭建、快速上手(本文) |
| API篇 | 第4-10篇 | OhosProductName类、各方法详解、异步处理 |
| 映射表篇 | 第11-15篇 | Mate/Pura/nova/MatePad/荣耀设备映射 |
| 源码篇 | 第16-22篇 | 插件架构、源码分析、MethodChannel机制 |
| 实战篇 | 第23-29篇 | 页面构建、反馈系统、统计分析、性能优化 |
| 生态篇 | 第30篇 | 源码贡献与生态共建 |
推荐阅读顺序:
- 先完成入门篇(第1-3篇)建立整体认知
- 再阅读API篇(第4-10篇)掌握所有方法用法
- 根据需要选读映射表篇、源码篇或实战篇
总结
通过本文的三步走 流程(添加依赖→安装依赖→调用API),你已经成功在OpenHarmony应用中集成了apple_product_name 库。整个过程非常简单:一行依赖配置、一条安装命令、一行API调用,即可获取设备的友好产品名称。该库提供的getProductName()、getMachineId()和lookup()三个核心方法覆盖了绝大多数使用场景,两级查找策略确保在任何设备上都能返回有意义的结果。
下一篇文章将深入介绍OhosProductName类的完整API和设计细节。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- OpenHarmony适配仓库:https://gitcode.com/oh-flutter/flutter_apple_product_name
- 开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
- 原始GitHub仓库:https://github.com/kyle-seongwoo-jun/flutter_apple_product_name
- Flutter OHOS仓库:https://gitee.com/openharmony-sig/flutter_flutter
- device_info_plus:https://pub.dev/packages/device_info_plus
- Flutter官方文档:https://flutter.dev
- OpenHarmony官方文档:https://www.openharmony.cn
- pub.dev包管理:https://pub.dev