1. 项目概述:当Flutter遇见OpenHarmony
作为一名同时接触过Flutter和OpenHarmony的开发者,当我看到这个项目标题时,立刻意识到它的独特价值。Flutter作为Google推出的跨平台UI框架,其"一次编写,多端运行"的特性早已被广泛验证。而OpenHarmony作为新兴的分布式操作系统,正在构建自己的生态体系。将两者结合开发轻量级记事本应用,本质上是在探索一种新的技术融合路径。
这个开源记事本App的核心模块——笔记编辑器,需要解决三个关键问题:首先是如何在OpenHarmony上运行Flutter框架,这涉及到框架适配和性能优化;其次是实现高效的文本编辑功能,包括基础CRUD操作、格式支持和数据持久化;最后是保持应用的轻量化,符合OpenHarmony对轻量级应用的要求标准。
从技术选型角度看,使用Flutter开发OpenHarmony应用有几个显著优势:
- 开发效率高:一套代码可以同时覆盖OpenHarmony和其他平台
- 性能表现好:Flutter的Skia渲染引擎能保证UI流畅度
- 生态丰富:可以直接使用pub.dev上的成熟插件
- 未来可扩展:便于后续增加iOS/Android等多端支持
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境搭建与项目初始化
2.1 OpenHarmony开发环境准备
在开始Flutter for OpenHarmony项目前,需要先配置好基础开发环境。我推荐使用Ubuntu 20.04或更高版本作为开发主机,因为OpenHarmony的编译工具链对Linux支持最完善。以下是关键步骤:
- 安装依赖工具:
bash复制sudo apt-get update && sudo apt-get install -y git python3.8 python3-pip
- 配置OpenHarmony的编译环境:
bash复制python3 -m pip install --user ohpm
export PATH=$PATH:~/.local/bin
- 获取OpenHarmony源码(以6.1 LTS版本为例):
bash复制repo init -u https://gitee.com/openharmony/manifest.git -b OpenHarmony-6.1-LTS --no-repo-verify
repo sync -c
注意:国内用户建议使用gitee镜像源,同步速度更快。整个过程可能需要1-2小时,取决于网络状况。
2.2 Flutter for OpenHarmony适配
目前Flutter对OpenHarmony的支持还处于社区驱动阶段,需要一些特殊配置:
- 首先安装Flutter SDK(建议3.19.0+版本):
bash复制git clone https://github.com/flutter/flutter.git -b stable
export PATH="$PATH:`pwd`/flutter/bin"
flutter doctor
- 添加OpenHarmony平台支持:
bash复制flutter pub global activate flutter_ohos
flutter create --platforms ohos my_note_app
- 配置oh-package.json(OpenHarmony特有的依赖声明文件):
json复制{
"name": "my_note_app",
"version": "1.0.0",
"dependencies": {
"@ohos/ace_engine": "^1.0.0"
}
}
常见问题排查:
- 如果遇到"initializing the flutter sdk"卡住的情况,尝试设置国内镜像:
bash复制export PUB_HOSTED_URL=https://pub.flutter-io.cn export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn - "flutter's main gradle plugin"错误通常是由于Gradle版本不兼容导致,建议使用Gradle 7.5+
3. 笔记编辑器核心功能实现
3.1 编辑器UI框架搭建
记事本App的核心是编辑器界面,我们采用Flutter的Material Design组件构建基础框架:
dart复制class EditorScreen extends StatefulWidget {
@override
_EditorScreenState createState() => _EditorScreenState();
}
class _EditorScreenState extends State<EditorScreen> {
final TextEditingController _controller = TextEditingController();
String _currentNote = '';
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('我的笔记'),
actions: [
IconButton(
icon: Icon(Icons.save),
onPressed: _saveNote,
),
],
),
body: Padding(
padding: EdgeInsets.all(16.0),
child: TextField(
controller: _controller,
maxLines: null,
keyboardType: TextInputType.multiline,
decoration: InputDecoration(
hintText: '开始记录你的想法...',
border: InputBorder.none,
),
style: TextStyle(fontSize: 18.0),
),
),
);
}
void _saveNote() async {
// 保存逻辑实现
}
}
这个基础框架已经包含了:
- 可滚动的多行文本输入区域
- 自动适应键盘弹出的布局
- 顶部工具栏和保存按钮
- 响应式状态管理
3.2 富文本编辑功能增强
基础的纯文本编辑器体验有限,我们需要增加一些富文本支持:
- 添加文本样式工具栏:
dart复制Widget _buildStyleToolbar() {
return Container(
height: 50,
color: Colors.grey[200],
child: Row(
children: [
IconButton(
icon: Icon(Icons.format_bold),
onPressed: () => _toggleStyle(TextStyle(fontWeight: FontWeight.bold)),
),
IconButton(
icon: Icon(Icons.format_italic),
onPressed: () => _toggleStyle(TextStyle(fontStyle: FontStyle.italic)),
),
// 更多样式按钮...
],
),
);
}
void _toggleStyle(TextStyle style) {
final text = _controller.text;
final selection = _controller.selection;
_controller.value = _controller.value.copyWith(
text: text,
selection: selection,
composing: TextRange.empty,
style: style.merge(_controller.style),
);
}
- 实现Markdown预览切换:
dart复制bool _isMarkdown = false;
void _toggleMarkdown() {
setState(() {
_isMarkdown = !_isMarkdown;
if (_isMarkdown) {
_renderMarkdown();
}
});
}
Future<void> _renderMarkdown() async {
final markdown = await flutterMarkdown.convert(_controller.text);
// 在预览窗口显示渲染结果
}
- 添加图片插入功能:
dart复制Future<void> _insertImage() async {
final image = await ImagePicker().pickImage(source: ImageSource.gallery);
if (image != null) {
final bytes = await image.readAsBytes();
final imageTag = '\n})\n';
_controller.text = _controller.text.insert(_controller.selection.start, imageTag);
}
}
4. 数据持久化与同步
4.1 本地存储方案选择
在OpenHarmony环境下,我们有几种数据存储选择:
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| Preferences | 轻量级,API简单 | 只支持基础数据类型 | 配置信息 |
| SQLite | 关系型查询能力强 | 需要ORM支持 | 结构化数据 |
| File | 灵活,无大小限制 | 需要手动管理 | 非结构化数据 |
对于笔记应用,我推荐使用SQLite+Preferences混合方案:
- SQLite存储笔记内容
- Preferences存储用户设置
4.2 实现跨平台数据层
使用floor作为SQLite ORM:
- 定义实体类:
dart复制@Entity(tableName: 'notes')
class Note {
@PrimaryKey(autoGenerate: true)
final int? id;
final String title;
final String content;
final DateTime createdAt;
final DateTime updatedAt;
Note({
this.id,
required this.title,
required this.content,
required this.createdAt,
required this.updatedAt,
});
}
- 创建DAO接口:
dart复制@dao
abstract class NoteDao {
@Query('SELECT * FROM notes ORDER BY updatedAt DESC')
Future<List<Note>> getAllNotes();
@insert
Future<void> insertNote(Note note);
@update
Future<void> updateNote(Note note);
@delete
Future<void> deleteNote(Note note);
}
- 初始化数据库:
dart复制final database = await $FloorAppDatabase
.databaseBuilder('app_database.db')
.build();
4.3 数据同步策略
考虑到OpenHarmony的分布式能力,我们可以实现设备间笔记同步:
- 定义同步协议:
dart复制class SyncPacket {
final String deviceId;
final List<Note> changes;
final DateTime syncTime;
// JSON序列化方法
Map<String, dynamic> toJson() {...}
factory SyncPacket.fromJson(Map<String, dynamic> json) {...}
}
- 实现冲突解决策略(采用最后修改优先):
dart复制void _resolveConflicts(List<Note> local, List<Note> remote) {
final merged = <Note>[];
final allNotes = {...local, ...remote};
allNotes.forEach((id, note) {
final localNote = local.firstWhere((n) => n.id == id, orElse: () => null);
final remoteNote = remote.firstWhere((n) => n.id == id, orElse: () => null);
if (localNote != null && remoteNote != null) {
merged.add(localNote.updatedAt.isAfter(remoteNote.updatedAt)
? localNote
: remoteNote);
} else {
merged.add(localNote ?? remoteNote);
}
});
return merged;
}
5. 性能优化与测试
5.1 渲染性能优化
在OpenHarmony上运行Flutter应用需要注意以下性能要点:
- 减少Widget重建范围:
dart复制// 错误做法:整个页面setState
// 正确做法:使用ValueNotifier局部更新
final _textNotifier = ValueNotifier<String>('');
@override
Widget build(BuildContext context) {
return ValueListenableBuilder(
valueListenable: _textNotifier,
builder: (context, value, child) {
return Text(value);
},
);
}
- 使用Isolate处理耗时操作:
dart复制Future<String> _heavyComputation(String input) async {
return await compute(_doHeavyWork, input);
}
static String _doHeavyWork(String input) {
// 在独立Isolate中执行
}
- 图片资源优化:
yaml复制# pubspec.yaml中声明资源压缩
flutter:
assets:
- assets/images/
uses-material-design: true
performance:
enable-image-optimization: true
5.2 OpenHarmony特有适配
- 屏幕方向锁定:
dart复制void _lockScreenOrientation() {
// 调用OpenHarmony原生能力
const MethodChannel('flutter/platform')
.invokeMethod('setPreferredOrientation', ['portrait']);
}
- 分布式能力集成:
dart复制Future<List<DeviceInfo>> _getAvailableDevices() async {
try {
final result = await MethodChannel('flutter/distributed')
.invokeMethod('getConnectedDevices');
return List<DeviceInfo>.from(
json.decode(result).map((x) => DeviceInfo.fromJson(x)));
} on PlatformException catch (e) {
print("Failed to get devices: ${e.message}");
return [];
}
}
- 功耗优化:
dart复制void _enablePowerSave() {
// 减少后台更新频率
_timer?.cancel();
_timer = Timer.periodic(Duration(minutes: 5), (_) => _syncData());
}
5.3 测试策略
完整的测试方案应该包括:
- 单元测试(测试业务逻辑):
dart复制void main() {
test('Note content trimming', () {
final note = Note(
id: 1,
title: ' Hello ',
content: ' World ',
createdAt: DateTime.now(),
updatedAt: DateTime.now(),
);
expect(note.title.trim(), 'Hello');
expect(note.content.trim(), 'World');
});
}
- Widget测试(测试UI组件):
dart复制testWidgets('Editor renders correctly', (tester) async {
await tester.pumpWidget(MaterialApp(home: EditorScreen()));
expect(find.byType(TextField), findsOneWidget);
await tester.enterText(find.byType(TextField), 'Test note');
expect(find.text('Test note'), findsOneWidget);
});
- 集成测试(测试完整流程):
dart复制void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Create and save note', (tester) async {
await tester.pumpWidget(MyApp());
await tester.tap(find.byIcon(Icons.add));
await tester.pumpAndSettle();
await tester.enterText(find.byType(TextField), 'New note');
await tester.tap(find.byIcon(Icons.save));
await tester.pumpAndSettle();
expect(find.text('New note'), findsOneWidget);
});
}
6. 项目构建与发布
6.1 OpenHarmony应用打包
- 配置签名信息:
json复制// oh-package.json
{
"release": {
"signingConfig": {
"storeFile": "my-release-key.keystore",
"storePassword": "password",
"keyAlias": "my-key-alias",
"keyPassword": "password"
}
}
}
- 构建HAP包:
bash复制flutter build ohos --release
- 生成App包:
bash复制ohos-build-tool --mode=release --target=default
6.2 应用商店发布
目前OpenHarmony应用可以发布到:
- 官方应用市场(需企业开发者账号)
- 第三方开源应用商店(如OpenHarmony开源社区商店)
- 直接分发HAP文件
发布前需要准备:
- 应用图标(多种分辨率)
- 截图和宣传图
- 应用描述和分类
- 隐私政策说明
6.3 持续集成方案
推荐使用GitHub Actions自动化构建:
yaml复制name: OpenHarmony CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Flutter
uses: subosito/flutter-action@v2
- name: Build OpenHarmony
run: |
flutter pub get
flutter build ohos
- name: Archive HAP
uses: actions/upload-artifact@v3
with:
name: my-note-app
path: build/ohos/release/*.hap
7. 项目扩展与进阶
7.1 多语言支持
- 添加arb文件:
json复制// app_en.arb
{
"@@locale": "en",
"appTitle": "My Notes",
"saveButton": "Save",
// ...
}
// app_zh.arb
{
"@@locale": "zh",
"appTitle": "我的笔记",
"saveButton": "保存",
// ...
}
- 配置本地化:
dart复制MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
Locale('en'),
Locale('zh'),
],
// ...
);
7.2 云同步功能
使用开源后端方案实现跨设备同步:
- 服务端选择:
- Supabase(开源Firebase替代)
- Appwrite(自托管后端)
- 直接使用REST API + 自建服务器
- 客户端实现:
dart复制class CloudSync {
final String _userId;
final Dio _dio = Dio();
Future<void> uploadNotes(List<Note> notes) async {
await _dio.post(
'https://api.example.com/sync',
data: {'userId': _userId, 'notes': notes},
);
}
Future<List<Note>> downloadNotes() async {
final response = await _dio.get(
'https://api.example.com/sync',
params: {'userId': _userId},
);
return List<Note>.from(
response.data.map((x) => Note.fromJson(x)));
}
}
7.3 插件系统设计
允许用户通过插件扩展编辑器功能:
- 定义插件接口:
dart复制abstract class EditorPlugin {
String get name;
Widget buildToolbarButton();
void onTextChanged(String text);
}
- 实现插件加载机制:
dart复制Future<void> _loadPlugins() async {
final pluginsDir = Directory('plugins');
final plugins = await pluginsDir.list().toList();
for (final plugin in plugins) {
final package = await Isolate.spawnUri(
plugin.uri,
[],
null,
);
_plugins.add(package as EditorPlugin);
}
}
- 示例插件实现(字数统计):
dart复制class WordCountPlugin implements EditorPlugin {
@override
String get name => 'Word Counter';
@override
Widget buildToolbarButton() {
return IconButton(
icon: Icon(Icons.countertops),
onPressed: _showWordCount,
);
}
void _showWordCount() {
// 显示字数统计对话框
}
@override
void onTextChanged(String text) {
// 实时更新统计
}
}
8. 开源项目管理
8.1 项目结构规范
推荐的项目目录结构:
code复制my_note_app/
├── android/ # Android平台代码
├── ios/ # iOS平台代码
├── ohos/ # OpenHarmony平台代码
├── lib/ # 主要Dart代码
│ ├── models/ # 数据模型
│ ├── services/ # 业务逻辑
│ ├── utils/ # 工具类
│ ├── widgets/ # 自定义组件
│ └── main.dart # 应用入口
├── test/ # 测试代码
├── plugins/ # 自定义插件
└── pubspec.yaml # 依赖配置
8.2 开源许可证选择
对于开源记事本项目,常见的许可证选择:
| 许可证 | 允许商用 | 要求署名 | 允许修改 | 要求开源 |
|---|---|---|---|---|
| MIT | 是 | 是 | 是 | 否 |
| Apache 2.0 | 是 | 是 | 是 | 否 |
| GPL 3.0 | 是 | 是 | 是 | 是 |
建议选择MIT许可证,对使用者限制最少:
- 在项目根目录添加LICENSE文件
- 在pubspec.yaml中声明:
yaml复制name: my_note_app
description: A lightweight note app for OpenHarmony
version: 1.0.0
license: MIT
8.3 社区协作规范
建立健康的开源社区需要:
- 清晰的贡献指南(CONTRIBUTING.md)
- Issue模板(bug报告、功能请求)
- Pull Request审查流程
- 行为准则(CODE_OF_CONDUCT.md)
- 定期发布计划
示例贡献指南要点:
- 提交PR前先创建Issue讨论
- 遵循现有代码风格
- 包含测试用例
- 更新相关文档
- 签署CLA(贡献者许可协议)
9. 实际开发中的经验分享
在完成这个Flutter for OpenHarmony记事本项目的过程中,我积累了一些值得分享的经验:
-
混合开发策略:对于OpenHarmony特有的功能(如分布式能力),最佳实践是通过MethodChannel调用原生能力,而不是尝试用纯Flutter实现。这既保证了功能完整性,又避免了不必要的兼容层开发。
-
状态管理选择:经过对比测试,在OpenHarmony环境下,Riverpod相比Bloc有更好的性能表现,特别是在频繁更新UI的场景下。这可能与OpenHarmony的JS引擎优化有关。
-
字体渲染优化:OpenHarmony的字体渲染与Android略有不同,需要特别注意:
- 明确指定中文字体(如使用'NotoSansSC')
- 适当增加行高(建议1.5倍字体大小)
- 避免使用过小的字体尺寸(最小建议14sp)
-
键盘兼容性问题:不同OpenHarmony设备上的输入法表现不一致,解决方案:
dart复制TextField( keyboardAppearance: Brightness.light, // 强制亮色键盘 inputFormatters: [ FilteringTextInputFormatter.singleLineFormatter, // 避免多行冲突 ], ) -
性能监控工具:推荐使用OpenHarmony的HiDumper工具分析应用性能:
bash复制
hidumper -s 你的应用包名 -a performance -
内存管理技巧:OpenHarmony对内存使用更为严格,需要注意:
- 及时释放不再使用的图片资源
- 对大文本内容进行分块加载
- 避免在build方法中创建大量临时对象
-
调试技巧:当遇到难以定位的问题时,可以:
- 使用
ohos_logger包输出详细日志 - 通过ADB连接设备查看系统日志
- 在真机上使用OpenHarmony的DevEco Studio调试工具
- 使用
-
跨平台代码组织:建议将平台相关代码明确分离:
code复制lib/ ├── platform/ │ ├── android/ │ ├── ios/ │ └── ohos/ └── shared/ # 共用代码通过条件导入实现平台适配:
dart复制import 'package:flutter/foundation.dart' show defaultTargetPlatform; import 'package:flutter/material.dart' show TargetPlatform; String getPlatformName() { if (defaultTargetPlatform == TargetPlatform.android) { return 'Android'; } else if (defaultTargetPlatform == TargetPlatform.iOS) { return 'iOS'; } else { return 'OpenHarmony'; } }
这个项目最让我惊喜的是Flutter在OpenHarmony上的运行效率。经过适当优化后,UI流畅度甚至可以超过部分原生开发的应用。特别是在使用Skia硬件加速的场景下,滚动列表和富文本渲染的表现非常出色。
