flutter鸿蒙扩展screen_brightness实现屏幕亮度调节

随着华为鸿蒙操作系统(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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值