# 鸿蒙适配方案 > 文档创建: 2026-04-09 | 最后更新: 2026-04-25 > 适配策略: 纯 Dart 包零成本适配 + 原生插件完整适配 > ⚠️ 重要教训: 纯Dart包禁止添加ohos目录,会导致启动闪退(9001005) --- ## 一、纯 Dart 包 vs 原生插件判断 | 检查项 | 纯 Dart 包 | 原生插件 | |--------|-----------|---------| | `android/` `ios/` 目录 | ❌ 无 | ✅ 有 | | `flutter.plugin` 声明 | ❌ 无 | ✅ 有 | | MethodChannel / FFI | ❌ 无 | ✅ 有 | | 适配方式 | **仅改版本号,无ohos目录!** | ets 原生实现 + har 包 | | 工作量 | 1min | 1-3 天 | ### 快速判断流程 ``` 新包是否包含原生代码? ├── 否(纯 Dart)→ ✅ 零适配:仅改版本号即可! │ ⛔ 禁止创建 ohos 目录!会导致 Invalid relative path (9001005) 启动闪退 │ Flutter引擎启动时会扫描所有 ohos 模块并 copyResource, │ 空壳模块引用不存在的 libs/flutter.har → 直接崩溃 │ └── 是(有原生代码) ├── MethodChannel → 需 ets 实现 + DevEco Studio 打 har └── FFI → 需编译鸿蒙版 .so + CMakeLists ``` ### ⛔ 血泪教训 (2026-04-25) 2026-04-25 因给9个纯Dart包创建了空壳ohos目录,导致鸿蒙端持续闪退: - 错误码 `9001005` (Invalid relative path) - 堆栈 `copyResource → startInitialization → onCreate` - 根因:空壳 `oh-package.json5` 引用不存在的 `libs/flutter.har` - **修复**: 删除全部9个纯Dart包的 ohos 目录 - **结论**: 纯Dart包 = 不需要任何ohos文件! --- ## 二、纯 Dart 包适配步骤(正确做法) ### 2.1 拉取源码 ```bash cd packages git clone --depth 1 --branch ``` ### 2.2 修改版本号 `pubspec.yaml` 中 `version: x.x.x` → `x.x.x-ohos.1` ### 2.3 项目引用 & 验证 ```yaml # pubspec.yaml dependencies: : path: packages/ ``` ```bash flutter pub get && flutter analyze --no-pub ``` ### ✅ 完成! > **就这么简单!** 纯Dart代码跨平台编译,不需要任何原生适配。 > 不要创建 ohos/ 目录、不要写 Plugin.ets、不要配置 module.json5。 --- ## 三、原生插件适配流程(参考) 详见 [ohos平台适配flutter三方库指导.md](./ohos平台适配flutter三方库指导.md) ``` 1. flutter create --platforms ohos _ohos 2. 复制 android 版 lib dart 代码,android → ohos 3. DevEco Studio 编写 ets 原生代码(参考 android/ios) 4. pubspec.yaml 添加 flutter.plugin.platforms.ohos 5. DevEco Studio → Build → Make Module 打 har 包 6. flutter create --platforms ohos example 验证 ``` --- ## 四、Web 兼容性问题备忘 项目 Web 白屏与各适配包无关,是项目本身依赖问题: | 问题依赖 | 原因 | 修复方案 | |----------|------|---------| | `dart:io` (logger_service) | Web 不支持 | 条件导入或 kIsWeb 检查 | | `path_provider` (git版) | 可能无 web 实现 | 跳过初始化 | | `permission_handler` | Web 不支持原生权限 | stub 或跳过 | | `fluttertoast` (本地) | 可能无 web 实现 | SnackBar 替代 | --- ## 五、已适配包清单 ### 5.1 总览表 | # | 包名 | 类型 | 原版本 | 适配版本 | ohos目录 | 日期 | |---|------|------|--------|---------|---------|------| | 1 | fl_chart | 🟢 纯Dart | 1.2.0 | 1.2.0-ohos.1 | ❌ 无需 | 2026-04-09 | | 2 | badges | 🟢 纯Dart | 3.2.0 | 3.2.0-ohos.1 | ❌ 无需 | 2026-04-10 | | 3 | flutter_staggered_grid_view | 🟢 纯Dart | 0.7.0 | 0.7.0-ohos.1 | ❌ 无需 | 2026-04-12 | | 4 | cached_network_image | 🟢 纯Dart | 3.4.1 | 3.4.1-ohos.1 | ❌ 无需 | 2026-04-12 | | 5 | flutter_markdown_plus | 🟢 纯Dart | 1.0.7 | 1.0.7-ohos.1 | ❌ 无需 | 2026-04-14 | | 6 | flutter_card_swiper | 🟢 纯Dart | 7.2.0 | 7.2.0-ohos.1 | ❌ 无需 | 2026-04-14 | | 7 | qr | 🟢 纯Dart | 3.0.2 | 3.0.2-ohos.1 | ❌ 无需 | 2026-04-19 | | 8 | mailer | 🟢 纯Dart | 7.1.0 | 7.1.0-ohos.1 | ❌ 无需 | 2026-04-19 | | 9 | docs_gee | 🟢 纯Dart | 1.3.2 | 1.3.2-ohos.1 | ❌ 无需 | 2026-04-24 | | 10 | **pdf** | 🟢 纯Dart | 3.12.0 | 3.12.0-ohos.1 | ❌ 无需 | 2026-04-25 | | 11 | mobile_scanner | 🔴 原生插件 | 7.2.0 | 7.2.0+ohos | ✅ 有ets实现 | 2026-04-22 | | 12 | file_picker | 🔴 原生插件 | - | 1.0.1 | ✅ 有ets实现 | 已适配 | | 13 | fluttertoast_ohos | 🔴 原生插件 | - | 1.0.0 | ✅ 有ets实现 | 已适配 | > **🟢 纯Dart (10个)**: 仅改版本号,无任何ohos文件。Flutter AOT编译直接运行。 > **🔴 原生插件 (3个)**: 含ets原生代码 + flutter.har依赖,需要DevEco Studio编译。 ### 5.2 各包克隆命令速查 ```bash cd packages # ====== 🟢 纯Dart包(仅改版本号即可)====== # 1. fl_chart git clone --depth 1 --branch 1.2.0 https://github.com/imaNNeo/fl_chart.git fl_chart # 2. badges git clone --depth 1 --branch v3.2.0 https://github.com/yako-dev/flutter_badges.git badges # 3. flutter_staggered_grid_view git clone --depth 1 --branch v0.7.0 https://github.com/letsar/flutter_staggered_grid_view.git # 4. cached_network_image(monorepo,主包在子目录) git clone --depth 1 --branch v3.4.1 https://github.com/Baseflow/flutter_cached_network_image.git cached_network_image # 引用路径: packages/cached_network_image/cached_network_image # 5. flutter_markdown_plus git clone --depth 1 --branch v1.0.7 https://github.com/foresightmobile/flutter_markdown_plus.git flutter_markdown_plus # 6. flutter_card_swiper git clone --depth 1 --branch v7.2.0 https://github.com/ricardodalarme/flutter_card_swiper.git flutter_card_swiper # 7. qr git clone --depth 1 --branch v3.0.2 https://github.com/kevmoo/qr.dart.git qr # 8. mailer git clone --depth 1 --branch v7.1.0 https://github.com/dart-mailer/mailer.git mailer # 9. docs_gee(纯Dart,DOCX/PDF文档生成库) git clone --depth 1 https://github.com/erykkruk/docs_gee.git docs_gee # 实际代码在 docx_generator/ 子目录,引用路径: packages/docs_gee/docx_generator # 10. pdf(纯Dart,专业PDF生成库,GitHub 2k+ stars) git clone --depth 1 https://github.com/DavBfr/dart_pdf.git pdf # monorepo结构,实际代码在 pdf/ 子目录,引用路径: packages/pdf/pdf # ====== 🔴 原生插件(需要ets实现+flutter.har)====== # 10. mobile_scanner(官方v7.2.0 + 鸿蒙适配合并) git clone --depth 1 --branch v7.2.0 https://github.com/juliansteenbakker/mobile_scanner.git mobile_scanner # 合并鸿蒙适配:ohos/ 目录、CameraUtil.ets、Barcode.ets 等 ``` ### 5.3 各包使用示例 **fl_chart** ```dart import 'package:fl_chart/fl_chart.dart'; LineChart(LineChartData(...)) ``` **badges** ```dart import 'package:badges/badges.dart' as badges; badges.Badge(badgeContent: Text('3'), child: Icon(CupertinoIcons.shopping_cart)) ``` **flutter_staggered_grid_view** ```dart import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; MasonryGridView.count(crossAxisCount: 2, itemCount: items.length, itemBuilder: (ctx, i) => Tile(index: i)) ``` **cached_network_image** ```dart import 'package:cached_network_image/cached_network_image.dart'; CachedNetworkImage(imageUrl: 'url', placeholder: (ctx, url) => CircularProgressIndicator(), errorWidget: (ctx, url, err) => Icon(Icons.error)) ``` **flutter_markdown_plus** ```dart import 'package:flutter_markdown_plus/flutter_markdown_plus.dart'; Markdown(data: '# Hello\n**bold** text', onTapLink: (text, href, title) {}) ``` **flutter_card_swiper** ```dart import 'package:flutter_card_swiper/flutter_card_swiper.dart'; CardSwiper(itemCount: cards.length, itemBuilder: (ctx, index) => CardWidget(cards[index]), onSwipe: (prev, curr, direction) {}) ``` **qr** ```dart import 'package:qr/qr.dart'; final qrCode = QrCode(4, QrErrorCorrectLevel.L)..addData('Hello, world!'); final qrImage = QrImage(qrCode); ``` **mailer** ```dart import 'package:mailer/mailer.dart'; import 'package:mailer/smtp_server.dart'; final smtpServer = gmail('user@gmail.com', 'password'); final message = Message()..from = Address('user@gmail.com')..recipients.add('target@example.com')..subject = 'Test'..text = 'Hello'; final sendReport = await send(message, smtpServer); ``` **mobile_scanner** ```dart import 'package:mobile_scanner/mobile_scanner.dart'; MobileScanner( controller: MobileScannerController(), onDetect: (result) { print(result.barcodes.first.rawValue); }, ) ``` **docs_gee** ```dart import 'package:docs_gee/docs_gee.dart'; import 'dart:io'; final doc = Document(title: '报告', author: '作者'); doc.addParagraph(Paragraph.heading('标题', level: 1)); doc.addParagraph(Paragraph.text('正文内容')); doc.addTable(Table(rows: [ TableRow(cells: [TableCell.text('列1'), TableCell.text('列2')]), TableRow(cells: [TableCell.text('数据1'), TableCell.text('数据2')]), ])); File('report.docx').writeAsBytesSync(DocxGenerator().generate(doc)); File('report.pdf').writeAsBytesSync(PdfGenerator().generate(doc)); ``` **pdf(专业PDF生成,推荐用于PDF导出)** ```dart import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; final pdf = pw.Document( theme: pw.ThemeData.withFont( base: pw.Font.ttf(fontBytes.buffer.asByteData()), bold: pw.Font.ttf(boldFontBytes.buffer.asByteData()), ), ); pdf.addPage(pw.MultiPage( pageFormat: PdfPageFormat.a4, build: (context) => [ pw.Text('标题', style: pw.TextStyle(fontSize: 24, fontWeight: pw.FontWeight.bold)), pw.SizedBox(height: 16), pw.Text('正文内容'), pw.TableHelper.fromTextArray( headers: ['列1', '列2'], data: [['数据1', '数据2']], ), ], )); final bytes = await pdf.save(); File('report.pdf').writeAsBytesSync(bytes); ``` --- ## 六、项目依赖兼容性总览 | 依赖 | 来源 | Web | 鸿蒙 | 类型 | 备注 | |------|------|-----|------|------|------| | fl_chart | 本地 path | ✅ | ✅ | 🟢纯Dart | 图表 | | badges | 本地 path | ✅ | ✅ | 🟢纯Dart | 徽标 | | flutter_staggered_grid_view | 本地 path | ✅ | ✅ | 🟢纯Dart | 瀑布流 | | cached_network_image | 本地 path | ✅ | ✅ | 🟢纯Dart | 图片缓存 | | flutter_markdown_plus | 本地 path | ✅ | ✅ | 🟢纯Dart | Markdown | | flutter_card_swiper | 本地 path | ✅ | ✅ | 🟢纯Dart | 卡片滑动 | | qr | 本地 path | ✅ | ✅ | 🟢纯Dart | QR码生成 | | mailer | 本地 path | ❌ | ✅ | 🟢纯Dart | SMTP发邮件 | | docs_gee | 本地 path | ⚠️ | ✅ | 🟢纯Dart | DOCX/PDF生成 | | **pdf** | 本地 path | ✅ | ✅ | 🟢纯Dart | 专业PDF生成(推荐) | | mobile_scanner | 本地 path | ✅ | ✅ | 🔴原生插件 | 扫码 | | file_picker | 本地 path | ✅ | ✅ | 🔴原生插件 | 文件选择 | | fluttertoast_ohos | 本地 path | ⚠️ | ✅ | 🔴原生插件 | Toast提示 | | hive_ce | pub.dev | ✅ | ✅ | 🟢纯Dart | 数据库 | | get / dio / logger / intl | pub.dev | ✅ | ✅ | 🟢纯Dart | 工具 | | shared_preferences | pub.dev | ✅ | ✅ | 🟢纯Dart | 存储 | | path_provider | git(鸿蒙版) | ⚠️ | ✅ | 🔴原生插件 | 路径 | | connectivity_plus | git(鸿蒙版) | ⚠️ | ✅ | 🔴原生插件 | 网络 | | share_plus | git(鸿蒙版) | ⚠️ | ✅ | 🔴原生插件 | 分享 | | permission_handler | git(鸿蒙版) | ❌ | ✅ | 🔴原生插件 | 权限 | --- ## 七、参考文档索引 | 文档 | 用途 | |------|------| | [**Flutter包鸿蒙适配通用指南.md**](./Flutter包鸿蒙适配通用指南.md) | **👈 通用方法论:判断包类型、适配步骤、踩坑记录、检查清单(给其他人看)** | | [ohos平台适配flutter三方库指导.md](./ohos平台适配flutter三方库指导.md) | 原生插件完整适配流程(MethodChannel、打 har 包) | | [开发FFI plugin.md](./开发FFI plugin.md) | FFI 插件开发指南 | | [OpenHarmony应用如何集成Flutter模块.md](./OpenHarmony应用如何集成Flutter模块.md) | Flutter 模块集成到鸿蒙应用 | | [FlutterChannel通信.md](./如何使用Flutter与OpenHarmony通信%20FlutterChannel.md) | MethodChannel / EventChannel / BasicMessageChannel 用法 |