1. 项目背景与核心价值
最近在技术社区看到一个很有意思的讨论:如何用Flutter开发一个能同时运行在鸿蒙6.0和Android API 20+设备上的待办事项应用。作为一个长期关注跨平台开发的工程师,我决定亲自尝试这个挑战,并记录下完整的过程。
这个项目的核心价值在于验证Flutter在鸿蒙新版本上的兼容性表现。鸿蒙6.0带来了许多底层架构的更新,而Android API 20(对应Android 4.4W)则是相对较旧的系统版本。通过这个项目,我们不仅能验证Flutter的跨端能力,还能探索在差异较大的系统环境下保持功能一致的解决方案。
2. 环境准备与工具链配置
2.1 Flutter SDK适配方案
首先需要特别注意的是Flutter版本选择。经过实测,Flutter 3.13.0版本在鸿蒙6.0上表现最为稳定。安装时建议使用以下命令指定版本:
bash复制flutter version 3.13.0
对于国内开发者,还需要配置镜像源以加速依赖下载:
bash复制export PUB_HOSTED_URL=https://pub.flutter-io.cn
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn
2.2 鸿蒙开发环境搭建
鸿蒙6.0的开发需要安装DevEco Studio 3.1及以上版本。安装完成后,需要额外配置鸿蒙的SDK路径:
- 下载HarmonyOS SDK
- 在DevEco Studio中配置SDK路径
- 安装API 6对应的工具链
注意:鸿蒙6.0的模拟器需要开启VT-x虚拟化支持,在BIOS中确保已启用该功能。
2.3 多平台调试环境
建议同时准备以下测试设备:
- 搭载鸿蒙6.0的真机(如华为Mate 60系列)
- Android 4.4W的模拟器(可通过Android Studio创建)
- 可选:iOS设备用于验证Flutter的跨平台一致性
3. 项目架构设计
3.1 整体架构方案
采用经典的Flutter分层架构:
code复制lib/
├── models/ # 数据模型
├── services/ # 业务逻辑
├── repositories/ # 数据持久化
├── widgets/ # 公共组件
└── views/ # 页面UI
3.2 核心依赖库选型
针对待办事项应用的特点,我们选择以下关键依赖库:
| 功能需求 | 库名称 | 版本 | 跨平台兼容性说明 |
|---|---|---|---|
| 状态管理 | provider | 6.0.5 | 全平台兼容 |
| 本地存储 | shared_preferences | 2.2.1 | 需鸿蒙适配 |
| 日期时间选择 | flutter_datetime_picker | 1.5.1 | 需样式调整 |
| 网络请求 | dio | 5.3.3 | 全平台兼容 |
3.3 鸿蒙特定适配方案
在android/app/build.gradle中需要添加鸿蒙的兼容配置:
groovy复制android {
defaultConfig {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
}
对于鸿蒙特有的功能调用,我们创建了一个平台通道:
dart复制const platform = MethodChannel('com.example.todo/harmony');
Future<void> _callHarmonyFeature() async {
try {
await platform.invokeMethod('harmonyFeature');
} on PlatformException catch (e) {
print("调用鸿蒙功能失败: ${e.message}");
}
}
4. 核心功能实现细节
4.1 待办事项数据模型
设计一个兼顾灵活性和性能的数据结构:
dart复制class TodoItem {
final String id;
String title;
String description;
DateTime dueDate;
bool isCompleted;
Priority priority;
// 支持JSON序列化
Map<String, dynamic> toJson() {
return {
'id': id,
'title': title,
'description': description,
'dueDate': dueDate.toIso8601String(),
'isCompleted': isCompleted,
'priority': priority.index,
};
}
// 反序列化工厂方法
factory TodoItem.fromJson(Map<String, dynamic> json) {
return TodoItem(
id: json['id'],
title: json['title'],
description: json['description'],
dueDate: DateTime.parse(json['dueDate']),
isCompleted: json['isCompleted'],
priority: Priority.values[json['priority']],
);
}
}
4.2 跨平台存储解决方案
由于鸿蒙和Android的存储机制存在差异,我们实现了统一的存储接口:
dart复制abstract class TodoStorage {
Future<List<TodoItem>> loadTodos();
Future<void> saveTodos(List<TodoItem> todos);
}
// Android/鸿蒙实现
class SharedPrefsStorage implements TodoStorage {
@override
Future<List<TodoItem>> loadTodos() async {
final prefs = await SharedPreferences.getInstance();
final jsonString = prefs.getString('todos') ?? '[]';
final jsonList = jsonDecode(jsonString) as List;
return jsonList.map((e) => TodoItem.fromJson(e)).toList();
}
@override
Future<void> saveTodos(List<TodoItem> todos) async {
final prefs = await SharedPreferences.getInstance();
final jsonList = todos.map((e) => e.toJson()).toList();
await prefs.setString('todos', jsonEncode(jsonList));
}
}
4.3 任务列表性能优化
针对可能的大量待办事项,我们采用ListView.builder配合AutomaticKeepAliveClientMixin:
dart复制class TodoList extends StatefulWidget {
@override
_TodoListState createState() => _TodoListState();
}
class _TodoListState extends State<TodoList> with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;
@override
Widget build(BuildContext context) {
super.build(context);
return Consumer<TodoModel>(
builder: (context, model, child) {
return ListView.builder(
itemCount: model.todos.length,
itemBuilder: (context, index) {
final todo = model.todos[index];
return TodoItemCard(
todo: todo,
onToggle: (value) => model.toggleComplete(todo.id),
);
},
);
},
);
}
}
5. 鸿蒙特定功能适配
5.1 卡片服务集成
鸿蒙的卡片服务是其特色功能,我们通过平台通道实现:
java复制// 鸿蒙侧代码
public class TodoCardProvider extends FormRemoteView {
@Override
public ComponentProvider onCreateComponentProvider(Intent intent) {
ComponentProvider componentProvider = new ComponentProvider();
// 构建卡片UI
componentProvider.setIntentAgent(createIntentAgent());
return componentProvider;
}
private IntentAgent createIntentAgent() {
Intent intent = new Intent();
Operation operation = new Intent.OperationBuilder()
.withBundleName(getBundleName())
.withAbilityName(getAbilityName())
.build();
intent.setOperation(operation);
IntentAgent agent = IntentAgentHelper.getIntentAgent(
getContext(),
IntentAgentConstant.OperationType.START_ABILITY,
Collections.singletonList(operation),
null,
null);
return agent;
}
}
5.2 分布式能力调用
鸿蒙的分布式能力允许设备间协作,我们实现了一个简单的任务共享功能:
dart复制Future<void> shareTodoWithOtherDevice(TodoItem todo) async {
try {
final result = await platform.invokeMethod('distributeTodo', {
'id': todo.id,
'title': todo.title,
'description': todo.description,
'dueDate': todo.dueDate.toIso8601String(),
});
debugPrint('分发结果: $result');
} on PlatformException catch (e) {
debugPrint('分发失败: ${e.message}');
}
}
6. 兼容性处理与问题排查
6.1 常见兼容性问题解决方案
在开发过程中遇到的典型问题及解决方法:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 鸿蒙设备上UI渲染异常 | Skia引擎兼容性问题 | 在main.dart中强制使用CanvasKit:renderer: RendererOption.canvaskit |
| Android 4.4上应用崩溃 | 旧版Android不支持某些API | 在build.gradle中设置minSdkVersion 20 |
| 鸿蒙设备无法保存数据 | 权限未正确声明 | 在config.json中添加"reqPermissions": [{"name": "ohos.permission.WRITE_USER_STORAGE"}] |
| 日期选择器在鸿蒙上显示异常 | 时区处理差异 | 使用intl包统一日期格式,避免直接使用DateTime.parse |
6.2 性能优化技巧
-
列表滚动优化:
- 使用
const构造函数创建无状态组件 - 为列表项设置
key属性 - 避免在
itemBuilder中进行复杂计算
- 使用
-
内存管理:
dart复制// 在StatefulWidget中重写dispose方法 @override void dispose() { _controller.dispose(); _focusNode.dispose(); super.dispose(); } -
跨平台渲染优化:
dart复制// 在main.dart中根据平台调整渲染参数 void main() { WidgetsFlutterBinding.ensureInitialized(); if (Platform.isHarmony) { debugPrint('鸿蒙设备优化初始化...'); // 鸿蒙特定优化 } runApp(MyApp()); }
7. 测试与发布策略
7.1 多平台测试方案
建议的测试矩阵:
| 测试类型 | Android 4.4W | 鸿蒙6.0 | 测试要点 |
|---|---|---|---|
| 核心功能测试 | ✓ | ✓ | 添加/删除/完成待办事项 |
| 性能测试 | ✓ | ✓ | 列表滚动流畅度,内存占用 |
| 兼容性测试 | ✓ | ✓ | 不同屏幕尺寸,字体大小调整 |
| 持久化测试 | ✓ | ✓ | 应用重启后数据恢复 |
| 分布式功能测试 | ✗ | ✓ | 鸿蒙设备间任务共享 |
7.2 发布准备
对于鸿蒙平台:
- 生成HAP包:
bash ./gradlew assembleRelease - 在AppGallery Connect创建应用
- 准备鸿蒙特有的应用截图和描述
对于Android平台:
- 生成APK:
flutter build apk --release - 注意兼容旧版Android的ProGuard配置:
gradle复制android { buildTypes { release { minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } }
8. 项目总结与扩展建议
经过这个项目的实践,我总结了几个关键点:
-
鸿蒙适配要点:
- 尽早获取鸿蒙真机进行测试
- 关注鸿蒙特有的权限系统
- 利用好鸿蒙的分布式能力可以创造独特体验
-
低版本Android兼容技巧:
- 避免使用新版Java API
- 测试所有的异步操作
- 简化动画效果
-
后续扩展方向:
- 添加云同步功能
- 实现更丰富的提醒方式
- 开发鸿蒙原子化服务
这个项目最让我惊喜的是Flutter在鸿蒙6.0上的流畅表现,虽然遇到了一些兼容性问题,但都有合理的解决方案。对于想要尝试跨鸿蒙和Android开发的团队,Flutter确实是一个值得考虑的选择。
