Flutter 三方库 OpenHarmony 鸿蒙适配实战:dialog_alert 纯 Dart 对话框库评估、改动与鸿蒙 PC 真机验证全流程

基于 Flutter-OH 3.44.9-dev(Dart 3.12.2)在 Windows 10 22H2 上全程实测通过;真机环节在一台**鸿蒙 PC(OpenHarmony 6.1.1,API 24,arm64,2in1 形态)**上验证。文中所有源码分析、改动内容、构建输出、真机效果均为实际环境抓取,可放心对照复现。

前言

OpenHarmony × Flutter 社区资源

环境搭好之后(还没搭的看这篇环境搭建保姆级教程),下一步就是给项目引入三方库。但拿到一个库就动手改代码是大忌——先评估,再动手,能省掉大量无用功。

本文以 dialog_alert(对话框组件库)为例,完整演示从评估 → 改动 → 构建 → 真机验证的全流程,重点讲清楚一个关键判断:这个库到底需不需要写 ArkTS 原生代码? 答案可能出乎你的意料。

在这里插入图片描述

在这里插入图片描述

一、库评估:拿到三方库的第一步不是改代码,是判断要不要改

1.1 dialog_alert 基本信息

dialog_alert 是一个 Flutter 对话框组件库,提供 showDialogAlert() 统一接口,支持标题、正文、确认/取消按钮及自定义按钮样式,内部通过 Platform.isIOS 自动切换 Material 和 Cupertino 两种视觉风格——整个实现完全基于 Flutter 自带的 Widget(AlertDialog、TextButton 等),不依赖任何系统原生 API。

项目内容
库名dialog_alert
pub.dev 版本0.0.3
功能显示对话框弹窗(Material / Cupertino 双风格)
主要 APIshowDialogAlert()
维护状态4 年未更新

1.2 六步评估法(来自 ohos-flutter-plugin-adaptation-necessity-check 评估流程)

拿到一个 Flutter 库,按下面六步走一遍就能得出结论:

第 1 步:目录结构检查

用 GitHub API 查看仓库根目录文件列表。dialog_alert 的根目录只有这些:

dialog_alert/
├── lib/           ← Dart 源码
├── example/       ← 示例工程
├── test/          ← 单元测试
├── gif/           ← 演示动图
├── CHANGELOG.md
├── LICENSE
├── README.md
└── pubspec.yaml

没有 android/ 目录,没有 ios/ 目录。 这是第一个强信号——这个库从一开始就没有任何原生平台代码。

第 2 步:pubspec.yaml plugin 声明检查

读 pubspec.yaml 的完整内容:

name: dialog_alert
description: A new Flutter package for showing native alert view in ios
  and native alert dialog in android.
version: 0.0.3
homepage: https://github.com/mkarundas/DialogAlert

environment:
  sdk: ">=2.15.1 <3.0.0"
  flutter: ">=1.17.0"

dependencies:
  flutter:
    sdk: flutter

dev_dependencies:
  flutter_test:
    sdk: flutter
  flutter_lints: ^1.0.0

flutter:

注意三个关键点:

  • 没有 plugin: 字段——不是 Flutter 插件,是纯 Dart 包
  • 没有 platforms: 声明——没有注册任何平台的原生实现
  • dependencies 只有 flutter SDK——零三方原生依赖

虽然 description 写了"native alert view in ios and native alert dialog in android",但 pub.dev 的 description 经常名不副实——看代码不看描述

第 3 步:MethodChannel 平台通道检查

通过 CDN 读取全部 Dart 源码(lib/ 下两个文件),搜索 MethodChannel、PlatformMessage、BinaryMessenger 等关键词。

show_dialog_alert.dart 的完整核心实现(省略 import 行):

enum ButtonActionType { action, cancel }

Future<ButtonActionType?> showDialogAlert({
  required BuildContext context,
  required String title,
  required String message,
  required String actionButtonTitle,
  String? cancelButtonTitle,
  TextStyle? actionButtonTextStyle,
  TextStyle? cancelButtonTextStyle,
}) {
  return _showDialogAlert(
    context: context,
    title: title,
    message: message,
    actionButtonTitle: actionButtonTitle,
    cancelButtonTitle: cancelButtonTitle,
    actionButtonTextStyle: actionButtonTextStyle,
    cancelButtonTextStyle: cancelButtonTextStyle,
  );
}

dialog_alert_button.dart 的完整实现:

class DialogAlertButton extends StatelessWidget {
  const DialogAlertButton({
    Key? key,
    required this.onPressed,
    required this.title,
    this.isDestructiveAction = false,
    this.isDefaultAction = false,
    this.textStyle,
  }) : super(key: key);

  final VoidCallback onPressed;
  final String title;
  final bool isDestructiveAction;
  final bool isDefaultAction;
  final TextStyle? textStyle;

  
  Widget build(BuildContext context) {
    return !Platform.isIOS
        ? TextButton(
            onPressed: onPressed,
            child: Text(
              title,
              style: textStyle,
            ),
          )
        : CupertinoDialogAction(
            isDestructiveAction: isDestructiveAction,
            isDefaultAction: isDefaultAction,
            onPressed: onPressed,
            child: Text(
              title,
              style: textStyle,
            ),
          );
  }
}

零 MethodChannel,零平台通道调用。 所有 UI 完全由 Flutter Widget(AlertDialog、TextButton、CupertinoAlertDialog、CupertinoDialogAction)实现。

第 4 步:Platform.isIOS 平台判断检查

两个文件中都有 Platform.isIOS 判断,用于切换 Material / Cupertino 风格。这个判断在 OpenHarmony 上的行为后面第四章详细分析。

第 5 步:依赖递归检查

唯一依赖是 flutter SDK 本身,无递归依赖链风险。

第 6 步:综合判断

评估维度结果
原生平台代码(android/、ios/)
MethodChannel / 平台通道
pubspec plugin 声明
三方原生依赖
结论纯 Dart 实现,无需原生适配,可直接用于 OpenHarmony

关键提醒:pub.dev 的 platforms 字段标注了 Flutter、Android、iOS、Windows 等平台——这个字段不可靠。纯 Dart 包会被 pub.dev 自动标注为全平台支持,不代表它有原生实现。判断的唯一标准是看源码有没有 MethodChannel 和原生目录


二、适配流程:两处 pubspec 改动 + 一个 ohos 宿主工程

评估结论是"纯 Dart 无需原生适配"后,实际改动非常轻量。

2.1 克隆仓库到本地

原库托管在 GitHub,国内网络直连不稳定,使用 ghproxy 镜像加速:

cd D:\Flutters
git clone https://ghproxy.net/https://github.com/mkarundas/DialogAlert.git dialog_alert

如果你的网络能直连 GitHub,直接用原始地址 git clone https://github.com/mkarundas/DialogAlert.git dialog_alert 即可。

2.2 修改 Dart SDK 版本约束(唯一的代码改动)

这是整个适配过程中唯一需要改代码的地方

问题:原库 pubspec.yaml 的 SDK 约束是 >=2.15.1 ❤️.0.0,上限锁死在 Dart 2。而 Flutter-OH 3.44.9 搭载的是 Dart 3.12.2,flutter pub get 直接报版本冲突:

Because dialog_alert requires SDK version >=2.15.1 <3.0.0, version solving failed.

修法:把上限从 ❤️.0.0 放宽到 <4.0.0。

修改前(pubspec.yaml 第 6~8 行):

environment:
  sdk: ">=2.15.1 <3.0.0"
  flutter: ">=1.17.0"

修改后:

environment:
  sdk: ">=2.15.1 <4.0.0"
  flutter: ">=1.17.0"

example 工程的 pubspec.yaml 同步修改(SDK 约束放宽 + 主包依赖改为本地路径引用)。

修改前:

environment:
  sdk: ">=2.15.1 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  dialog_alert: ^0.0.2

修改后:

environment:
  sdk: ">=2.15.1 <4.0.0"

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^1.0.2
  dialog_alert:
    path: ../

path: …/ 让 example 直接引用本地修改后的主包,而不是从 pub.dev 拉原版——这样后面的真机验证测的就是我们改过的版本。

为什么原库 4 年没更新? dialog_alert 最后一次发布是 2021 年,当时 Dart 3 还没发布,作者写 ❤️.0.0 完全合理。只是库停更后,新环境(Dart 3)和旧约束之间出现了不兼容。放宽到 <4.0.0 是社区公认的兼容修法,向下兼容 Dart 2,向上兼容 Dart 3。

2.3 创建 OpenHarmony 宿主工程

example 工程原本只有 android/ 和 ios/ 宿主,需要补上 ohos/:

cd D:\Flutters\dialog_alert\example
flutter create --platforms=ohos .

这条命令在 example/ 下生成 ohos/ 目录(约 39 个文件),结构如下:

example/ohos/
├── entry/src/main/
│   ├── module.json5              ← 设备类型声明(下一步要改)
│   ├── ets/entryability/         ← 应用入口 Ability
│   └── resources/                ← 资源文件
├── build-profile.json5           ← 构建配置(签名后会自动写入证书路径)
├── hvigorfile.js                 ← hvigor 构建脚本
└── oh-package.json5              ← ohpm 包配置

2.4 补全 deviceTypes(鸿蒙 PC 必改项)

flutter create 生成的 module.json5 里,deviceTypes 只有 phone。如果你的目标设备是鸿蒙 PC(2in1 形态)或平板(tablet),必须补全,否则 DevEco Studio 运行时会报设备类型不匹配:

Error Message: The type of target device does not match the device type
configured by module: entry.
Required device type:2in1, current module device type:phone

修改 example/ohos/entry/src/main/module.json5:

{
  "module": {
    "name": "entry",
    "type": "entry",
    "deviceTypes": [
      "phone",
      "tablet",
      "2in1"
    ],
    // ... 其余配置保持不变
  }
}

经验值:凡是 Flutter-OH 工程(包括三方库适配的 example),deviceTypes 建议 phone、tablet、2in1 三态全声明,一步到位兼容所有鸿蒙设备形态。


三、构建与真机验证

3.1 DevEco Studio 配置调试签名

真机运行 HAP 必须有签名。配置一次即可,后续命令行构建不再需要打开 DevEco。

操作步骤(中文版 DevEco Studio 26 实测菜单路径):

  1. DevEco Studio →「文件」→「打开」→ 选择 D:\Flutters\dialog_alert\example\ohos(注意是 ohos 子目录,不是 example 根目录,选错找不到签名入口)
  2. 等右下角工程同步完成
  3. 「文件」→「项目结构」→ 左侧「签名配置」→ 勾选「自动生成签名」
  4. 弹出华为账号登录框,登录后证书自动填充,点「确定」

签名信息写入 example/ohos/build-profile.json5。

3.2 运行与构建

在 example 目录下执行:

cd D:\Flutters\dialog_alert\example
flutter run

只连一台设备时不用 -d 参数。hvigor 编译(实测约 38 秒)完成后,应用自动安装到设备并启动。

也可以直接在 DevEco Studio 里点运行按钮,效果一样。DevEco 方式走 IDE 内部的 JDK 构建,不会受系统 JAVA_HOME 版本影响。

在这里插入图片描述

3.3 真机效果验证

example 的 main.dart 提供了三个按钮,逐个点击验证:

按钮 1:Simple Alert Dialog

showDialogAlert(
  context: context,
  title: 'Success',
  message: 'You have successfully updated your profile.',
  actionButtonTitle: 'OK',
);

预期效果:弹出 Material 风格对话框,标题"Success",正文提示,底部一个"OK"按钮。

按钮 2:Alert Dialog with Cancel Button

final result = await showDialogAlert(
  context: context,
  title: 'Message',
  message: 'Do you want to upload your profile picture?',
  actionButtonTitle: 'Upload',
  cancelButtonTitle: 'Cancel',
);

预期效果:弹出带"Upload"和"Cancel"两个按钮的对话框。返回值为 ButtonActionType.action 或 ButtonActionType.cancel。

按钮 3:Custom Button Title Text Style

final result = await showDialogAlert(
  context: context,
  title: 'Success',
  message: 'You have successfully uploaded',
  actionButtonTitle: 'Submit',
  cancelButtonTitle: 'Cancel',
  actionButtonTextStyle: const TextStyle(
    color: Colors.green,
  ),
  cancelButtonTextStyle: const TextStyle(
    color: Colors.pink,
  ),
);

预期效果:弹出对话框,"Submit"按钮绿色,"Cancel"按钮粉色——验证 TextStyle 自定义参数也能正常传递。

实测结果:三个按钮全部正常弹窗,所有 API 参数工作正常。

验证状态汇总:

验证项状态说明
依赖解析(flutter pub get)✅ 通过Dart 3.12.2 下 SDK 约束冲突已修复
hvigor 编译(flutter build hap)✅ 通过实测约 38 秒完成
真机运行(三个按钮弹窗)✅ 通过Material 风格,全部 API 工作正常

在这里插入图片描述

四、源码深度分析:Platform.isIOS 在鸿蒙上的行为

4.1 关键判断逻辑

库内所有平台区分逻辑集中在一个函数里(show_dialog_alert.dart 第 58~73 行):

Future<ButtonActionType?> _showDialogAlertWidget(
    BuildContext context, String title, String message, List<Widget> actions) {
  if (!Platform.isIOS) {
    return showDialog(
        context: context,
        builder: (context) => AlertDialog(
            title: Text(title), content: Text(message), actions: actions));
  }
  return showCupertinoDialog(
      context: context,
      builder: (context) => CupertinoAlertDialog(
            title: Text(title),
            content: Text(message),
            actions: actions,
          ));
}

逻辑很简单:不是 iOS 就走 Material 风格(showDialog + AlertDialog),是 iOS 就走 Cupertino 风格(showCupertinoDialog + CupertinoAlertDialog)。

4.2 OpenHarmony 上的实际走向

dart:io 的 Platform.isIOS 在 OpenHarmony 上恒为 false(鸿蒙不是 iOS 设备),所以代码始终走 Material 分支。

这意味着:

  • showDialog() 弹出 Material 风格对话框 → ✅ 正常工作
  • AlertDialog 渲染标题、正文、按钮 → ✅ 正常工作
  • TextButton 渲染按钮(支持 TextStyle 自定义) → ✅ 正常工作
  • Navigator.pop() 返回 ButtonActionType 枚举值 → ✅ 正常工作

Cupertino 风格(CupertinoAlertDialog)在鸿蒙上永远不会触发——这不是缺陷,而是库的设计行为。Android 上也是同样的表现,鸿蒙与 Android 一致。

4.3 按钮侧的同一模式

DialogAlertButton 的 build 方法也是同样的判断:


Widget build(BuildContext context) {
  return !Platform.isIOS
        ? TextButton(
            onPressed: onPressed,
            child: Text(
              title,
              style: textStyle,
            ),
          )
        : CupertinoDialogAction(
            isDestructiveAction: isDestructiveAction,
            isDefaultAction: isDefaultAction,
            onPressed: onPressed,
            child: Text(
              title,
              style: textStyle,
            ),
          );
}

鸿蒙上走 TextButton 分支,与 Android 行为完全一致。

4.4 为什么纯 Dart 库能直接跨平台

Flutter 的核心设计理念是"一次编写,多端运行"。Material 和 Cupertino 组件都是 Flutter 框架自带的纯 Widget 实现,渲染由 Flutter Engine 的 Skia/Impeller 图形引擎完成,不依赖任何操作系统原生 UI 控件。

所以:

  • AlertDialog 不是调用系统的对话框 API,而是 Flutter 自己画的
  • TextButton 不是系统的按钮控件,而是 Flutter 自己渲染的
  • 只要 Flutter Engine 能在某个平台上跑(OpenHarmony 可以),这些 Widget 就能正常工作

这就是纯 Dart 库无需原生适配的根本原因——它从头到尾都没碰过原生代码


常见问题 FAQ

Q1:拿到一个 Flutter 库,怎么快速判断它需不需要原生适配?

看 pubspec.yaml 有没有 plugin: platforms: 声明。下面是一个需要原生适配的插件库 pubspec(对比 dialog_alert 的纯 Dart 包 pubspec):

# 需要原生适配的插件库(如 toast、share_plus 等)
flutter:
  plugin:
    platforms:
      android:
        pluginClass: ToastPlugin
      ios:
        pluginClass: ToastPlugin
      ohos:
        pluginClass: ToastPlugin

dialog_alert 的 pubspec 里没有 plugin: 字段——说明它是纯 Dart 包,不需要写任何原生代码。pub.dev 的 platforms 标签不可靠,纯 Dart 包会被自动标注为全平台支持,判断的唯一标准是看 pubspec 有没有 plugin 声明。

Q2:dialog_alert 的 description 写了"native alert view in ios and native alert dialog in android",为什么实际没有原生代码?

看源码就知道——showDialogAlert 内部用的是 Flutter 自带的 Widget,不是系统原生 API:

// show_dialog_alert.dart 第 58~73 行(真实源码)
if (!Platform.isIOS) {
  return showDialog(                          // Flutter 框架方法
      context: context,
      builder: (context) => AlertDialog(      // Flutter 框架 Widget
          title: Text(title), content: Text(message), actions: actions));
}
return showCupertinoDialog(                   // Flutter 框架方法
    context: context,
    builder: (context) => CupertinoAlertDialog(  // Flutter 框架 Widget
          title: Text(title),
          content: Text(message),
          actions: actions,
        ));

showDialog、AlertDialog、showCupertinoDialog、CupertinoAlertDialog 全部是 Flutter 框架自带的纯 Widget 实现,渲染由 Flutter Engine 完成,不依赖任何操作系统原生 UI 控件。description 里的"native"是宣传用语,名不副实。

Q3:鸿蒙上弹窗是 Material 风格而不是 Cupertino 风格,算适配缺陷吗?

不算。库内通过 Platform.isIOS 区分风格:

// dialog_alert_button.dart 第 23~39 行(真实源码)
return !Platform.isIOS
    ? TextButton(...)           // Material 风格 → 鸿蒙走这里
    : CupertinoDialogAction(...);  // Cupertino 风格 → 仅 iOS

鸿蒙上 Platform.isIOS 恒为 false,始终走 TextButton 分支——这和 Android 上的行为完全一致,是库的设计行为,不是适配缺陷。

Q4:如果想练完整的原生适配流程(Kotlin → ArkTS 翻译),应该选什么库?

选 pubspec.yaml 里有 plugin: platforms: 声明且有 MethodChannel 调用的库。比如一个典型的需要完整适配的插件:

# 需要完整原生适配的插件库 pubspec.yaml
flutter:
  plugin:
    platforms:
      android:
        pluginClass: VibrationPlugin
      ohos:
        pluginClass: VibrationPlugin    # 需要你在 ArkTS 中实现这个类

对应的 Dart 侧会有 MethodChannel 调用:

// Dart 侧通过 MethodChannel 调用原生能力
static const _channel = MethodChannel('com.example/vibration');
Future<void> vibrate() => _channel.invokeMethod('vibrate');

这类库才需要走完整五阶段:生成 ohos 骨架 → 把 Kotlin/Java 翻译成 ArkTS → 注册 pluginClass → 构建 HAR → 真机验证。典型代表:toast(系统通知)、vibration(振动)、share_plus(系统分享)。

Q5:SDK 约束放宽到 <4.0.0 会不会影响 Dart 2 的兼容性?

不会。看修改前后对比:

# 修改前:只兼容 Dart 2
environment:
  sdk: ">=2.15.1 <3.0.0"   # 只接受 2.15.1 ~ 2.x.x

# 修改后:同时兼容 Dart 2 和 Dart 3
environment:
  sdk: ">=2.15.1 <4.0.0"   # 接受 2.15.1 ~ 3.x.x

下限 >=2.15.1 没变,Dart 2 的老项目照样能用;上限从 ❤️.0.0 放宽到 <4.0.0,Dart 3 环境也能解析。这是社区对老库停更后出现版本冲突的标准修法。

Q6:真机运行必须用命令行 flutter run 吗?

不是,两种方式都可以:

# 方式一:命令行(支持热重载)
cd D:\Flutters\dialog_alert\example
flutter run                    # 按 r 热重载,按 R 热重启,按 q 退出

# 方式二:DevEco Studio 点运行按钮
# 文件 → 打开 → example/ohos → 点运行按钮

DevEco 方式走 IDE 内部的 JDK 构建,不会受系统 JAVA_HOME 版本影响。flutter run 的优势是支持热重载(按 r 秒级刷新),适合开发阶段频繁调试;DevEco 方式适合不习惯命令行的用户。

Q7:deviceTypes 必须三个都写吗?只写 phone 行不行?

只写 phone 在手机上能跑,但换设备就报错:

// ❌ 只声明 phone → 鸿蒙 PC(2in1)和平板上报错
"deviceTypes": ["phone"],
// Error: Required device type:2in1, current module device type:phone

// ✅ 三态全声明 → 一次兼容所有鸿蒙设备形态
"deviceTypes": [
  "phone",    // 手机
  "tablet",   // 平板
  "2in1"      // 鸿蒙 PC
],

建议所有 Flutter-OH 工程都写全三态,避免切换设备时再改。


总结

本文完整记录了 dialog_alert 库从评估到鸿蒙 PC 真机验证的全流程:先通过六步评估法确认它是纯 Dart 实现(无原生目录、无 MethodChannel、无 plugin 声明),然后只做了两处 SDK 约束放宽(pubspec.yaml 的 ❤️.0.0 改为 <4.0.0)+ 一行本地路径依赖(path: …/)+ 一个 flutter create 生成的 ohos 宿主 + 一行 deviceTypes 补全,Dart 层源码零改动,就在鸿蒙 PC 真机上跑通了全部三个对话框弹窗。核心经验:拿到库先花 5 分钟评估类型,纯 Dart 库根本不需要写 ArkTS 代码——动手前查一眼源码,能省掉几小时的无用功。动手前也建议先查一眼 Flutter OH 三方库适配列表,很多热门库已有人适配过,别重复造轮子。

参考资料

Logo

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

更多推荐