三亩地 三亩地SAN MU DI · CODE DIARY
ARTICLE DETAIL

日记详情

真实记录编程学习的某一天,欢迎挑你感兴趣的翻一翻。

Flutter在OpenHarmony上的购物清单应用开发实践

Flutter在OpenHarmony上的购物清单应用开发实践

1. 项目背景与需求分析

Flutter作为Google推出的跨平台UI框架,在移动端开发领域已经积累了丰富的生态和开发者社区。而OpenHarmony作为国产开源操作系统,正在构建自己的应用生态。将Flutter应用于OpenHarmony平台,是一个极具探索价值的技术方向。

这次我们要实现的是一个衣橱管家App中的购物清单功能。这个功能看似简单,但实际上需要考虑以下几个核心需求:

  1. 数据持久化:购物清单需要能够保存用户的添加记录,即使App重启也不会丢失
  2. 多设备同步:考虑到用户可能有多台设备,数据需要在不同设备间保持同步
  3. UI适配:需要完美适配OpenHarmony系统的UI风格和交互习惯
  4. 性能优化:在资源受限的设备上也能流畅运行

2. 环境搭建与项目初始化

2.1 Flutter for OpenHarmony环境配置

要在OpenHarmony上运行Flutter应用,我们需要先搭建开发环境:

  1. 安装Flutter SDK(建议使用3.44或更高版本)
  2. 配置OpenHarmony开发环境(需要安装DevEco Studio)
  3. 安装Flutter for OpenHarmony的适配层
# 安装Flutter SDK git clone https://github.com/flutter/flutter.git -b stable export PATH="$PATH:`pwd`/flutter/bin" # 验证安装 flutter doctor

注意:如果遇到"flutter环境设置之后cmd闪退"的问题,可能是环境变量配置不正确导致的。建议检查PATH设置,并确保没有中文路径。

2.2 创建Flutter项目

使用以下命令创建一个新的Flutter项目:

flutter create wardrobe_assistant cd wardrobe_assistant

然后我们需要添加OpenHarmony的支持:

  1. 在项目根目录下创建ohos文件夹
  2. 配置OpenHarmony的config.json文件
  3. 添加必要的原生能力声明

3. 购物清单功能实现

3.1 数据模型设计

购物清单的核心数据结构可以设计为:

class ShoppingItem { final String id; String name; int quantity; bool purchased; DateTime createdAt; ShoppingItem({ required this.id, required this.name, this.quantity = 1, this.purchased = false, DateTime? createdAt, }) : createdAt = createdAt ?? DateTime.now(); }

3.2 状态管理方案选择

对于状态管理,我们有以下几种选择:

  1. Provider:轻量级,适合中小型应用
  2. Riverpod:Provider的升级版,更灵活
  3. Bloc:适合复杂业务逻辑
  4. GetX:功能全面但学习曲线较陡

考虑到我们的应用规模,选择Provider作为状态管理方案是最合适的:

class ShoppingListProvider with ChangeNotifier { final List<ShoppingItem> _items = []; List<ShoppingItem> get items => _items; void addItem(ShoppingItem item) { _items.add(item); notifyListeners(); } void togglePurchase(String id) { final index = _items.indexWhere((item) => item.id == id); if (index != -1) { _items[index].purchased = !_items[index].purchased; notifyListeners(); } } }

3.3 UI界面实现

购物清单的UI可以分为以下几个部分:

  1. 添加新项目:顶部有一个输入框和添加按钮
  2. 清单列表:显示所有购物项目
  3. 项目操作:每个项目可以有勾选、编辑、删除等操作
class ShoppingListScreen extends StatelessWidget { final TextEditingController _controller = TextEditingController(); @override Widget build(BuildContext context) { final provider = Provider.of<ShoppingListProvider>(context); return Scaffold( appBar: AppBar( title: Text('购物清单'), ), body: Column( children: [ Padding( padding: const EdgeInsets.all(8.0), child: Row( children: [ Expanded( child: TextField( controller: _controller, decoration: InputDecoration( hintText: '输入要购买的商品', border: OutlineInputBorder(), ), ), ), IconButton( icon: Icon(Icons.add), onPressed: () { if (_controller.text.isNotEmpty) { provider.addItem(ShoppingItem( id: Uuid().v4(), name: _controller.text, )); _controller.clear(); } }, ), ], ), ), Expanded( child: ListView.builder( itemCount: provider.items.length, itemBuilder: (context, index) { final item = provider.items[index]; return ListTile( leading: Checkbox( value: item.purchased, onChanged: (_) => provider.togglePurchase(item.id), ), title: Text(item.name), subtitle: Text('数量: ${item.quantity}'), trailing: IconButton( icon: Icon(Icons.delete), onPressed: () => provider.removeItem(item.id), ), ); }, ), ), ], ), ); } }

4. 数据持久化与同步

4.1 本地存储方案

在OpenHarmony上,我们有几种数据持久化方案:

  1. SharedPreferences:适合存储简单键值对
  2. Hive:轻量级NoSQL数据库,性能优异
  3. SQLite:关系型数据库,适合复杂查询
  4. 文件存储:直接读写文件

对于购物清单这种结构化但不复杂的数据,Hive是最佳选择:

void main() async { await Hive.initFlutter(); Hive.registerAdapter(ShoppingItemAdapter()); await Hive.openBox<ShoppingItem>('shopping_items'); runApp(MyApp()); } class ShoppingListProvider with ChangeNotifier { final Box<ShoppingItem> _box; ShoppingListProvider(this._box); List<ShoppingItem> get items => _box.values.toList(); Future<void> addItem(ShoppingItem item) async { await _box.put(item.id, item); notifyListeners(); } Future<void> togglePurchase(String id) async { final item = _box.get(id); if (item != null) { item.purchased = !item.purchased; await _box.put(id, item); notifyListeners(); } } }

4.2 多设备同步实现

要实现多设备同步,我们可以使用OpenHarmony的分布式能力:

  1. config.json中声明分布式权限
  2. 使用@ohos.distributedData模块实现数据同步
  3. 处理冲突解决策略
// 在原生侧实现数据同步 // ohos/src/main/ets/MainAbility/pages/index.ets import distributedData from '@ohos.distributedData'; const STORE_ID = 'wardrobe_shopping_list'; const KEY_SYNC = 'shopping_items_sync'; // 初始化KVManager let kvManager; distributedData.createKVManager({ bundleName: 'com.example.wardrobe', options: { kvStoreType: distributedData.KVStoreType.SINGLE_VERSION, securityLevel: distributedData.SecurityLevel.S1, }, }, (err, manager) => { kvManager = manager; // 获取KVStore kvManager.getKVStore(STORE_ID, (err, kvStore) => { if (err) { console.error(`Failed to get KVStore. Code:${err.code},message:${err.message}`); return; } // 监听数据变化 kvStore.on('dataChange', distributedData.SubscribeType.SUBSCRIBE_TYPE_ALL, (data) => { // 处理同步数据 const items = JSON.parse(data.value); // 更新Flutter侧数据 Channel.send('syncData', items); }); }); }); // 提供给Flutter调用的同步方法 function syncShoppingItems(items) { kvManager.getKVStore(STORE_ID, (err, kvStore) => { if (err) return; // 将数据同步到分布式数据库 kvStore.put(KEY_SYNC, JSON.stringify(items), (err) => { if (err) { console.error(`Failed to sync data. Code:${err.code},message:${err.message}`); } }); }); }

5. 性能优化与测试

5.1 列表性能优化

购物清单可能会包含大量项目,我们需要优化列表性能:

  1. 使用ListView.builder而不是ListViewColumn
  2. 为列表项添加const构造函数
  3. 使用AutomaticKeepAliveClientMixin保持滚动位置
  4. 实现分页加载
class ShoppingListItem extends StatelessWidget { const ShoppingListItem({ Key? key, required this.item, required this.onToggle, required this.onDelete, }) : super(key: key); final ShoppingItem item; final VoidCallback onToggle; final VoidCallback onDelete; @override Widget build(BuildContext context) { return ListTile( leading: Checkbox( value: item.purchased, onChanged: (_) => onToggle(), ), title: Text(item.name), subtitle: Text('数量: ${item.quantity}'), trailing: IconButton( icon: const Icon(Icons.delete), onPressed: onDelete, ), ); } }

5.2 内存管理

在资源受限的设备上,内存管理尤为重要:

  1. 避免在build方法中创建大量对象
  2. 使用const修饰符尽可能多的Widget
  3. 及时释放不再需要的资源
  4. 使用Image.assetcacheWidthcacheHeight参数控制图片内存占用

5.3 测试策略

完整的测试应该包括:

  1. 单元测试:测试业务逻辑和数据模型
  2. Widget测试:测试UI组件
  3. 集成测试:测试完整功能流程
  4. 性能测试:确保应用流畅运行
void main() { test('Adding item increases list length', () { final provider = ShoppingListProvider(MockBox()); expect(provider.items.length, 0); provider.addItem(ShoppingItem(id: '1', name: 'Test')); expect(provider.items.length, 1); }); testWidgets('ShoppingListScreen displays items', (tester) async { final provider = ShoppingListProvider(MockBox()); provider.addItem(ShoppingItem(id: '1', name: 'Test Item')); await tester.pumpWidget( MaterialApp( home: ChangeNotifierProvider.value( value: provider, child: ShoppingListScreen(), ), ), ); expect(find.text('Test Item'), findsOneWidget); }); }

6. 打包与发布

6.1 打包为OpenHarmony应用

要将Flutter应用打包为OpenHarmony应用,需要以下步骤:

  1. 配置build.gradle文件,添加OpenHarmony构建支持
  2. 运行flutter build ohos命令
  3. 生成的HAP包位于build/ohos/outputs目录

提示:如果遇到"you are applying flutter's main gradle plugin imperatively using the apply s"警告,可以更新Gradle插件版本或按照提示修改构建配置。

6.2 应用签名

发布到应用市场前需要对应用进行签名:

  1. 生成签名证书
  2. 配置签名信息
  3. 使用签名工具对HAP包进行签名

6.3 发布到应用市场

OpenHarmony应用可以发布到:

  1. 华为应用市场
  2. 其他支持OpenHarmony的应用商店
  3. 企业自有分发渠道

发布前需要准备:

  1. 应用图标和截图
  2. 应用描述和功能介绍
  3. 隐私政策说明
  4. 必要的资质证明

7. 常见问题与解决方案

7.1 Flutter与OpenHarmony的兼容性问题

  1. 问题:某些Flutter插件在OpenHarmony上不可用

    • 解决方案:寻找替代插件或自行实现原生功能
  2. 问题:UI渲染不一致

    • 解决方案:使用OpenHarmony的主题适配器,或自定义Widget以匹配系统风格

7.2 数据同步问题

  1. 问题:同步延迟或失败

    • 解决方案:实现重试机制,添加本地缓存,提供手动同步按钮
  2. 问题:冲突解决

    • 解决方案:使用时间戳或版本号实现最后修改优先的策略

7.3 性能问题

  1. 问题:列表滚动卡顿

    • 解决方案:优化列表项Widget,减少重建,使用RepaintBoundary
  2. 问题:启动时间过长

    • 解决方案:延迟加载非必要资源,使用SplashScreen

在实际开发中,我发现Flutter for OpenHarmony的集成已经相当成熟,但仍有几个需要注意的地方:首先是分布式能力的调用需要通过原生桥接实现,其次是某些系统级功能可能需要等待Flutter插件的适配。对于购物清单这类功能,核心难点不在于功能实现本身,而在于如何充分利用OpenHarmony的分布式特性提供无缝的多设备体验。

← 返回列表