欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

本文基于flutter3.27.5开发

在这里插入图片描述

一、screen 库概述

屏幕亮度控制和保持屏幕唤醒是移动应用的常见需求,用于阅读器、视频播放、导航等场景。在 Flutter for OpenHarmony 应用开发中,screen 是一个轻量级的屏幕控制插件,提供了跨平台的亮度和唤醒控制能力。

screen 库特点

screen 库基于 Flutter 平台接口实现,提供了以下核心特性:

亮度控制:支持获取和设置屏幕亮度,可实现阅读器护眼模式、视频播放亮度调节等功能。

保持唤醒:支持保持屏幕常亮,防止屏幕自动休眠,适用于导航、视频播放、阅读等场景。

简洁 API:提供简单直观的静态方法,无需实例化对象即可使用。

跨平台支持:统一的 API 设计,支持 Android、iOS、OpenHarmony 等多个平台。

功能支持对比

功能 Android iOS OpenHarmony
获取亮度
设置亮度
获取唤醒状态
设置唤醒状态

使用场景:电子书阅读器、视频播放器、导航应用、倒计时应用、展示类应用等。


二、安装与配置

2.1 添加依赖

在项目的 pubspec.yaml 文件中添加 screen 依赖:

dependencies:
  screen:
    git:
      url: https://atomgit.com/openharmony-sig/fluttertpc_screen.git

然后执行以下命令获取依赖:

flutter pub get

2.2 权限配置

在 OpenHarmony 项目中,控制屏幕亮度通常不需要特殊权限,但如果需要修改系统亮度设置,可能需要相应权限。打开 ohos/entry/src/main/module.json5 文件确认权限配置。


三、核心 API 详解

3.1 Screen 类

Screen 是屏幕控制的核心类,提供静态方法控制亮度和唤醒状态。

class Screen {
  static const MethodChannel _channel = 
      const MethodChannel('github.com/clovisnicolas/flutter_screen');

  static Future<double> get brightness async;
  static Future setBrightness(double brightness);
  static Future<bool> get isKeptOn async;
  static Future keepOn(bool on);
}

3.2 brightness 属性

brightness 属性用于获取当前屏幕亮度。

static Future<double> get brightness async

返回值:返回当前屏幕亮度值,范围 0.0 ~ 1.0。

说明

  • 如果应用设置了自定义亮度,返回应用设置的亮度值
  • 如果应用使用系统亮度,返回系统当前亮度值(已转换为 0.0 ~ 1.0 范围)

使用示例

double currentBrightness = await Screen.brightness;
print('当前亮度: $currentBrightness');

3.3 setBrightness 方法

setBrightness 方法用于设置屏幕亮度。

static Future setBrightness(double brightness)

参数

参数 类型 说明
brightness double 亮度值,范围 0.0 ~ 1.0

说明

  • 设置的亮度仅对当前应用窗口生效
  • 不会修改系统全局亮度设置
  • 退出应用后亮度设置会自动恢复

使用示例

await Screen.setBrightness(0.5);
await Screen.setBrightness(1.0);
await Screen.setBrightness(0.0);

3.4 isKeptOn 属性

isKeptOn 属性用于获取屏幕是否保持唤醒状态。

static Future<bool> get isKeptOn async

返回值:返回 true 表示屏幕保持唤醒,false 表示正常休眠。

使用示例

bool isKeptOn = await Screen.isKeptOn;
print('屏幕保持唤醒: $isKeptOn');

3.5 keepOn 方法

keepOn 方法用于设置屏幕是否保持唤醒。

static Future keepOn(bool on)

参数

参数 类型 说明
on bool true 保持唤醒,false 允许休眠

说明

  • 设置为 true 后,屏幕将保持常亮,不会自动休眠
  • 设置为 false 后,恢复正常的屏幕超时行为
  • 退出应用后设置会自动恢复

使用示例

await Screen.keepOn(true);
await Screen.keepOn(false);

四、数据类型详解

4.1 亮度值范围

说明
0.0 最低亮度
0.5 中等亮度
1.0 最高亮度

4.2 唤醒状态

说明
true 屏幕保持唤醒
false 屏幕正常休眠

五、OpenHarmony 平台实现原理

5.1 原生 API 映射

Flutter API OpenHarmony API
brightness window.getWindowProperties().brightness
setBrightness window.setWindowBrightness()
isKeptOn window.getWindowProperties().isKeepScreenOn
keepOn window.setWindowKeepScreenOn()

5.2 亮度控制实现

OpenHarmony 使用 window 模块控制窗口亮度:

onMethodCall(call: MethodCall, result: MethodResult): void {
  switch (call.method) {
    case "brightness":
      result.success(this.getBrightness());
      break;
    case "setBrightness":
      this.mainWindow?.setWindowBrightness(
        parseFloat(call.argument("brightness"))
      );
      result.success(null);
      break;
  }
}

getBrightness(): number {
  const brightness = this.mainWindow?.getWindowProperties().brightness;
  if (brightness && brightness >= 0) {
    return brightness;
  }
  let value = settings.getValueSync(
    this.context,
    settings.display.SCREEN_BRIGHTNESS_STATUS,
    '100',
    settings.domainName.DEVICE_SHARED
  );
  return parseFloat(value) / 255;
}

5.3 唤醒控制实现

case "isKeptOn":
  let flags: boolean = this.mainWindow?.getWindowProperties().isKeepScreenOn || false;
  result.success(flags);
  break;
case "keepOn":
  let on: boolean = call.argument("on");
  if (on) {
    this.mainWindow?.setWindowKeepScreenOn(true);
  } else {
    this.mainWindow?.setWindowKeepScreenOn(false);
  }
  result.success(null);
  break;

5.4 Android 平台实现对比

case "brightness":
  result.success(getBrightness());
  break;
case "setBrightness":
  double brightness = call.argument("brightness");
  WindowManager.LayoutParams layoutParams = 
      activity.getWindow().getAttributes();
  layoutParams.screenBrightness = (float)brightness;
  activity.getWindow().setAttributes(layoutParams);
  result.success(null);
  break;
case "isKeptOn":
  int flags = activity.getWindow().getAttributes().flags;
  result.success((flags & FLAG_KEEP_SCREEN_ON) != 0);
  break;
case "keepOn":
  Boolean on = call.argument("on");
  if (on) {
    activity.getWindow().addFlags(FLAG_KEEP_SCREEN_ON);
  } else {
    activity.getWindow().clearFlags(FLAG_KEEP_SCREEN_ON);
  }
  result.success(null);
  break;

六、MethodChannel 通信协议

6.1 方法列表

方法 参数 返回值 说明
brightness - double 获取屏幕亮度
setBrightness {“brightness”: double} null 设置屏幕亮度
isKeptOn - bool 获取唤醒状态
keepOn {“on”: bool} null 设置唤醒状态

6.2 Channel 名称

const MethodChannel _channel = 
    const MethodChannel('github.com/clovisnicolas/flutter_screen');

七、实战案例

7.1 完整屏幕控制示例

以下示例整合了屏幕亮度和唤醒控制的核心功能,包括:亮度调节滑块、保持唤醒开关、状态显示等。

import 'package:flutter/material.dart';
import 'package:screen/screen.dart';

void main() {
  runApp(const MaterialApp(home: ScreenControlPage()));
}

class ScreenControlPage extends StatefulWidget {
  const ScreenControlPage({super.key});

  
  State<StatefulWidget> createState() => _ScreenControlPageState();
}

class _ScreenControlPageState extends State<ScreenControlPage> {
  double _brightness = 0.5;
  bool _isKeptOn = false;
  bool _isLoading = true;

  
  void initState() {
    super.initState();
    _loadScreenSettings();
  }

  Future<void> _loadScreenSettings() async {
    try {
      final brightness = await Screen.brightness;
      final isKeptOn = await Screen.isKeptOn;
      setState(() {
        _brightness = brightness;
        _isKeptOn = isKeptOn;
        _isLoading = false;
      });
    } catch (e) {
      setState(() {
        _isLoading = false;
      });
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('加载屏幕设置失败: $e')),
        );
      }
    }
  }

  Future<void> _setBrightness(double value) async {
    try {
      await Screen.setBrightness(value);
      setState(() {
        _brightness = value;
      });
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('设置亮度失败: $e')),
        );
      }
    }
  }

  Future<void> _toggleKeepOn(bool value) async {
    try {
      await Screen.keepOn(value);
      setState(() {
        _isKeptOn = value;
      });
    } catch (e) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('设置唤醒状态失败: $e')),
        );
      }
    }
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('屏幕控制')),
      body: _isLoading
          ? const Center(child: CircularProgressIndicator())
          : Padding(
              padding: const EdgeInsets.all(16),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  _buildBrightnessSection(),
                  const SizedBox(height: 24),
                  _buildKeepOnSection(),
                  const SizedBox(height: 24),
                  _buildStatusSection(),
                ],
              ),
            ),
    );
  }

  Widget _buildBrightnessSection() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              children: [
                const Icon(Icons.brightness_6, size: 24),
                const SizedBox(width: 8),
                const Text(
                  '屏幕亮度',
                  style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                ),
                const Spacer(),
                Text(
                  '${(_brightness * 100).toStringAsFixed(0)}%',
                  style: const TextStyle(fontSize: 16),
                ),
              ],
            ),
            const SizedBox(height: 16),
            Slider(
              value: _brightness,
              min: 0.0,
              max: 1.0,
              divisions: 100,
              onChanged: _setBrightness,
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                TextButton.icon(
                  onPressed: () => _setBrightness(0.2),
                  icon: const Icon(Icons.brightness_low),
                  label: const Text('暗'),
                ),
                TextButton.icon(
                  onPressed: () => _setBrightness(0.5),
                  icon: const Icon(Icons.brightness_medium),
                  label: const Text('中'),
                ),
                TextButton.icon(
                  onPressed: () => _setBrightness(1.0),
                  icon: const Icon(Icons.brightness_high),
                  label: const Text('亮'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildKeepOnSection() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          children: [
            const Icon(Icons.screen_lock_portrait, size: 24),
            const SizedBox(width: 8),
            const Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    '保持屏幕唤醒',
                    style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                  ),
                  SizedBox(height: 4),
                  Text(
                    '开启后屏幕将保持常亮',
                    style: TextStyle(fontSize: 14, color: Colors.grey),
                  ),
                ],
              ),
            ),
            Switch(
              value: _isKeptOn,
              onChanged: _toggleKeepOn,
            ),
          ],
        ),
      ),
    );
  }

  Widget _buildStatusSection() {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              '当前状态',
              style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 12),
            _buildStatusRow('亮度值', _brightness.toStringAsFixed(2)),
            _buildStatusRow('亮度百分比', '${(_brightness * 100).toStringAsFixed(0)}%'),
            _buildStatusRow('唤醒状态', _isKeptOn ? '保持唤醒' : '正常休眠'),
          ],
        ),
      ),
    );
  }

  Widget _buildStatusRow(String label, String value) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(label, style: const TextStyle(color: Colors.grey)),
          Text(value, style: const TextStyle(fontWeight: FontWeight.w500)),
        ],
      ),
    );
  }
}

代码要点说明

功能模块 实现方式
亮度获取 Screen.brightness 获取当前亮度值
亮度设置 Screen.setBrightness(double) 设置亮度
唤醒状态获取 Screen.isKeptOn 获取当前唤醒状态
唤醒状态设置 Screen.keepOn(bool) 设置唤醒状态
错误处理 try-catch 捕获异常并显示提示
状态管理 initState 中加载初始状态

八、常见问题与解决方案

8.1 亮度设置无效

问题:调用 setBrightness 后屏幕亮度没有变化。

解决方案

  1. 确保亮度值在 0.0 ~ 1.0 范围内
  2. 检查设备是否支持亮度调节
  3. 某些设备可能需要用户手动授权
Future<void> setBrightnessSafely(double value) async {
  if (value < 0.0 || value > 1.0) {
    throw ArgumentError('亮度值必须在 0.0 到 1.0 之间');
  }
  await Screen.setBrightness(value.clamp(0.0, 1.0));
}

8.2 保持唤醒不生效

问题:调用 keepOn(true) 后屏幕仍然会休眠。

解决方案

  1. 确保应用在前台运行
  2. 检查设备的省电模式设置
  3. 某些设备可能限制了后台应用的唤醒权限

8.3 退出应用后设置未恢复

问题:退出应用后亮度或唤醒状态没有恢复。

解决方案

在应用退出时手动恢复设置:

class ScreenManager {
  static double? _originalBrightness;
  static bool? _originalKeepOn;

  static Future<void> saveOriginalSettings() async {
    _originalBrightness = await Screen.brightness;
    _originalKeepOn = await Screen.isKeptOn;
  }

  static Future<void> restoreOriginalSettings() async {
    if (_originalBrightness != null) {
      await Screen.setBrightness(_originalBrightness!);
    }
    if (_originalKeepOn != null) {
      await Screen.keepOn(_originalKeepOn!);
    }
  }
}

8.4 获取亮度返回系统亮度

问题:设置亮度后,再次获取返回的是系统亮度而非应用设置值。

解决方案

这是正常行为,应用设置的亮度仅对当前窗口生效。如果需要记住用户设置,可以自行缓存:

class BrightnessManager {
  static double _currentBrightness = 0.5;

  static double get currentBrightness => _currentBrightness;

  static Future<void> setBrightness(double value) async {
    await Screen.setBrightness(value);
    _currentBrightness = value;
  }
}

九、与其他库对比

特性 screen screen_brightness wakelock
亮度控制
保持唤醒
API 复杂度 简单 中等 简单
OpenHarmony 支持
维护状态 社区维护 活跃开发 活跃开发

建议

  • 需要同时控制亮度和唤醒:使用 screen
  • 只需要亮度控制:可考虑 screen_brightness
  • 只需要保持唤醒:可考虑 wakelock

十、总结

screen 库为 Flutter for OpenHarmony 提供了简洁的屏幕控制能力,支持亮度调节和保持唤醒功能。API 设计简单直观,适合快速集成到阅读器、播放器等应用中。

核心要点

  1. 使用静态方法直接调用,无需实例化
  2. 亮度值范围为 0.0 ~ 1.0
  3. 设置仅对当前应用窗口生效
  4. 退出应用后设置自动恢复
  5. 建议在应用启动时保存原始设置

最佳实践

  • 在应用启动时保存原始亮度设置
  • 提供亮度预设值(暗、中、亮)方便用户选择
  • 视频播放时自动保持屏幕唤醒
  • 阅读器应用提供护眼亮度模式
  • 处理异常情况,提供友好的错误提示
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐