随着鸿蒙生态的快速发展,越来越多的 Flutter 开发者希望将现有应用迁移到鸿蒙平台。然而,许多依赖原生能力的三方库在鸿蒙上无法直接运行,需要经过适配改造。本文以 adaptive_image_picker 为例,详细介绍如何将该 Flutter 三方库进行鸿蒙化适配,帮助开发者少走弯路。

1. 背景与适配目标

adaptive_image_picker 是一个用于图片选择的 Flutter 插件,它通过平台通道调用原生相册能力。在 Android 和 iOS 上,该库分别依赖系统相册接口;而在鸿蒙上,需要改用鸿蒙的 PhotoViewPicker 等能力来实现同等功能。

本次适配的目标是:在不改变 Flutter 层 API 的前提下,为鸿蒙平台补齐原生实现,使现有业务代码无需改动即可运行。

2. 适配前准备

在开始适配之前,需要准备好以下环境和工具:

环境搭建的详细步骤请直接参考官方文档:Flutter 鸿蒙环境搭建指南。这里不再赘述,下面重点说明从源码拉取到适配完成的完整过程。

2.1 同步上游仓库到 AtomGit

首先,将上游仓库 fork 或同步到自己的 AtomGit 账号下,方便后续管理和提交适配分支。在 AtomGit 上进入目标仓库页面,点击「Fork」按钮,将 adaptive_image_picker 仓库复制到自己的命名空间下。

如果上游仓库后续有更新,可以通过 AtomGit 的「同步上游」功能,将最新代码拉取到自己的仓库中,保持与上游一致。

2.2 将代码拉取到宿主机

在宿主机(开发电脑)上,使用 git clone 命令将 Fork 后的仓库克隆到本地:

git clone https://atomgit.com/你的用户名/adaptive_image_picker.git
cd adaptive_image_picker

克隆完成后,还需要将上游仓库添加为远程仓库,方便后续同步上游的最新代码。执行以下命令添加上游仓库:

git remote add upstream https://atomgit.com/oh-flutter/adaptive_image_picker.git

添加完成后,可以通过 git remote -v 查看远程仓库列表,确认 origin 指向自己 Fork 的仓库、upstream 指向上游仓库。后续需要同步上游更新时,执行 git fetch upstream 拉取上游代码即可。

2.3 创建分支并自动补全 ohos 适配结构

在目标仓库根目录下,先创建一个适配分支,分支命名统一采用 feat/ohos_库名称_版本号 的格式:

git checkout -b feat/ohos_adaptive_image_picker_1.0.0

接着,使用 Flutter 鸿蒙版的适配工具,自动完成 ohos 目录结构的补全。执行以下命令:

flutter create --platforms ohos .

该命令会在工程根目录下自动生成 ohos 目录,并补齐鸿蒙插件模块所需的基础文件(如 oh-package.json5、module.json5、Index.ets 等),省去手动搭建工程结构的繁琐步骤。

3. 工程结构分析

首先,我们需要了解 adaptive_image_picker 的工程结构。该插件采用标准的 Flutter 插件结构,主要包含以下部分:

adaptive_image_picker/
├── lib/                    # Dart 层代码
│   └── adaptive_image_picker.dart
├── android/                # Android 原生实现
├── ios/                    # iOS 原生实现
├── ohos/                   # 鸿蒙原生实现(需新增)
└── pubspec.yaml

适配的核心工作,就是在工程中新增 ohos 目录,并实现与 Android/iOS 对应的平台通道逻辑。

4. 鸿蒙原生实现

接下来,我们逐步实现鸿蒙侧的原生代码。

4.1 创建鸿蒙插件模块

在工程根目录下创建 ohos 目录,并在 DevEco Studio 中新建一个 HarmonyOS 插件模块。模块名称建议与插件名保持一致,便于管理。

4.2 实现平台通道

鸿蒙侧需要注册 MethodChannel,并实现图片选择方法。核心代码如下:

import { MethodCall, MethodChannel } from '@ohos/flutter_ohos';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { BusinessError } from '@kit.BasicServicesKit';

export class AdaptiveImagePickerPlugin {
  private channel: MethodChannel;

  constructor() {
    this.channel = new MethodChannel('adaptive_image_picker');
    this.channel.setMethodCallHandler(this.handleMethodCall.bind(this));
  }

  private async handleMethodCall(call: MethodCall): Promise<any> {
    if (call.method === 'pickImage') {
      return this.pickImage();
    }
    throw new Error('Unsupported method: ' + call.method);
  }

  private async pickImage(): Promise<string> {
    try {
      const picker = new photoAccessHelper.PhotoViewPicker();
      const result = await picker.select({
        MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
        maxSelectNumber: 1
      });
      if (result.photoUris.length > 0) {
        return result.photoUris[0];
      }
      return '';
    } catch (error) {
      const err = error as BusinessError;
      throw new Error('Image pick failed: ' + err.message);
    }
  }
}

4.3 注册插件

在鸿蒙模块的入口文件中注册插件实例,确保 Flutter 引擎启动时能够加载:

import { AdaptiveImagePickerPlugin } from './AdaptiveImagePickerPlugin';

export default {
  onRegister(): void {
    new AdaptiveImagePickerPlugin();
  }
}

5. Dart 层适配

鸿蒙原生实现完成后,还需要检查 Dart 层代码是否兼容。大多数情况下,由于平台通道接口保持一致,Dart 层无需改动。但需要注意以下几点:

  • 确认 MethodChannel 名称与鸿蒙侧注册的名称一致。
  • 检查返回的数据类型是否与 Dart 层预期一致,例如图片路径的格式。
  • 如果鸿蒙返回的 URI 与 Android 的 content URI 格式不同,需要在 Dart 层做兼容处理。

6. 使用 Demo 验证适配效果

适配完成后,我们需要通过一个 Demo 来验证功能是否正常。对于 Flutter 插件,可以直接使用仓库根目录下的 example 工程作为 Demo;如果仓库没有提供 example,则需要自行创建一个 Flutter 工程来验证。

6.1 在 Demo 中引入三方库

在 pubspec.yaml 中,通过 AtomGit 链接方式引入本地或远程的三方库依赖。推荐使用本地路径方式,直接指向我们刚才适配好的仓库目录:

dependencies:
  flutter:
    sdk: flutter
  adaptive_image_picker:
    path: ../adaptive_image_picker  # 指向本地适配后的仓库

如果希望直接引用 AtomGit 远程仓库,也可以在 pubspec.yaml 中通过 git 方式引入:

dependencies:
  adaptive_image_picker:
    git:
      url: https://atomgit.com/你的用户名/adaptive_image_picker.git
      ref: feat/ohos_adaptive_image_picker_1.0.0

配置完成后,在工程根目录执行 flutter pub get 拉取依赖。

6.2 调用接口实现功能

在 Demo 的页面中,调用 AdaptiveImagePicker 提供的接口,实现图片选择功能。示例代码如下:

import 'package:flutter/material.dart';
import 'package:adaptive_image_picker/adaptive_image_picker.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('adaptive_image_picker Demo')),
        body: const Center(child: PickImageButton()),
      ),
    );
  }
}

class PickImageButton extends StatelessWidget {
  const PickImageButton({super.key});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () async {
        final picker = AdaptiveImagePicker();
        final String? imagePath = await picker.pickImage();
        if (imagePath != null && imagePath.isNotEmpty) {
          // ignore: use_build_context_synchronously
          ScaffoldMessenger.of(context).showSnackBar(
            SnackBar(content: Text('选中图片:$imagePath')),
          );
        }
      },
      child: const Text('选择图片'),
    );
  }
}

6.3 在鸿蒙设备上运行

连接鸿蒙真机或启动模拟器后,执行以下命令构建并运行应用:

flutter run -d <设备ID>

应用启动后,点击「选择图片」按钮,系统会弹出鸿蒙相册选择器。选中一张图片后,页面会显示所选图片的 URI 路径,说明平台通道调用成功,适配生效。

7. 常见问题与解决方案

在适配过程和使用过程中,开发者可能会遇到以下常见问题:

问题现象可能原因解决方案
调用图片选择无响应插件未正确注册检查 onRegister 是否被调用,确认模块配置正确
返回路径无法访问URI 格式与 Dart 层预期不一致在 Dart 层增加 URI 格式转换逻辑
编译报错缺少依赖缺少 MediaLibraryKit 依赖在 module.json5 中补充所需依赖声明
相册权限被拒绝未声明相册读取权限在 module.json5 中声明 ohos.permission.READ_IMAGEVIDEO

7.1 库本身存在问题,如何在对应仓库提交 Issue

当你在适配或使用过程中发现库本身存在 Bug(例如平台通道调用异常、接口行为与文档不符、缺少鸿蒙平台支持等),建议直接到上游仓库提交 Issue,让维护者知晓并修复。具体步骤如下:

  1. 提交 Issue,说明问题和复现步骤
    从文末 链接 进入 fluttertpc_map_launcher 鸿蒙适配仓库,打开 Issues 页面,先搜索有没有相同的问题。如果没有,点击右上角的「新建 Issue」,填写问题标题和复现信息。报告时把 pubspec.yaml 的依赖配置贴出来,再附上 pubspec.lock 中实际解析的主包/平台接口/ohos 包版本,说明预期什么、实际报什么错,以及 Flutter 版本、设备系统、提交号和关键日志。2. Fork 项目 ,在自己的仓库中修改。如果问题能自己修,点击上游仓库右上角的 Fork。在 Fork 页面确认项目名称、自己的账号和要复制的分支,再点击 创建 Fork 项目。
    Fork 完成后,把自己的仓库克隆到本地,并添加上游仓库
    git clone https://atomgit.com/你的用户名/adaptive_image_picker.git
    cd adaptive_image_picker
    git checkout -b fix/ohos_pick_image_issue
  2. 能解决,如何在对应仓库提交 PR

    当开发者修复了库的问题或新增了功能,可以通过提交 Pull Request(PR)回馈社区。具体步骤如下。

  3. PR 提交后,维护者会进行 Code Review,根据反馈修改代码,最终合并到主分支。

    为帮助读者更好地理解和复现本文内容,补充以下资源与说明。

8. 完整示例工程

为了方便读者快速上手,这里提供一个完整的示例工程结构,涵盖鸿蒙插件模块、平台通道实现、Dart 层调用以及 Demo 验证的完整链路。你可以直接基于该结构搭建自己的适配工程。

adaptive_image_picker_ohos_demo/
├── lib/
│   └── main.dart                 # Demo 入口,调用图片选择接口
├── ohos/
│   ├── entry/
│   │   └── src/main/
│   │       ├── ets/
│   │       │   ├── entryability/
│   │       │   │   └── EntryAbility.ets
│   │       │   └── pages/
│   │       │       └── Index.ets   # 鸿蒙侧页面,展示选择结果
│   │       └── module.json5        # 声明权限与依赖
│   └── plugin/
│       └── src/main/ets/
│           ├── AdaptiveImagePickerPlugin.ets  # 平台通道实现
│           └── Index.ets                      # 插件注册入口
├── pubspec.yaml                 # 依赖声明
└── README.md                    # 使用说明

其中,鸿蒙插件模块的核心文件 AdaptiveImagePickerPlugin.ets 负责注册 MethodChannel 并调用 PhotoViewPicker 实现图片选择;Index.ets 在引擎启动时完成插件注册;Dart 层通过统一的 AdaptiveImagePicker 接口调用,无需关心平台差异。

9. 适配检查清单

在完成鸿蒙化适配后,建议对照以下清单逐项检查,确保适配质量与功能完整性:

检查项说明状态
ohos 目录结构完整包含 oh-package.json5、module.json5、Index.ets 等基础文件☐
平台通道名称一致Dart 层与鸿蒙侧 MethodChannel 名称完全匹配☐
插件已正确注册onRegister 被调用,模块配置无误☐
权限声明完整module.json5 中已声明相册读取等所需权限☐
返回数据格式兼容URI 格式与 Dart 层预期一致,或已做兼容转换☐
编译无错误DevEco Studio 单独编译鸿蒙工程通过☐
真机功能验证在鸿蒙真机或模拟器上运行 Demo,图片选择功能正常☐
异常处理完善对用户取消、权限拒绝等场景有合理处理☐

10. 相关链接

以下资源对鸿蒙化适配具有重要参考价值,建议收藏备用:

  • 上游仓库:adaptive_image_picker 源码仓库,用于 Fork、同步与提交 PR。
  • Flutter 鸿蒙环境搭建指南:官方环境搭建文档,涵盖 SDK 安装与工程配置。
  • 鸿蒙开发者文档:HarmonyOS 官方文档,查阅 PhotoViewPicker、MediaLibraryKit 等 API 详情。
  • Flutter 鸿蒙适配工具:通过 flutter create --platforms ohos . 自动生成 ohos 目录结构,相关说明见 Flutter 鸿蒙版 SDK 文档。
  • AtomGit 平台:AtomGit 官网,用于仓库托管、Fork 与 Pull Request 协作。
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐