随着华为鸿蒙操作系统(HarmonyOS)的快速发展,Flutter 开发者面临着如何让应用在鸿蒙平台上完美运行的挑战。本文将详细介绍如何扩展 Flutter 的 screen_brightness 插件,使其支持鸿蒙平台的屏幕亮度调节功能。
首先我们看看代码结构

在原本的目录的技术上增加了screen_brightness_ohos目录,并用arkts实现鸿蒙平台的代码部分

screen_brightness_ohos的配置文件增加
flutter:
plugin:
platforms:
ohos:
package: com.aaassseee.screen_brightness_ohos
pluginClass: ScreenBrightnessohosPlugin
然后再ohos里面如上图目录新建插件文件
ScreenBrightnessPlugin.ets
import settings from '@ohos.settings';
import window from '@ohos.window';
import FlutterManager from '@ohos/flutter_ohos/src/main/ets/embedding/ohos/FlutterManager';
import { AbilityPluginBinding, FlutterPlugin, FlutterPluginBinding } from '@ohos/flutter_ohos/index';
import MethodChannel, {
MethodCallHandler,
MethodResult
} from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodChannel';
import EventChannel, {
EventSink,
StreamHandler
} from '@ohos/flutter_ohos/src/main/ets/plugin/common/EventChannel';
import MethodCall from '@ohos/flutter_ohos/src/main/ets/plugin/common/MethodCall';
import Log from '@ohos/flutter_ohos/src/main/ets/util/Log';
/**
* 日志标签
*/
const TAG = "ScreenBrightnessPlugin";
/**
* 亮度最小值
*/
const MIN_BRIGHTNESS = 0.0;
/**
* 亮度最大值
*/
const MAX_BRIGHTNESS = 1.0;
/**
* 屏幕亮度插件实现类
* 实现了Flutter插件接口,用于处理屏幕亮度相关的操作
*/
export class ScreenBrightnessPlugin implements FlutterPlugin, MethodCallHandler {
/**
* 方法通道名称
* 与Flutter端保持一致
*/
private methodChannelName: string = "github.com/aaassseee/screen_brightness";
/**
* 应用亮度变化事件通道名称
*/
private applicationBrightnessChangedEventChannelName: string =
"github.com/aaassseee/screen_brightness/application_brightness_changed";
/**
* 系统亮度变化事件通道名称
*/
private systemBrightnessChangedEventChannelName: string =
"github.com/aaassseee/screen_brightness/system_brightness_changed";
/**
* 插件绑定对象
*/
private abilityPluginBinding: AbilityPluginBinding | null = null;
/**
* 方法通道
*/
private methodChannel: MethodChannel | null = null;
/**
* 应用亮度变化事件通道
*/
private applicationBrightnessChangedEventChannel: EventChannel | null = null;
/**
* 系统亮度变化事件通道
*/
private systemBrightnessChangedEventChannel: EventChannel | null = null;
/**
* 主窗口对象
*/
private mainWindow: window.Window | null = null;
/**
* 应用亮度值
* null表示使用系统亮度
*/
private applicationBrightness: number | null = null;
/**
* 是否自动重置亮度
* 当应用进入后台时是否重置亮度
*/
private autoReset: boolean = true;
/**
* 是否使用动画
* 亮度变化时是否使用动画效果
*/
private animate: boolean = false;
/**
* 应用亮度事件接收器
*/
private applicationBrightnessEventSink: EventSink | null = null;
/**
* 系统亮度事件接收器
*/
private systemBrightnessEventSink: EventSink | null = null;
/**
* 系统亮度监听器
*/
private systemBrightnessObserver: any = null;
/**
* 获取插件的唯一类名
* @returns 插件的唯一类名
*/
getUniqueClassName(): string {
return TAG;
}
/**
* 插件附加到引擎时调用
* 初始化方法通道和事件通道
* @param binding Flutter插件绑定对象
*/
onAttachedToEngine(binding: FlutterPluginBinding): void {
Log.i(TAG, "插件附加到引擎");
// 初始化方法通道
this.methodChannel = new MethodChannel(binding.getBinaryMessenger(), this.methodChannelName);
this.methodChannel.setMethodCallHandler(this);
Log.d(TAG, `方法通道初始化完成: ${this.methodChannelName}`);
// 初始化应用亮度变化事件通道
this.applicationBrightnessChangedEventChannel = new EventChannel(
binding.getBinaryMessenger(),
this.applicationBrightnessChangedEventChannelName
);
this.applicationBrightnessChangedEventChannel.setStreamHandler({
onListen: (arguments: Object, eventSink: EventSink): void => {
Log.d(TAG, "应用亮度变化事件监听开始");
this.applicationBrightnessEventSink = eventSink;
},
onCancel: (arguments: Object): void => {
Log.d(TAG, "应用亮度变化事件监听取消");
this.applicationBrightnessEventSink = null;
}
});
Log.d(TAG, `应用亮度变化事件通道初始化完成: ${this.applicationBrightnessChangedEventChannelName}`);
// 初始化系统亮度变化事件通道
this.systemBrightnessChangedEventChannel = new EventChannel(
binding.getBinaryMessenger(),
this.systemBrightnessChangedEventChannelName
);
this.systemBrightnessChangedEventChannel.setStreamHandler({
onListen: (arguments: Object, eventSink: EventSink): void => {
Log.d(TAG, "系统亮度变化事件监听开始");
this.systemBrightnessEventSink = eventSink;
// 开始监听系统亮度变化
this.startMonitoringSystemBrightness();
},
onCancel: (arguments: Object): void => {
Log.d(TAG, "系统亮度变化事件监听取消");
this.systemBrightnessEventSink = null;
// 停止监听系统亮度变化
this.stopMonitoringSystemBrightness();
}
});
Log.d(TAG, `系统亮度变化事件通道初始化完成: ${this.systemBrightnessChangedEventChannelName}`);
}
/**
* 插件从引擎分离时调用
* 清理方法通道和事件通道
* @param binding Flutter插件绑定对象
*/
onDetachedFromEngine(binding: FlutterPluginBinding): void {
Log.i(TAG, "插件从引擎分离");
this.methodChannel?.setMethodCallHandler(null);
this.methodChannel = null;
this.applicationBrightnessChangedEventChannel?.setStreamHandler(null);
this.applicationBrightnessChangedEventChannel = null;
this.systemBrightnessChangedEventChannel?.setStreamHandler(null);
this.systemBrightnessChangedEventChannel = null;
// 停止监听系统亮度变化
this.stopMonitoringSystemBrightness();
}
/**
* 插件附加到Ability时调用
* 保存Ability绑定对象,用于后续获取上下文
* @param binding Ability插件绑定对象
*/
onAttachedToAbility(binding: AbilityPluginBinding): void {
Log.i(TAG, "插件附加到Ability");
this.abilityPluginBinding = binding;
// 监听应用生命周期变化
if (this.autoReset) {
// TODO: 添加生命周期监听,在应用进入后台时重置亮度
Log.d(TAG, "自动重置亮度功能已启用,但生命周期监听尚未实现");
}
}
/**
* 插件从Ability分离时调用
* 清理Ability绑定对象和窗口对象
*/
onDetachedFromAbility(): void {
Log.i(TAG, "插件从Ability分离");
// TODO: 移除生命周期监听
this.abilityPluginBinding = null;
this.mainWindow = null;
}
/**
* 获取主窗口对象
* 如果窗口对象为空,则尝试获取
*/
getWindow(): void {
if (!this.mainWindow && this.abilityPluginBinding) {
Log.d(TAG, "正在获取主窗口对象");
try {
this.mainWindow = FlutterManager.getInstance()
.getWindowStage(FlutterManager.getInstance().getUIAbility(this.abilityPluginBinding?.getAbility().context))
.getMainWindowSync();
Log.d(TAG, "主窗口对象获取成功");
} catch (error) {
Log.e(TAG, `获取主窗口对象失败: ${error}`);
}
}
}
/**
* 处理Flutter端的方法调用
* @param call 方法调用对象,包含方法名和参数
* @param result 结果回调对象,用于返回结果
*/
onMethodCall(call: MethodCall, result: MethodResult): void {
Log.i(TAG, `收到方法调用: ${call.method}`);
try {
if (!this.mainWindow) {
this.getWindow();
}
switch (call.method) {
// 获取系统亮度
case "getSystemScreenBrightness":
this.getSystemBrightness().then(brightness => {
Log.d(TAG, `获取系统亮度成功: ${brightness}`);
result.success(brightness);
}).catch(error => {
Log.e(TAG, `获取系统亮度失败: ${error}`);
result.error("-9", "获取系统亮度失败", error);
});
break;
// 设置系统亮度
case "setSystemScreenBrightness":
const systemBrightness = parseFloat(call.argument("brightness"));
Log.d(TAG, `尝试设置系统亮度: ${systemBrightness}`);
if (this.isValidBrightness(systemBrightness)) {
this.setSystemBrightness(systemBrightness).then(() => {
Log.d(TAG, `设置系统亮度成功: ${systemBrightness}`);
result.success(null);
}).catch(error => {
Log.e(TAG, `设置系统亮度失败: ${error}`);
result.error("-1", "设置系统亮度失败", error);
});
} else {
Log.e(TAG, `亮度值无效: ${systemBrightness}`);
result.error("-2", "亮度值必须在0.0到1.0之间", null);
}
break;
// 获取应用亮度
case "getApplicationScreenBrightness":
this.getApplicationBrightness().then(brightness => {
Log.d(TAG, `获取应用亮度成功: ${brightness}`);
result.success(brightness);
}).catch(error => {
Log.e(TAG, `获取应用亮度失败: ${error}`);
result.error("-9", "获取应用亮度失败", error);
});
break;
// 设置应用亮度
case "setApplicationScreenBrightness":
const appBrightness = parseFloat(call.argument("brightness"));
Log.d(TAG, `尝试设置应用亮度: ${appBrightness}`);
if (this.isValidBrightness(appBrightness)) {
this.setApplicationBrightness(appBrightness).then(() => {
Log.d(TAG, `设置应用亮度成功: ${appBrightness}`);
result.success(null);
}).catch(error => {
Log.e(TAG, `设置应用亮度失败: ${error}`);
result.error("-1", "设置应用亮度失败", error);
});
} else {
Log.e(TAG, `亮度值无效: ${appBrightness}`);
result.error("-2", "亮度值必须在0.0到1.0之间", null);
}
break;
case "resetApplicationScreenBrightness":
Log.d(TAG, "尝试重置应用亮度");
this.resetApplicationBrightness().then(() => {
Log.d(TAG, "重置应用亮度成功");
result.success(null);
}).catch(error => {
Log.e(TAG, `重置应用亮度失败: ${error}`);
result.error("-1", "重置应用亮度失败", error);
});
break;
case "hasApplicationScreenBrightnessChanged":
const hasChanged = this.hasApplicationBrightnessChanged();
Log.d(TAG, `应用亮度是否已更改: ${hasChanged}`);
result.success(hasChanged);
break;
case "isAutoReset":
Log.d(TAG, `是否自动重置亮度: ${this.isAutoReset}`);
result.success(this.isAutoReset);
break;
case "setAutoReset":
const autoReset = call.argument("isAutoReset");
Log.d(TAG, `设置是否自动重置亮度: ${autoReset}`);
this.setAutoReset(autoReset);
result.success(null);
break;
case "isAnimate":
Log.d(TAG, `是否使用动画: ${this.isAnimate}`);
result.success(this.isAnimate);
break;
case "setAnimate":
const animate = call.argument("isAnimate");
Log.d(TAG, `设置是否使用动画: ${animate}`);
this.setAnimate(animate);
result.success(null);
break;
case "canChangeSystemBrightness":
this.canChangeSystemBrightness().then(canChange => {
Log.d(TAG, `是否可以更改系统亮度: ${canChange}`);
result.success(canChange);
}).catch(error => {
result.error("-1", "检查系统亮度权限失败", error);
});
break;
default:
result.notImplemented();
break;
}
} catch (e) {
Log.e(TAG, "处理方法调用失败: " + e);
result.error("-1", "处理方法调用失败", e);
}
}
// 检查亮度值是否有效
private isValidBrightness(brightness: number): boolean {
return brightness >= MIN_BRIGHTNESS && brightness <= MAX_BRIGHTNESS;
}
// 获取系统亮度
private async getSystemBrightness(): Promise<number> {
try {
// 从系统设置中获取亮度值
// 注意:settings.getValueSync返回的是0-255范围的字符串值
Log.d(TAG, "正在获取系统亮度值");
let value = settings.getValueSync(
this.abilityPluginBinding?.getAbility().context,
settings.display.SCREEN_BRIGHTNESS_STATUS,
'100',
settings.domainName.DEVICE_SHARED
);
const brightness = parseFloat(value) / 255;
Log.d(TAG, `系统亮度值获取成功,原始值: ${value}, 转换后的值: ${brightness}`);
return brightness;
} catch (err) {
Log.e(TAG, `获取系统亮度失败,错误详情: ${err}\n${err.stack}`);
return 1.0; // 默认返回最大亮度
}
}
// 设置系统亮度
private async setSystemBrightness(brightness: number): Promise<void> {
if (!this.isValidBrightness(brightness)) {
const error = new RangeError(`亮度值 ${brightness} 超出有效范围 [${MIN_BRIGHTNESS}, ${MAX_BRIGHTNESS}]`);
Log.e(TAG, `设置系统亮度失败: ${error}`);
throw error;
}
try {
// 将0-1的亮度值转换为0-255
const brightnessValue = Math.round(brightness * 255).toString();
Log.d(TAG, `正在设置系统亮度,输入值: ${brightness}, 转换后的值: ${brightnessValue}`);
await settings.setValue(
this.abilityPluginBinding?.getAbility().context,
settings.display.SCREEN_BRIGHTNESS_STATUS,
brightnessValue,
settings.domainName.DEVICE_SHARED
);
// 通知系统亮度变化
if (this.systemBrightnessEventSink) {
Log.d(TAG, `发送系统亮度变化事件: ${brightness}`);
this.systemBrightnessEventSink.success(brightness);
}
Log.i(TAG, `系统亮度设置成功: ${brightness}`);
} catch (error) {
Log.e(TAG, `设置系统亮度失败: ${error}\n${error.stack}`);
throw error;
}
}
// 获取应用亮度
private async getApplicationBrightness(): Promise<number> {
if (this.applicationBrightness !== null) {
return this.applicationBrightness;
}
// 如果应用亮度未设置,返回系统亮度
return await this.getSystemBrightness();
}
// 设置应用亮度
private async setApplicationBrightness(brightness: number): Promise<void> {
if (!this.isValidBrightness(brightness)) {
throw new RangeError("亮度值必须在0.0到1.0之间");
}
try {
if (!this.mainWindow) {
this.getWindow();
}
// 设置窗口亮度
await this.mainWindow?.setWindowBrightness(brightness);
this.applicationBrightness = brightness;
// 通知应用亮度变化
if (this.applicationBrightnessEventSink) {
Log.d(TAG, `发送应用亮度变化事件: ${brightness}`);
this.applicationBrightnessEventSink.success(brightness);
}
} catch (error) {
Log.e(TAG, "设置应用亮度失败: " + error);
throw error;
}
}
// 重置应用亮度
private async resetApplicationBrightness(): Promise<void> {
try {
if (!this.mainWindow) {
this.getWindow();
}
// 在鸿蒙系统中,设置为-1表示使用系统亮度
await this.mainWindow?.setWindowBrightness(-1);
this.applicationBrightness = null;
// 通知应用亮度变化
if (this.applicationBrightnessEventSink) {
const systemBrightness = await this.getSystemBrightness();
Log.d(TAG, `发送应用亮度重置事件: ${systemBrightness}`);
this.applicationBrightnessEventSink.success(systemBrightness);
}
Log.d(TAG, "应用亮度已重置为系统亮度");
} catch (error) {
Log.e(TAG, "重置应用亮度失败: " + error);
throw error;
}
}
// 判断应用亮度是否已更改
private hasApplicationBrightnessChanged(): boolean {
return this.applicationBrightness !== null;
}
// 获取是否自动重置亮度
private isAutoReset(): boolean {
return this.isAutoReset;
}
// 设置是否自动重置亮度
private setAutoReset(autoReset: boolean): void {
this.isAutoReset = autoReset;
Log.d(TAG, `自动重置亮度已${autoReset ? '启用' : '禁用'}`);
// TODO: 根据autoReset的值添加或移除生命周期监听
}
// 获取是否使用动画
private isAnimate(): boolean {
return this.isAnimate;
}
// 设置是否使用动画
private setAnimate(animate: boolean): void {
this.isAnimate = animate;
Log.d(TAG, `亮度动画已${animate ? '启用' : '禁用'}`);
// 注意:鸿蒙系统可能不支持亮度动画,这里只是记录设置
}
// 检查是否可以更改系统亮度
private async canChangeSystemBrightness(): Promise<boolean> {
try {
// 在鸿蒙系统中,需要检查是否有修改系统设置的权限
// 这里简化处理,假设有权限
// TODO: 实现实际的权限检查
return true;
} catch (error) {
Log.e(TAG, "检查系统亮度权限失败: " + error);
return false;
}
}
// 开始监听系统亮度变化
private startMonitoringSystemBrightness(): void {
Log.d(TAG, "开始监听系统亮度变化");
try {
// TODO: 实现系统亮度变化监听
// 鸿蒙系统中可以使用settings.on方法监听系统设置变化
// 示例代码:
// settings.on('change', {
// uri: settings.display.SCREEN_BRIGHTNESS_STATUS,
// callback: async () => {
// if (this.systemBrightnessEventSink) {
// const brightness = await this.getSystemBrightness();
// this.systemBrightnessEventSink.success(brightness);
// }
// }
// });
Log.d(TAG, "系统亮度变化监听已启动");
} catch (error) {
Log.e(TAG, "启动系统亮度变化监听失败: " + error);
}
}
// 停止监听系统亮度变化
private stopMonitoringSystemBrightness(): void {
Log.d(TAG, "停止监听系统亮度变化");
try {
// TODO: 实现停止系统亮度变化监听
// 鸿蒙系统中可以使用settings.off方法停止监听系统设置变化
// 示例代码:
// settings.off('change', {
// uri: settings.display.SCREEN_BRIGHTNESS_STATUS
// });
Log.d(TAG, "系统亮度变化监听已停止");
} catch (error) {
Log.e(TAG, "停止系统亮度变化监听失败: " + error);
}
}
// 兼容旧版API的方法
getBrightness(): number {
const brightness = this.mainWindow?.getWindowProperties().brightness;
if (brightness !== undefined && brightness >= 0) {
return brightness;
}
// 首次未获取到窗口亮度时返回系统设置的亮度
let result: number;
try {
// 从系统设置中获取亮度值
let value = settings.getValueSync(
this.abilityPluginBinding?.getAbility().context,
settings.display.SCREEN_BRIGHTNESS_STATUS,
'100',
settings.domainName.DEVICE_SHARED
);
result = parseFloat(value) / 255;
Log.d(TAG, `获取系统亮度成功: ${result}`);
} catch (err) {
result = 1.0;
Log.e(TAG, "获取系统亮度失败: " + err);
}
return result;
}
}
最后在插件的入口目录screen_brightness引入平台包

鸿蒙平台实现原理是根据华为官网的api文档进行操作的,也兼容了部分旧的接口

测试用例里面也了部分方法,可以正在跑起来,本文所写的代码已经开源。
https://gitcode.com/astevencui/screen_brightness