Flutter OHOS 插件适配实践:color_brightness 颜色明暗调节扩展移植,Dart 层零变更实现 ArkTS 通道、HAR 打包与真机测试 FAQ
开发工具: 华为云码道
color_brightness 把按百分比调整颜色明暗的常用算法封装为 Flutter 的 Color 扩展,应用可以直接在任意颜色上调用 darken() 和 lighten()。本文以分支 8013c036f22060a8289319e039e6a591b2b3079d 为例,介绍源码准备、OHOS 工程配置、ArkTS 实现和 example 的构建与验证。

插件目前支持 ohos 平台,源码位于 AtomGit 配套仓库。文中的代码以提交 6c38aa45efabf9d3c6faab61d2fcf43801d3113c 为参考。
一、插件简介与适配目标
颜色明暗调节是主题与视觉效果处理中的基础能力。应用给定一个基色和一个百分比,库按算法算出更深或更浅的同类颜色,业务层不需要自己换算 ARGB 通道,也不必为不同平台维护两套取色逻辑。
例如,卡片可以按主题色算出一个略深的悬浮层背景,按钮可以按主色算出按下态颜色,图表也可以按同一基色生成一组明暗递进的色阶。
明暗计算在 Dart 层同步完成:darken() 与 lighten() 都是纯函数,返回新的 Color 对象,不修改原对象,也不经过平台通道。
因此本库的鸿蒙化目标与"移植原生能力"类插件不同:功能面不需要重写,适配要做的是补齐 ohos 平台声明与与其他平台保持一致的 ArkTS 插件类,让该包在 OHOS 侧被正确登记为支持 ohos 的插件。
二、环境准备
环境搭建参考社区文档:Flutter OH 开发环境搭建,完成 Flutter OH SDK 安装、环境变量和 DevEco Studio 配置。
完成后,在宿主机终端执行以下命令,确认当前选中的是支持 OHOS 的 Flutter 工具链,并能发现目标设备:
flutter --version
flutter doctor -v
hdc list targets
工程使用的工具链和 SDK 配置如下:
| 项目 | 版本或配置 | 用途 |
|---|---|---|
| Flutter OHOS SDK | 3.47.7-ohos-1.0.0 | Flutter 编译与 OHOS 平台工具链 |
| Flutter 分支 | oh-3.47-dev | Flutter OHOS 对应开发分支 |
| Dart SDK | 3.13.3 | Dart 语言与包管理环境 |
| HarmonyOS 开发套件 | 26.0.0 release(26.0.0.851) | 本机 DevEco Studio 与安装的 SDK 版本(API 26) |
compileSdkVersion | 未在 product 中显式声明 | 编译时使用本机 DevEco 安装的 SDK |
targetSdkVersion | 6.1.1(24) | 应用面向的行为版本 |
compatibleSdkVersion | 6.1.1(24) | 当前工程声明的最低兼容版本 |
| 插件版本 | 1.0.0 | pubspec.yaml 中的包版本 |
| 原生语言 | ArkTS | HarmonyOS 插件实现 |
| 插件产物 | HAR | 被应用 entry 模块依赖 |
2.1 开发套件版本与工程中的 SDK 版本配置
本机 DevEco Studio 为 26.0.0,对应 API 26;宿主工程却把 compatibleSdkVersion 和 targetSdkVersion 声明为 6.1.1(24)。两者不是同一套编号,含义如下:
26.0.0(API 26)表示本机安装的 HarmonyOS 开发套件版本为26.0.0,对应 API 26,编译时实际使用的就是它。6.1.1(24)是本文 HarmonyOS 应用工程中compatibleSdkVersion和targetSdkVersion的属性值,表示 HarmonyOS 6.1.1,对应 API 24。
对应的 product 配置为:
{
"name": "default",
"signingConfig": "default",
"compatibleSdkVersion": "6.1.1(24)",
"targetSdkVersion": "6.1.1(24)",
"runtimeOS": "HarmonyOS"
}
这组配置以 API 24 为目标版本,并以 API 24 作为最低兼容版本,与本文目标设备的 OpenHarmony-6.1.1.120(API 24)一致。DevEco 只安装了 API 26 的 SDK 并不影响该写法:compatibleSdkVersion 声明的是安装与运行的门槛,编译仍然使用已安装的 SDK。
版本号写法有一条固定规则:API ≥ 26 时直接写纯版本号(如 26.0.0),API < 26 必须写成 版本(API) 形式(如 6.1.1(24))。API 与版本号的对应关系可查 DevEco 的 hos-config.json(osVersionMapper)。安装报版本不匹配时,按这条规则对齐,而不是盲目沿用模板生成的 SDK 版本号。
三、从源码仓库开始准备适配工程
3.1 将上游源码同步到 AtomGit
适配已有第三方插件时,先从 Pub 包信息或项目 README 确认上游地址、包名、版本和许可证。同步仓库时保留源码、许可证和提交历史,方便后续跟踪上游更新。
在 AtomGit 网页的新建仓库流程中,找到从已有仓库导入的入口,填写上游 Git 地址,选择自己有写权限的组织或个人空间,设置目标仓库名称后执行导入。完成后检查目标分支、pubspec.yaml、LICENSE 和提交历史是否完整,并记录适配起点的提交号。如果上游本身托管在 AtomGit,也可以通过 Fork 获得自己的工作仓库。
fluttertpc_color_brightness 已从上游 kakzaki/flutter_color_brightness 同步到 AtomGit。上游包名为 color_brightness,版本为 1.0.0,许可证为 MIT。下面使用 AtomGit 地址拉取代码;需要提交修改时,使用自己有写权限的仓库或 Fork。
3.2 将代码拉取到宿主机
在安装了 Flutter OH 和 DevEco Studio 的开发电脑上打开终端,进入准备存放项目的目录,执行:
git clone https://atomgit.com/oh-flutter/fluttertpc_color_brightness.git
cd fluttertpc_color_brightness
pwd
ls
git remote -v
git status --short --branch
git rev-parse HEAD
git clone 会创建 fluttertpc_color_brightness/ 目录;cd 后的位置就是下文所说的插件仓库根目录,这里应能看到 pubspec.yaml、lib/ 和 example/。Git 仓库名是 fluttertpc_color_brightness,Dart 包名是 color_brightness。
需要使用与本文相同的代码版本时,在没有未提交修改的仓库中切换到以下提交:
git switch --detach 6c38aa45efabf9d3c6faab61d2fcf43801d3113c
适配其他插件时,使用该插件对应版本的 tag 或 commit 作为分支起点。
3.3 在仓库根目录确定适配分支与版本标记
本库没有为 OHOS 适配单独开特性分支,适配提交直接落在 master 上,版本通过 TAG 标记。TAG 命名规则为 原库版本-ohos-版本号-beta.x,本库使用 1.0.0-ohos-1.0.0-beta.1。在 fluttertpc_color_brightness/ 根目录执行:
git switch master
git branch --show-current
git tag --list '1.0.0-ohos-*'
git log --oneline -3
git branch --show-current 用于确认当前所在分支,git tag --list 用于确认版本标记是否已推送。向接收仓库提交时按其对分支与 TAG 的要求执行;需要在自己的 Fork 上独立维护时,再新建 feat/ohos_color_brightness_1.0.0 之类的分支也不影响上述规则。
3.4 自动补全 OHOS 适配结构
确认分支后,仍在同一个插件根目录执行结构补全。以下命令适用于尚无 ohos/ 目录的既有 Flutter 平台插件:
flutter create --template=plugin --platforms=ohos --project-name color_brightness .
git status --short
git diff -- pubspec.yaml lib example
--template=plugin指定插件模板。--platforms=ohos指定需要补全的平台。--project-name color_brightness使用 Dart 包名,避免把仓库目录名作为包名。- 最后的
.表示在当前插件目录补全工程,不是另建一层color_brightness/。
该命令生成 OHOS 平台脚手架。生成后务必用 diff 检查:模板会连带注入与 OHOS 无关的内容,例如 federated 骨架(lib/*_method_channel.dart、lib/*_platform_interface.dart、lib/*_web.dart)、.kts 构建脚本、*.iml、local.properties,还可能改写 analysis_options.yaml。本次适配保留了已有 API、其他平台注册项及依赖配置,只保留 ohos/ 与 example/ohos/ 相关产物。不同 Flutter OH 版本生成的模板可能略有差异。
如果生成后 example/ohos/ 仍不存在,进入已有示例应用补全平台:
cd example
flutter create --platforms=ohos .
cd ..
配套仓库已经包含 ohos/ 和 example/ohos/,直接运行示例时可以跳过结构补全。新建插件则使用 flutter create --org com.example --template=plugin --platforms=ohos color_brightness;已有插件使用上面的 . 在当前目录补全。
3.5 适配后的项目目录
适配后的关键目录如下:
fluttertpc_color_brightness/
├── lib/
│ ├── color_brightness.dart
│ └── src/color_brightness_base.dart
├── ohos/
│ ├── index.ets
│ ├── oh-package.json5
│ ├── build-profile.json5
│ └── src/main/
│ ├── ets/components/plugin/ColorBrightnessPlugin.ets
│ └── module.json5
├── example/
│ ├── lib/main.dart
│ ├── lib/pages/color_brightness_demo_page.dart
│ └── ohos/entry/
├── docs/
└── pubspec.yaml
项目根目录如下,其中包含 ohos/、example/,以及 OpenHarmony 中英文说明和变更记录文件:
| 文件 | 主要职责 |
|---|---|
lib/color_brightness.dart | 对外导出入口,暴露 Color 扩展 |
lib/src/color_brightness_base.dart | darken() / lighten() 的 ARGB 计算实现 |
ColorBrightnessPlugin.ets | 注册 Flutter 通道并返回平台版本信息 |
插件 module.json5 | 声明 HAR 模块与设备类型,本库不申请权限 |
示例 entry module.json5 | 声明宿主应用 Ability、设备类型与权限场景 |
example/lib/pages/color_brightness_demo_page.dart | 展示基色选择、比例调节、实时结果与计算结果日志 |
四、Dart 接口与通道分析
OHOS 实现需要遵循 Dart 层已有的方法、参数和回调约定。先阅读 lib/color_brightness.dart、lib/src/color_brightness_base.dart,再在 ohos/src/main/ets/components/plugin/ColorBrightnessPlugin.ets 中实现对应的原生调用。适配其他已有平台的插件时,也应保留其公开接口和其他平台实现。
本例的对应关系如下:
| Dart 入口或模型 | 通道协议 | OHOS 实现 | 应保持的行为 |
|---|---|---|---|
Color.darken(percent) | 无,纯 Dart 计算 | 不涉及原生代码 | 各通道乘以 1 - percent / 100,Alpha 不变 |
Color.lighten(percent) | 无,纯 Dart 计算 | 不涉及原生代码 | 各通道向 255 线性插值,Alpha 不变 |
| 无 Dart 调用方 | color_brightness / getPlatformVersion | deviceInfo 读取系统版本 | 返回"平台 + 版本"字符串,未识别方法返回未实现 |
原生端需要保持通道名、方法名和返回值结构与其余五个平台一致。方法执行异常时,通过错误回调通知 Dart 层。
4.1 跨端架构与调用时序
Flutter 侧与 HarmonyOS 侧之间有两条互不依赖的路径:
- 明暗计算:完全在 Dart 层完成,不经过任何通道,也不判断当前平台;
MethodChannel('color_brightness'):只提供一个getPlatformVersion自检方法,与 Android、iOS、macOS、Windows、Linux 的实现逐字对齐。
第一条路径决定功能是否可用,第二条路径决定插件形态是否完整。本库的功能不依赖通道,因此即使不注册插件,darken() 和 lighten() 在 OHOS 上依然可以正常计算。
4.1.1 一次颜色计算与一次通道自检的时序
计算是同步的,调用返回即拿到结果;通道自检是异步的,只在业务主动调用时发生。
4.2 颜色计算模型:lib/src/color_brightness_base.dart
两个扩展方法都按整数通道处理,Alpha 原样保留:
extension ColorBrightness on Color {
Color darken([double percent = 10]) {
assert(1 <= percent && percent <= 100);
double x = 1 - percent / 100;
return Color.fromARGB(
alpha, (red * x).round(), (green * x).round(), (blue * x).round());
}
Color lighten([double percent = 10]) {
assert(1 <= percent && percent <= 100);
double x = percent / 100;
return Color.fromARGB(alpha, red + ((255 - red) * x).round(),
green + ((255 - green) * x).round(), blue + ((255 - blue) * x).round());
}
}
| 入参 | 计算方式 | 业务含义 |
|---|---|---|
darken(percent) | 每个通道乘以 1 - percent / 100 | 数值越小颜色越深,100 得到黑色 |
lighten(percent) | 每个通道向 255 插值 percent / 100 | 数值越大颜色越浅,100 得到白色 |
percent 超出 1~100 | 触发 assert 断言失败 | 属于调用方入参错误,库不做钳制 |
计算结果是新的 Color,原对象保持不变,因此同一个基色可以反复计算不同比例而互不影响。Alpha 不参与运算,半透明色调用后仍然保持原有的透明度。
4.3 公开 API 与平台接口
本库没有 PlatformInterface,也没有平台实例注册流程。对外只有一个扩展,业务在任意 Color 上直接调用:
const Color baseColor = Colors.red;
final Color darker = baseColor.darken(30);
final Color lighter = baseColor.lighten(30);
percent 是可选参数,默认值为 10。两个方法的参数和返回语义如下:
| 方法 | 参数 | 默认值 | 返回 |
|---|---|---|---|
darken | double percent,取值 1~100 | 10 | 新的 Color |
lighten | double percent,取值 1~100 | 10 | 新的 Color |
扩展对任意 Color 实例生效,包括 MaterialColor、Color.fromARGB 与 Color.fromRGBO 构造的颜色。由于没有异步回调和平台分支,业务侧不需要初始化、订阅或释放任何资源。
4.4 Dart 通道协议分析
4.4.1 通道名称必须两端完全一致
final methodChannel = const MethodChannel('color_brightness');
通道名称属于跨语言协议。Dart 和 ArkTS 任何一端拼写不一致,都会出现"方法未实现"等问题。ArkTS 侧使用同一个常量:
const CHANNEL_NAME: string = 'color_brightness';
4.4.2 Dart 层不调用通道,通道保留为自检手段
lib/ 下没有 invokeMethod、EventChannel 或 Platform.is* 判断,明暗计算完全在本地完成。如果业务需要确认插件是否注册成功,可以主动调用一次:
import 'package:flutter/services.dart';
const MethodChannel _channel = MethodChannel('color_brightness');
Future<String?> readPlatformVersion() async {
try {
return await _channel.invokeMethod<String>('getPlatformVersion');
} on MissingPluginException {
return null; // 插件未注册
} on PlatformException catch (error) {
debugPrint('getPlatformVersion 失败:${error.code} ${error.message}');
return null;
}
}
这段代码只是可选自检,不影响 darken() 和 lighten() 的使用。返回值应形如 HarmonyOS 6.1.0.145 或 OpenHarmony-6.1.1.120。
4.4.3 未识别的方法返回未实现
原生侧只处理 getPlatformVersion,其余方法统一走 notImplemented(),与其余五个平台一致:
if (call.method == 'getPlatformVersion') {
result.success(this.getPlatformVersion());
} else {
result.notImplemented();
}
保留这个分支的用意是让协议边界清晰:任何拼错的方法名都会立刻得到"未实现"的明确反馈,而不是静默返回空值。
五、补全 OHOS 原生实现与工程配置
5.1 在 ColorBrightnessPlugin.ets 中实现原生能力
以 getPlatformVersion 为例:业务调用 invokeMethod('getPlatformVersion') 时,Dart 通道发出同名命令。需要补全的是 ColorBrightnessPlugin.ets 中的对应分支:读取系统版本,通过 result.success 回传结果,异常时通过 result.error 返回错误码。明暗计算不在这里实现,它仍然由 Dart 层的扩展完成,业务侧调用方式没有任何变化。
ColorBrightnessPlugin 实现 FlutterPlugin 和 MethodCallHandler。下面列出类中的主要成员和方法,完整文件还包含 getUniqueClassName() 等插件接口。
原生插件位于:
ohos/src/main/ets/components/plugin/ColorBrightnessPlugin.ets
5.1.1 引入 Flutter 和 HarmonyOS 能力
import {
FlutterPlugin,
FlutterPluginBinding,
MethodCall,
MethodCallHandler,
MethodChannel,
MethodResult,
} from '@ohos/flutter_ohos';
import deviceInfo from '@ohos.deviceInfo';
import { BusinessError } from '@ohos.base';
import hilog from '@ohos.hilog';
其中:
FlutterPlugin负责接入 Flutter Engine 生命周期;MethodChannel接收 Dart 发来的命令;deviceInfo提供系统版本信息,export default的导出形式决定了要用默认导入;BusinessError用于读取 HarmonyOS 异常码和异常消息;hilog用于原生侧诊断日志。
这里没有 EventChannel 和 EventSink:本库不产生持续事件,因此不需要事件通道。
5.1.2 连接 Flutter Engine
private channel: MethodChannel | null = null;
onAttachedToEngine(binding: FlutterPluginBinding): void {
try {
this.channel = new MethodChannel(binding.getBinaryMessenger(), CHANNEL_NAME);
this.channel.setMethodCallHandler(this);
hilog.info(DOMAIN, TAG, 'attached to engine, channel [%{public}s] registered', CHANNEL_NAME);
} catch (err) {
const error = err as BusinessError;
hilog.error(DOMAIN, TAG, 'onAttachedToEngine failed, code: %{public}d, message: %{public}s',
error.code, error.message);
}
}
onAttachedToEngine 只做三件事:创建通道、注册处理器、写一条日志。通道注册失败时吞掉异常会让问题隐藏到运行期,所以这里用 hilog.error 保留现场的异常码和消息。
5.1.3 读取平台版本信息
private getPlatformVersion(): string {
const osName: string = deviceInfo.distributionOSName ? deviceInfo.distributionOSName : '';
const osVersion: string = deviceInfo.distributionOSVersion ? deviceInfo.distributionOSVersion : '';
if (osName.length > 0 && osVersion.length > 0) {
return osName + ' ' + osVersion;
}
if (deviceInfo.osFullName && deviceInfo.osFullName.length > 0) {
return deviceInfo.osFullName;
}
return 'OpenHarmony API ' + deviceInfo.sdkApiVersion;
}
取值顺序与 Android 的 Build.VERSION.RELEASE、iOS 的 UIDevice.current.systemVersion 语义对齐:
- 优先取
distributionOSName+distributionOSVersion,即用户可见的发行版信息,例如HarmonyOS 6.1.0.145; - 其次取
osFullName,OpenHarmony 设备没有发行版信息时使用,格式本身已含平台名,因此不再重复加前缀; - 最后用
sdkApiVersion兜底,保证任何设备都能返回可读字符串。
这些字段均无需申请权限,只有 udid、ODID、diskSN 等字段需要。
5.1.4 没有常驻监听需要停止
本库不订阅系统事件,因此没有"取消订阅"这一步。getPlatformVersion 是一次性调用,返回即结束,不持有回调、不占用系统资源。
真正需要释放的是通道本身和处理器引用,它们在 Engine 解绑时统一清理,见 5.1.6。如果后续要在此基础上扩展"读取系统亮度"这类能力,才需要引入相应的权限与监听,并在页面退出时停止——那属于新的能力设计,不在本次适配范围内。
5.1.5 处理 MethodChannel 命令
onMethodCall(call: MethodCall, result: MethodResult): void {
try {
hilog.debug(DOMAIN, TAG, 'onMethodCall: %{public}s', call.method);
if (call.method == 'getPlatformVersion') {
result.success(this.getPlatformVersion());
} else {
result.notImplemented();
}
} catch (err) {
const error = err as BusinessError;
hilog.error(DOMAIN, TAG, 'onMethodCall [%{public}s] failed, code: %{public}d, message: %{public}s',
call.method, error.code, error.message);
result.error(ERR_CODE, 'Failed to handle ' + call.method + ': ' + error.message, error.message);
}
}
result.error 将错误码和消息传回 Dart,触发 PlatformException;hilog 则保留原生侧的诊断信息。错误码使用常量 COLOR_BRIGHTNESS_ERROR,便于在日志中检索。
5.1.6 Engine 解绑时释放资源
onDetachedFromEngine(binding: FlutterPluginBinding): void {
try {
if (this.channel != null) {
// 置空 handler 避免引擎销毁后仍持有回调,导致插件实例无法释放
this.channel.setMethodCallHandler(null);
this.channel = null;
}
hilog.info(DOMAIN, TAG, 'detached from engine');
} catch (err) {
const error = err as BusinessError;
hilog.error(DOMAIN, TAG, 'onDetachedFromEngine failed, code: %{public}d, message: %{public}s',
error.code, error.message);
}
}
Flutter Engine 销毁时执行清理,注销通道处理器并释放引用,覆盖应用退出、多引擎切换等场景。
5.2 声明插件和宿主权限
本库的核心能力由 Dart 层实现,原生侧只注册方法通道并读取系统版本信息,因此不需要任何权限。
5.2.1 插件 HAR 的权限
插件 ohos/src/main/module.json5 中没有 requestPermissions 字段,模块信息保持如下:
{
"module": {
"name": "color_brightness",
"type": "har",
"deviceTypes": ["default", "tablet"]
}
}
type 为 har,表示它作为静态库被宿主 entry 依赖。这里不添加权限声明,也不会因为缺少权限而出现功能受限。
5.2.2 应用 entry 的权限
宿主应用 example/ohos/entry/src/main/module.json5 中保留了模板自带的网络权限:
{
"module": {
"requestPermissions": [
{ "name": "ohos.permission.INTERNET" }
]
}
}
这条声明是工程模板的默认项,与本库的颜色计算和版本读取都无关,删掉不影响示例运行。getPlatformVersion 读取的 distributionOSName、distributionOSVersion、osFullName、sdkApiVersion 均为系统公开信息,不涉及运行时授权。
权限声明和运行时授权是两个步骤。若后续为插件新增能力,需要按目标 SDK 的权限定义处理授权;module.json5 中的声明不会自动完成运行时授权。
5.3 注册并导出插件
pubspec.yaml 通过以下配置声明 OHOS 插件类:
flutter:
plugin:
platforms:
ohos:
pluginClass: ColorBrightnessPlugin
原有 android、ios、linux、macos、windows、web 的注册项保持不变。
插件的 ohos/index.ets 需要导出实现:
import ColorBrightnessPlugin from './src/main/ets/components/plugin/ColorBrightnessPlugin';
export default ColorBrightnessPlugin;
执行 flutter pub get 和构建后,Flutter 工具会为应用生成插件注册代码。通常不应手工编辑 GeneratedPluginRegistrant.ets,因为下次构建可能覆盖它。
注册异常的排查步骤见第九节 MissingPluginException。
5.4 检查 example 的 OHOS 应用结构
本例的 example/ohos/build-profile.json5 应在 products 中设置版本。下面是需核对的配置片段,请合并到现有工程;其中 signingConfig: "default" 需要与本机配置的签名名称一致,签名材料保留在本地。
{
"app": {
"products": [
{
"name": "default",
"signingConfig": "default",
"compatibleSdkVersion": "6.1.1(24)",
"targetSdkVersion": "6.1.1(24)",
"runtimeOS": "HarmonyOS"
}
]
},
"modules": [
{
"name": "entry",
"srcPath": "./entry",
"targets": [
{
"name": "default",
"applyToProducts": ["default"]
}
]
}
]
}
配置后,在 DevEco Studio 中执行一次 Sync Project。如果 entry 模块正常识别,Project 视图中会出现 entry,并能打开 entry 模块的签名配置。
版本号要与目标设备对齐:本文设备为 API 24,因此两项都写 6.1.1(24)。沿用模板默认的 26.0.0 会导致安装时报版本不匹配,详见 9.7。
六、补全交付文件并提交适配分支
6.1 除代码外还要补全哪些文件
代码适配完成后,还需要整理安装说明、接口文档、版本记录和开源信息。接收仓库有专用模板时,按其格式填写:
| 文件 | 应写清楚的内容 |
|---|---|
README.md | 原项目说明、OHOS 支持入口、配套 Demo 和文档链接;保留上游信息 |
README.OpenHarmony_CN.md | 简介、AtomGit 安装方式、版本对应关系、环境约束、权限、接口表、示例、已验证范围和遗留问题 |
README.OpenHarmony.md | 与中文说明对应的英文文档 |
CHANGELOG.OpenHarmony.md | OHOS 新增能力、适配版本、兼容限制与测试范围 |
LICENSE | 保留上游许可证,本库为 MIT |
example/README.md | 依赖方式、运行目录、签名、操作步骤与效果图 |
pubspec.yaml、ohos/oh-package.json5 | 核对包名、版本、插件注册、仓库地址、许可证和依赖 |
.gitignore | 忽略构建缓存及本机签名材料,不漏提交必要源码和配置 |
本库是单包插件,直接沿用上游 LICENSE,未额外增加 NOTICE。上游版权与许可证信息已在 README.OpenHarmony_CN.md 中说明:包名 color_brightness,版本 1.0.0,MIT 许可证,来源为 kakzaki/flutter_color_brightness。
整理时还有两处要核对:ohos/oh-package.json5 的 license 字段目前仍是模板生成的 Apache-2.0,与上游 MIT 不一致,应改为与 LICENSE 相同;example/README.md 仍是模板默认内容,尚未写运行步骤。
6.2 提交前检查
提交前先完成第八节的插件、example 和真机测试,再从根目录检查改动:
git branch --show-current
git diff --check
git status --short
git diff --stat
git diff
检查 diff 中的接口、平台注册和依赖变化,移除本机路径及签名信息,并使文档中的版本和分支与提交内容一致。
本仓库当前工作区中,example/ohos/build-profile.json5 已被写入本机证书路径与加密口令。这类内容属于个人环境信息,提交前必须还原为空的 signingConfigs,不能进入仓库。
6.3 提交并推送到 AtomGit
文档和代码整理完成后,在根目录暂存并提交。文件名按项目实际情况调整:
git add ohos pubspec.yaml example
git add README.md README.OpenHarmony_CN.md README.OpenHarmony.md
git add CHANGELOG.OpenHarmony.md docs .gitignore
git diff --cached --check
git diff --cached --stat
git diff --cached
git commit -m "feat: add OpenHarmony platform support for color_brightness"
git remote -v
git branch --show-current
git push -u origin master
git tag 1.0.0-ohos-1.0.0-beta.1
git push origin 1.0.0-ohos-1.0.0-beta.1
DevEco 可能向 example/ohos/build-profile.json5 写入本机签名配置,需要在提交前从暂存内容中移除。推送时,origin 应指向自己的 AtomGit 仓库,当前分支为 master。
推送后在 AtomGit 发起合并请求,说明上游来源和版本、OHOS 实现范围、依赖及权限、测试环境、操作结果、已知限制,并附 Demo 运行图。目标分支和评审流程以接收仓库要求为准。
七、使用根目录 example 演示接入
仓库自带 example/,可以直接用来调试插件和体验颜色明暗变化。
7.1 本地适配时使用路径依赖
当前 example/pubspec.yaml 的依赖是:
dependencies:
flutter:
sdk: flutter
color_brightness:
path: ../
../ 相对于 example/pubspec.yaml 指向插件根目录,修改根目录插件后可直接联调。
7.2 通过 AtomGit 引入插件
业务应用通过 AtomGit 引入时,将 color_brightness 的 path 配置替换为下面的 Git 依赖。这里固定到本文使用的版本 TAG:
dependencies:
flutter:
sdk: flutter
color_brightness:
git:
url: https://atomgit.com/oh-flutter/fluttertpc_color_brightness.git
ref: 1.0.0-ohos-1.0.0-beta.1
使用自己的适配版本时,先推送分支与 TAG,再将 url 改为对应仓库,ref 改为自己的 TAG 或提交号。需要跟随开发过程时也可以先用分支名。
从插件根目录执行:
cd example
flutter pub get
flutter pub deps
检查 example/pubspec.lock 中 color_brightness 的来源为 git,并核对 url、ref 和 resolved-ref。同时检查没有 dependency_overrides 或 pubspec_overrides.yaml 将其覆盖回本地依赖,确认应用使用的是 Git 依赖。
7.3 调用接口实现明暗对照页面
下面的页面展示基色选择、比例调节和三种颜色的对照,可用于 example/lib/main.dart。仓库中的完整 Demo 还提供色阶矩阵、HEX 明细、操作历史与日志。
import 'package:color_brightness/color_brightness.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(home: BrightnessPage()));
}
class BrightnessPage extends StatefulWidget {
const BrightnessPage({super.key});
State<BrightnessPage> createState() => _BrightnessPageState();
}
class _BrightnessPageState extends State<BrightnessPage> {
static const List<Color> _colors = <Color>[
Colors.red,
Colors.orange,
Colors.green,
Colors.teal,
Colors.blue,
Colors.purple,
];
int _index = 0;
double _percent = 50;
Color get _base => _colors[_index];
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('颜色明暗调节')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Wrap(
spacing: 8,
runSpacing: 8,
children: List<Widget>.generate(_colors.length, (int i) {
return ChoiceChip(
label: Text('基色 ${i + 1}'),
selected: i == _index,
avatar: CircleAvatar(backgroundColor: _colors[i], radius: 8),
onSelected: (_) => setState(() => _index = i),
);
}),
),
const SizedBox(height: 12),
Slider(
min: 1,
max: 100,
divisions: 99,
value: _percent,
label: '${_percent.round()}%',
onChanged: (double value) => setState(() => _percent = value),
),
Text('当前比例:${_percent.round()}%'),
const SizedBox(height: 12),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_Swatch(color: _base, label: '原色'),
const SizedBox(width: 12),
_Swatch(color: _base.darken(_percent), label: 'darken'),
const SizedBox(width: 12),
_Swatch(color: _base.lighten(_percent), label: 'lighten'),
],
),
],
),
),
);
}
}
class _Swatch extends StatelessWidget {
const _Swatch({required this.color, required this.label});
final Color color;
final String label;
Widget build(BuildContext context) {
return Expanded(
child: Column(
children: <Widget>[
Container(height: 80, color: color),
const SizedBox(height: 4),
Text(label),
],
),
);
}
}
滑块的 min 和 max 固定为 1 和 100,与库内 assert 的取值范围一致,避免拖动过程中触发断言失败。
7.4 页面退出时的处理
本库没有订阅、没有异步回调,也没有需要释放的原生资源,因此不需要写 dispose 来取消任何东西,也不需要为回调检查 mounted。
需要注意的是相反的方向:darken() 和 lighten() 在 build 中同步执行,比例变化时由 setState 触发重建即可拿到新颜色。如果业务把计算结果缓存到 State 字段,则要在比例或基色变化时一起更新,否则界面会显示上一次的结果。
多个页面共用同一套配色时,可以把"基色 + 比例 → 颜色"的换算抽成主题层的方法,各页面直接取用,避免各自复制一份比例常量导致色调不一致。
八、验证、构建与鸿蒙设备运行效果
8.1 分别验证插件与 example
从插件仓库根目录执行:
flutter pub get
flutter analyze
cd example
flutter pub get
flutter analyze
本仓库没有保留测试目录,因此没有 flutter test 这一步:功能是纯函数计算,验证以静态分析和页面手工对照为主。如果需要自动化测试,可以按 darken(0)、darken(101) 这类边界补充断言用例,或在 Widget 测试中比对色块的实际颜色值。
静态分析方面,仓库现有记录为插件工程存在 11 条既有提示,全部是 Color.red/green/blue 的弃用告警,与本次适配无关;示例工程为 No issues found!。重新执行时以自己的输出为准,重点是确认没有新增问题。
git diff --stat -- lib/ 的输出应为空,这是"Dart 层零改动"最直接的验收方式。
8.2 确认设备连接
hdc list targets
flutter devices
设备首次连接电脑时,需要在手机端确认调试授权。列表为空时,检查 USB 连接、调试模式和电脑授权。
8.3 配置签名
真机安装的 HAP 通常需要有效签名。推荐使用 DevEco Studio 为 entry 模块配置自动签名:
- 用 DevEco Studio 打开
example/ohos,不是仓库根目录; - 等待工程 Sync 成功,确认 Project 视图中存在
entry模块; - 打开 File > Project Structure > Signing Configs;
- 为
defaultproduct 选择或生成签名; - 确认设备、应用包名、证书和 Profile 匹配;
- 再回到终端执行 Flutter 构建或运行。
签名材料保存在本机,公开仓库中只保留构建所需的通用配置。
8.4 运行示例
以下命令在 example/ 目录执行,将 <device-id> 替换为设备列表中的实际 ID:
flutter run -d <device-id>
也可以先构建 HAP:
flutter build hap --debug
在 Windows 宿主上,flutter build hap 可能在 hvigor 的 ohpm install 阶段失败(见 9.11)。此时可以直接调用 hvigor 打包,效果等价:
cd example/ohos
hvigorw assembleHap -p product=default -p buildMode=debug --no-daemon
该命令需要 java 在 PATH 中,若命令行找不到 java,把 DevEco 自带的 <DevEco>/jbr/bin 加入 PATH。
典型产物位于:
example/ohos/entry/build/default/outputs/default/
目录中通常包含 entry-default-unsigned.hap;完成签名配置后会出现已签名产物。真机安装应选择与当前设备匹配的已签名产物。
8.5 在设备上测试明暗调节
- 打开应用,确认初始状态为红色基色、比例 50%,对照区显示原色、
darken(50)与lighten(50)三个色块; - 依次切换红、橙、绿、青、蓝、紫六个基色,确认三个色块同步换色;
- 把比例拖到 1% 与 100% 两个边界,确认最浅与最深的结果符合预期;
- 在自定义基色区域调整 R、G、B 通道,确认结果只随滑块变化,不出现异常;
- 点击"应用",检查实时结果的 HEX 值与操作历史是否更新;
- 观察
flutter run控制台的日志,日志标签为color_brightness_example,应出现darken(...) = #...;lighten(...) = #...; - 点击右上角重置,确认回到初始状态且历史清空;
- 反复切换与调节,确认无卡顿、无断言失败弹窗。
页面初始显示的三个色块来自示例默认值,属于本地计算,不代表任何平台差异。真机验证的重点是安装成功、页面可交互、颜色与预期一致。
本文尚未在鸿蒙设备上安装运行,以上为待执行的验收步骤,不作为"已通过"的证据。
8.6 鸿蒙设备运行效果
适配完成后,Flutter 应用在鸿蒙设备上可以直接使用 darken() 与 lighten():任意基色都能得到一组明暗递进的颜色,半透明色的 Alpha 保持不变,页面切换基色与比例时三个色块同步刷新。
下面三个位置用于放置真机运行截图:
| 原色 | darken(50) | lighten(50) |
|---|---|---|
| 待补真机截图 | 待补真机截图 | 待补真机截图 |
本库不依赖设备硬件能力,只要应用能正常安装启动,颜色计算即与平台无关,不存在机型差异。
九、FAQ:适配过程与使用问题
9.1 Missing SDK components
典型错误如下:
Missing SDK components. SDK path: ...,
missing components: toolchains,ets,js,native,previewer.
这个错误发生在 Hvigor 同步阶段。通常需要检查构建工具使用的 SDK 路径、组件是否完整,以及 Hvigor 与 SDK 的版本是否匹配。
处理顺序:
- 在 DevEco Studio SDK Manager 中确认所需 API 组件已经下载完整;
- 检查 Flutter 和 DevEco Studio 使用的 SDK 路径是否一致;
- 避免误用
/Applications/DevEco-Studio.app/Contents/sdk之类的不完整目录,Windows 上同理不要指向 DevEco 安装目录下的中间目录; - 确认 SDK 根目录下存在
toolchains、ets、js、native、previewer; - 执行
flutter config --ohos-sdk <正确路径>; - 重新执行
flutter doctor -v和 DevEco Studio Sync。
因为 Sync 和 Compile 首先读取宿主机本地 SDK。手机 API 版本只在部署、安装和运行时参与兼容判断。即使完全不连接手机,本地 SDK 不完整时也会得到相同错误。
当前工程的 compatibleSdkVersion 是 API 24,因此 API 24 在安装版本门槛上是满足的;本机只装 API 26 的 SDK 也能编译,因为 compatibleSdkVersion 声明的是最低兼容版本。
9.2 DevEco Studio 中看不到 entry 模块
插件的 ohos/ 目录是 HAR 模块,可安装应用的 entry 模块位于 example/ohos/entry。
请直接使用 DevEco Studio 打开:
fluttertpc_color_brightness/example/ohos
如果仍看不到 entry,先解决 SDK Sync 错误,再检查 example/ohos/build-profile.json5 的 modules 是否包含 ./entry。同步失败时,Project Structure 无法正确解析模块,签名界面也可能不显示 entry。
9.3 无法手动签名
签名配置依附于可构建的应用模块和 product。只有 HAR 插件模块、工程 Sync 失败,或者打开了错误目录时,DevEco Studio 都可能无法提供 entry 签名入口。
建议先确认:
- 打开的是
example/ohos; - SDK 组件完整并且 Sync 成功;
entry的模块类型为entry;defaultproduct 和 target 已正确关联;- 当前账号、证书和调试设备状态有效。
9.4 能安装但颜色没有变化
按以下顺序检查:
- 是否使用了方法的返回值——
darken()返回新对象,不会修改原Color; - 比例是否真的传到了计算处,例如滑块的值是否被
clamp后仍为 1~100; - 是否在
setState中更新了比例或基色,缺失时界面不会重建; - 色块是否使用了
const构造导致没有跟随状态变化; - 是否把计算结果缓存进
State字段却没有同步更新; - 是否在自定义基色模式下仍以为使用预设色,此时基色由 R/G/B 滑块决定。
9.5 MissingPluginException
这通常表示 Dart 通道找不到已注册的原生插件。新增原生插件后需要重新构建应用。从仓库根目录执行:
cd example
flutter clean
flutter pub get
flutter run -d <device-id>
如果仍然出现,检查自动生成的插件注册文件中是否包含 ColorBrightnessPlugin,同时核对 pubspec.yaml、ohos/index.ets 和 oh-package.json5。
需要说明的是:本库的明暗计算不经过通道,因此即使出现该异常,darken() 和 lighten() 仍然可用,受影响的只有主动调用 getPlatformVersion 的自检逻辑。
9.6 连续调用会不会累积变暗
不会。darken() 和 lighten() 都是纯函数,每次都以传入的颜色为基准重新计算,不修改原对象,也没有内部状态或缓存。
如果出现"越点越黑",通常是把上一次的结果当作下一次的输入,例如在事件里写成 _color = _color.darken(10)。需要固定基准色时,始终从原始基色出发计算。
9.7 编译成功但安装失败
常见原因包括:
- HAP 未签名或使用了错误的 Profile;
- 设备未加入调试设备列表;
- 包名与签名 Profile 不匹配;
- 安装包的
compatibleSdkVersion高于设备 API; - 手机上已经安装了使用不同证书签名的同包名应用;
- 工程声明的 API 与设备
apiVersion不一致,尤其是沿用模板默认的26.0.0而设备为 API 24。
根据安装错误码区分签名、版本和包名冲突,再处理对应配置。版本一项按 2.1 的规则改成设备的 版本(API) 形式即可。
9.8 flutter create 不认识 ohos,或包名不合法
先执行 flutter --version,确认使用的是 OHOS 版工具链,环境配置回到第二节的社区链接核对。包名报错时,确认当前目录包含目标插件的 pubspec.yaml,并显式传入 --project-name color_brightness;仓库目录名 fluttertpc_color_brightness 与 Dart 包名不同,不能直接当作包名使用。生成后检查 diff,清理模板注入的 federated 骨架与 .kts 构建脚本,再补充 ArkTS 业务实现。
9.9 AtomGit 依赖提示找不到分支、TAG 或无权限
先检查 URL 是否指向已同步的目标仓库,再确认 ref 中的 TAG 1.0.0-ohos-1.0.0-beta.1 已经推送。TAG 尚未推送时,可以先使用第七节的提交号。私有仓库还需在本机配置 Git 认证。
9.10 改了本地 ArkTS,Demo 为什么没变化
先检查 example/pubspec.yaml:Git 依赖读取远程提交,不会自动读取本地插件改动。本地联调切回 path: ../;测试远程版本则先提交推送,再更新依赖并核对 pubspec.lock 的 resolved-ref。原生代码变动后停止应用并重新构建运行,不能只做 Dart 热重载。
9.11 Windows 下 flutter build hap 卡在 ohpm install
典型现象是构建很快失败,并输出:
> hvigor start to execute ohpm install
****** B A T C H R E C U R S I O N exceeds STACK limits ******
Recursion Count=242, Stack Usage=90 percent
> hvigor ERROR: 00306053 Specification Limit Violation
Error Message: ohpm install failed.
这是 DevEco 自带 ohpm.bat 在 Windows 下按字符递归处理首个参数导致的批处理栈溢出,与插件代码无关:手动在 example/ohos 执行 ohpm install 可以通过,直接调用 hvigorw 也不会复现,只有经 flutter build hap 拉起时触发。
可用处理方式:
cd example/ohos
hvigorw assembleHap -p product=default -p buildMode=debug --no-daemon
如果此时报 spawn java ENOENT,把 DevEco 自带的 jbr/bin 加入 PATH 后重试。也可以直接在 DevEco Studio 中构建。构建成功后可核对产物同级 pack.info 的 apiVersion,确认 compatible、target 与设备一致。
相关链接
更多推荐



所有评论(0)