去年夏天我在开发一款生活助手类App时,遇到了一个有趣的挑战:需要在OpenHarmony平台上实现一个跨平台的日记本功能。当时市面上关于Flutter在OpenHarmony上的实践案例还很少,这促使我决定记录下整个开发过程。
选择Flutter作为开发框架主要基于三个考虑:
OpenHarmony作为新兴的分布式操作系统,其与Flutter的结合在当时(2023年Q2)还属于比较前沿的技术尝试。官方提供的flutter_ohos插件版本是1.0.0-beta,这给开发带来了一些不确定性。
首先需要准备以下环境:
配置步骤:
bash复制flutter pub global activate flutter_ohos
flutter create --template=app --platforms=ohos my_diary_app
yaml复制dependencies:
flutter_ohos: ^1.0.0-beta
path_provider_ohos: ^0.1.0
注意:OpenHarmony的存储路径访问权限需要单独配置,在config.json中添加:
json复制"reqPermissions": [ { "name": "ohos.permission.READ_USER_STORAGE" }, { "name": "ohos.permission.WRITE_USER_STORAGE" } ]
在实际搭建过程中,我遇到了几个典型问题:
Flutter版本冲突:
现象:运行flutter doctor时提示ohos工具链不兼容
解决:需要锁定Flutter版本为3.10.x系列
模拟器连接失败:
建议使用真机调试,OpenHarmony模拟器对Flutter支持还不完善
热重载不生效:
需要在DevEco Studio中手动开启调试端口转发
日记本的核心数据结构设计如下:
dart复制class DiaryEntry {
final String id;
final String title;
final String content;
final DateTime date;
final List<String> tags;
final String mood; // 心情图标
final List<String> images; // 图片路径列表
// 构造方法、toJson/fromJson等
}
考虑到OpenHarmony的文件系统特性,我们选择使用Hive作为本地数据库:
dart复制void initHive() async {
final dir = await getApplicationDocumentsDirectory();
Hive.init(dir.path);
Hive.registerAdapter(DiaryEntryAdapter());
await Hive.openBox<DiaryEntry>('diaries');
}
主界面采用CustomScrollView实现瀑布流布局:
dart复制SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
return DiaryCard(
diary: diaries[index],
onTap: () => _openDetail(diaries[index]),
);
},
childCount: diaries.length,
),
)
日记编辑页使用了RichText编辑器插件:
dart复制FlutterQuill(
controller: _controller,
focusNode: _focusNode,
scrollController: ScrollController(),
scrollable: true,
padding: EdgeInsets.zero,
autoFocus: false,
readOnly: false,
placeholder: '写下今天的点滴...',
expands: true,
)
采用自定义Painter实现动态心情选择组件:
dart复制CustomPaint(
painter: MoodPainter(
selectedMood: currentMood,
onSelect: (mood) => setState(() => currentMood = mood),
),
)
OpenHarmony的图片选择需要特殊处理:
dart复制final picker = ImagePickerOhos();
final List<AssetEntity>? assets = await picker.pickAssets(
maxAssets: 5,
requestType: RequestType.image,
);
图片压缩使用flutter_image_compress插件,需要针对OHOS调整参数:
dart复制FlutterImageCompress.compressAndGetFile(
file.absolute.path,
targetPath,
quality: 85, // OHOS上建议不超过90
minWidth: 1080,
minHeight: 1080,
)
后台服务保活:
在ability_main.xml中添加:
xml复制<backgroundModes>
<mode name="dataTransfer"/>
</backgroundModes>
分布式能力调用:
dart复制try {
final result = await FlutterOhos.callDistributedService(
deviceId: targetDeviceId,
serviceName: 'diarySync',
method: 'syncLatest',
parameters: {'lastSync': lastSyncTime},
);
} on PlatformException catch (e) {
// 错误处理
}
列表性能优化:
dart复制SliverAnimatedList(
initialItemCount: diaries.length,
itemBuilder: (context, index, animation) {
return SizeTransition(
sizeFactor: animation,
child: DiaryItem(diary: diaries[index]),
);
},
)
图片缓存策略:
dart复制CachedNetworkImage(
imageUrl: imageUrl,
fit: BoxFit.cover,
placeholder: (context, url) => ShimmerEffect(),
errorWidget: (context, url, error) => Icon(Icons.error),
cacheManager: CacheManager(
Config(
'diaryImages',
maxNrOfCacheObjects: 100,
stalePeriod: Duration(days: 7),
),
),
)
针对OHOS平台的测试需要特别注意:
dart复制testWidgets('Diary CRUD测试', (tester) async {
await tester.pumpWidget(OhosAppWrapper(DiaryApp()));
// 测试新建日记
await tester.tap(find.byIcon(Icons.add));
await tester.pumpAndSettle();
// 测试输入
await tester.enterText(find.byType(TextField).first, '测试标题');
await tester.pump();
// 验证结果
expect(find.text('测试标题'), findsOneWidget);
});
日志收集:
dart复制void initLogger() {
Logger.init(
printer: OhosPrinter(), // 自定义OHOS日志输出
level: Level.debug,
);
}
性能分析:
使用OHOS的hiTrace工具:
bash复制hitrace --trace_async_start -t 5
在build.gradle中添加:
gradle复制ohos {
signingConfigs {
release {
storeFile file('my-release-key.jks')
storePassword 'password'
keyAlias 'my-alias'
keyPassword 'password'
signAlg 'SHA256withECDSA'
profile file('ohosRelease.p7b')
certpath file('ohosRelease.cer')
}
}
}
需要注意OHOS应用市场的特殊要求:
经过两个月的开发和调优,这个日记本功能最终在OHOS平台上实现了以下指标:
几个关键收获:
如果重新做这个项目,我会在以下方面改进: