《HarmonyOS 7 Flutter 三方插件鸿蒙化开发手记》03:把 HarmonyOS 系统能力装进一个 Flutter Plugin【鸿蒙心迹】
Android 返回一个文件路径,HarmonyOS 却返回一个 URI,插件到底该返回什么?

前两篇只有通信壳子。Dart 能调 ArkTS 了,但调什么?真正的业务逻辑还没接。
这篇接一个真正的系统能力,比如文件选择。Android 有文件选择,iOS 有文件选择,HarmonyOS 也有。但它们的 API 长得很像,用起来却完全不一样。
这时候才意识到:翻译 API 不等于迁移插件。
一、先想清楚:API 名字像,语义就一样吗
先找一个看起来很像的 API:文件选择。
Android:返回文件路径 String。
iOS:返回文件 URL。
HarmonyOS:返回文件 URI。
| 平台 | 返回值 |
|---|---|
| Android | /data/file.txt |
| iOS | file:///data/file.txt |
| HarmonyOS | file://com.example.app/data/file.txt |
看起来都是"文件位置",但格式完全不一样。Dart 层怎么统一?
二、能力映射不是语法翻译
很多人以为:Android 的 API 名换成 HarmonyOS 的 API 名,参数对应一下,就完了。
不对。API 名字相似,不代表语义一样。
| 对比 | Android | HarmonyOS |
|---|---|---|
| 文件选择 | ACTION_OPEN_DOCUMENT | filePicker |
| 权限 | READ_EXTERNAL_STORAGE | ohos.permission.READ_FILE |
| 返回值 | Uri | URI |
| 生命周期 | Activity 结果回调 | Want 结果 |
名字都叫"文件选择",但实现细节、权限、返回值、回调方式全不一样。
三、插件层要做语义对齐
插件层的工作不是"翻译",是"对齐"。
Dart 层给用户一个统一的接口:选文件,返回文件路径。
插件层在 HarmonyOS 这边:调用 HarmonyOS 的文件选择 API,拿到 URI,转成 Dart 层要的格式,返回。
这段代码解决什么问题: 文件选择插件实现。
文件: ohos/src/main/ets/FilePickerPlugin.ets
用途: 文件选择能力
接入位置: 插件实现
import { filePicker } from '@kit.CoreFileKit';
class FilePickerPlugin {
async pickFile(): Promise<string> {
// 调用 HarmonyOS 文件选择
let options = new filePicker.FileSelectOptions();
options.fileType = ['document'];
let result = await filePicker.open(options);
// 拿到 URI,转成 Dart 层要的格式
let uri = result.result[0].uri;
return uri; // 返回 file://... 格式
}
}

四、错误码为什么要统一
不同平台的错误码也不一样。Android 有 Android 的错误码,HarmonyOS 有 HarmonyOS 的错误码。
Dart 层用户怎么知道出了什么错?插件层要统一错误码。
| 错误 | Android 码 | HarmonyOS 码 | 统一码 |
|---|---|---|---|
| 用户取消 | CANCELED | USER_CANCELED | canceled |
| 文件不存在 | NOT_FOUND | FILE_NOT_EXIST | not_found |
| 权限拒绝 | PERMISSION_DENIED | PERMISSION_DENIED | permission_denied |
插件层把各平台的错误码,映射成 Dart 层统一的错误码。
五、几个容易踩的坑
第一个坑:Android 返回 path,HarmonyOS 却返回 URI。Dart 层用户拿到的格式不一样。
第二个坑:不同平台错误码语义不同。用户不知道为什么出错。
第三个坑:Dart API 为了兼容旧平台写死数据结构。新平台的新能力用不上。
第四个坑:HarmonyOS 特有能力被最低公共能力限制。为了兼容,把 HarmonyOS 的新特性砍了。
第五个坑:原生对象直接塞给 Channel。原生对象不能序列化,传输报错。

这次做能力接入最大的体会是:插件移植不是"API 翻译",是"语义对齐"。
真正做的时候,最容易忽略的不是怎么调 API,而是怎么把不同平台的差异藏在插件层里,给 Dart 层用户一个统一的接口。
更多推荐



所有评论(0)