KeepAwake 保持唤醒扩展:防止App被操作系统停用

KeepAwake 保持唤醒扩展

下载

.aix拓展文件:

de.ullisroboterseite.ursai2keepawake.aix

.aia示例文件:

UrsKeepAwakeServiceTest.aia

KeepAwake_Notification.aia

UPDReceiver.aia

版本历史

版本 修改内容
1.0 (2024-10-28) 初始版本
1.1 (2024-11-03) 内部调整

⚠️ 重要警告:使用此扩展将显著缩短设备电池寿命。如果确实不需要,不要设置WakeLocks,尽可能少地使用它们,并尽快释放它们。

⚠️ 注意:如果只需要偶尔执行操作,CPU不需要持续活动。可以使用闹钟代替(参见 UrsAI2Alarm)。

动机

对于某些项目,有必要防止相关应用程序被操作系统停用。典型例子是传感器数据应定期发送到MQTT代理。

从6.0版本(Marshmallow)开始,Android引入了Doze模式来优化电池寿命。当没有应用程序使用时,此功能会逐渐关闭所有功能(显示、CPU、WiFi等)。使用此处描述的扩展,您可以确保CPU不会关闭,应用程序在很长时间内保持活动。

在ZEBRA开发者门户可以找到很多有用的背景信息:Keeping your Android application running when the device wants to sleep

测试结果

测试程序在多个设备上进行了测试:

设备 结果
智能手机 Samsung A02s, Android 12 按预期工作
平板 Yestel T13_EEA, Android 13 按预期工作
智能手机 ZTE Blade A73, Android 13 按预期工作
智能手机 Redmi 5 Plus, Android 8.1 按预期工作

WakeLock

原则上,有三种使用场景:

  1. 在特定时间(也可以定期)应该运行某些操作,例如记录和保存测量值
  2. 应用程序应该对外部事件做出反应,例如注意传入的MQTT消息
  3. 显示屏不应变暗,例如显示食谱时

Android为这些情况提供以下解决方案:

  • AlarmManager类允许您在特定时间唤醒设备并执行代码。如果需要重复,可以重复启动闹钟。这相当可靠。当应用程序在前台或后台运行时,闹钟会被执行。甚至可以确保闹钟在应用程序关闭或设备切换到待机状态时被触发。闹钟可以通过UrsAI2Alarm扩展设置。

  • 下面描述如何通过设置Android使电池优化大部分关闭(见下面的电池优化设置)。但在较新的Android版本中,这不足以使设备永久保持活动状态。

  • 为了使CPU永久保持活动状态,有必要设置WakeLock。在Android中有四种WakeLock类型:

    • FULL_WAKE_LOCK:只要设置了这个WakeLock,屏幕和键盘背光就会保持全亮度,即使应用程序不再是前台应用程序。CPU和WiFi保持活动状态。只有当用户按下电源按钮并且设备切换到待机模式时,系统才隐式释放FULL_WAKE_LOCK锁。这会关闭屏幕和CPU(与PARTIAL_WAKE_LOCK相反)。当用户重新打开设备时,会恢复旧状态。

    • SCREEN_BRIGHT_WAKE_LOCK:与FULL_WAKE_LOCK相同,但键盘灯会在一段不活动时间后关闭。

    • SCREEN_DIM_WAKE_LOCK:同上。系统也被允许调暗屏幕。

    • PARTIAL_WAKE_LOCK:此WakeLock与其他类型的行为不同。它确保CPU继续运行。屏幕和键盘背光可以关闭。自Android 6.2以来,除了PARTIAL_WAKE_LOCK锁外,还必须设置ForegroundService。这与通知相关联。此通知向用户显示电池优化已关闭,设备不会切换到待机模式。

注意:Android已多次更改其电源管理策略。此外,不同设备制造商有时以不同方式实现这些功能。因此,务必测试此处提供的信息是否适用于您自己的项目。上述WakeLock的行为已通过各种设备进行了测试(参见测试结果)。

WifiLock

WakeLock不能防止网络连接在特定时间后被切断。为此有WifiLock。它使应用程序能够保持WiFi连接处于活动状态。通常,如果用户在较长时间内没有使用设备,WiFi硬件会关闭。如果设置了WifiLock,硬件将保持打开状态,直到锁被移除。

电池优化

电池优化通常按以下方式工作:

  • 限制后台活动:限制未主动使用的应用程序,即处于后台的应用程序,以减少能耗
  • 处理器性能调整:处理器被节流以节省能源
  • 停用不必要功能:不需要时停用蓝牙、WLAN或GPS等功能

何时应该停用电池优化?

虽然电池优化在大多数情况下是有益的,但有时可能导致某些应用程序出现问题。如果应用程序运行不正常,可以临时为此应用程序停用电池优化。

前台服务 Foreground-Service

服务用于在后台执行较长时间的功能。这使应用程序保持响应状态。ForegroundService的特殊功能是显示通知。因此称为Foreground。显示的通知向用户告知后台活动的状态,并给用户影响后台活动的选项。

PARTIAL_WAKE_LOCK防止设备在非活动时切换到待机模式以节省电池功耗。根据Android指南,必须在用户被告知的情况下才能这样做。因此,除了WakeLock外,还必须设置ForegroundService。其可见通知向用户显示应用程序仍处于活动状态并消耗电力。

在此扩展中,ForegroundService没有特殊功能。此服务的唯一目的是激活WakeLock并通知用户电池优化已停用,设备不会切换到待机模式。

ForegroundService仅在使用PARTIAL-WAKE-LOCK时才需要。使用其他WakeLock类型时,用户可以通过屏幕不关闭来识别缺少关闭功能。

⚠️ 注意:服务必须在清单文件中声明。这在Companion(App Inventor和Kodular)中缺少。因此UrsAI2KeepAwake在Companion中不起作用。

使用方法

请求 WakeLock

有不同的方法来设置各种锁。AquireFullWakeLockAquireScreenBrightWakeLockAquireScreenDimWakeLock获取名称中指定的WakeLock。设置PARTIAL_WAKE_LOCK锁时,必须考虑与ForegroundService关联的通知:

  • AquirePartialWakeLock:请求PARTIAL_WAKE_LOCK锁。通知通道、通知和点击通知时要执行的操作通过扩展的属性定义。有关详细信息,请参阅通知/通知通道部分。由于PARTIAL_WAKE_LOCK在没有ForegroundService的情况下无用,因此在创建WakeLock时会自动启动ForegroundService。

  • AquirePartialWakeLockFromNotification:通知属性和点击通知时要执行的操作通过UrsNotification和UrsIntent扩展的实例定义。通知通道信息通过扩展的属性定义。

  • AquirePartialWakeLockFromChannel:通知的属性和点击通知时要执行的操作通过扩展的属性定义。通知通道信息通过UrsAI2NotificationChannel扩展的实例定义。

  • AquirePartialWakeLockEx:通知属性和点击通知时要执行的操作通过UrsNotification和UrsIntent扩展的实例定义。通知通道信息通过UrsAI2NotificationChannel扩展的实例定义。

重要:每个扩展实例只能请求一个WakeLock。如果请求第二个,任何已使用的锁将首先被清除。

AcquireCausesWakeupOnAfterReleaseEnableShowOnLockScreen属性影响设置或清除锁时应用程序的行为。

任何类型的WakeLock都使用ReleaseWakeLock函数释放。

IsWakeLockActive属性可用于查询是否已设置WakeLock锁。WakeLockType属性提供有关当前活动锁类型的信息。

多个 WakeLocks

在极少数情况下,如果设置了FULL_WAKE_LOCK、SCREEN_BRIGHT_WAKE_LOCK或FULL_WAKE_LOCK锁,可能需要即使在用户想要将设备置于待机模式(即用电源按钮关闭屏幕)时CPU继续运行。不幸的是,无法简单地检测关闭过程,也无法将任务传递给App Inventor中的ForegroundService。

在这种情况下,使用扩展的两个实例是有意义的,在一个实例上设置FULL_WAKE_LOCK锁,在另一个实例上设置PARTIAL_WAKE_LOCK锁。请注意,扩展只能为所有实例(甚至在多个屏幕之间)安装单个共享前台服务。因此,一次只能由一个实例请求PARTIAL_WAKE_LOCK!当一个已激活时请求PARTIAL_WAKE_LOCK将导致错误。

通知 / 通知通道

在较新版本的Android中,通知必须分配给NotificationChannel。当启动ForegroundService时,如果需要,扩展会创建一个简单的通知和通知通道。

NotificationChannel

使用AquirePartialWakeLockAquirePartialWakeLockFromNotification函数时,扩展会创建一个通知通道。通道对用户可见的属性由ChannelNameChannelDescription属性定义。通道在首次调用这两个函数之一时创建。

没有单独的函数来更新通道数据。属性更改会立即反映在通道中。这两个属性也在设计器中可用。这意味着每次启动应用程序时都会检查和更新此数据。因此,如果需要更改ChannelNameChannelDescription,只需在设计器中调整数据并重新编译应用程序。一旦应用程序在设备上更新,下次启动应用程序时会自动更新通道详细信息。ChannelImportance定义了显示通知的条件。

如果您不希望应用程序通过内部创建的通道处理通知,可以使用DeleteChannel函数删除它。

内部创建的通道的ChannelId是常量KEEPAWAKE

如果扩展的简单选项不足以定义通知属性,还可以集成UrsAI2Notifier扩展。UrsAI2NotificationChannel扩展为设计通知通道提供了高级选项。有关详细信息,请参阅此扩展的文档。然后使用UrsAI2NotificationChannel扩展的属性和函数管理通道数据。AquirePartialWakeLockExAquirePartialWakeLockFromChannel函数允许通过UrsAI2NotificationChannel对象指定通道。

Notification

⚠️ 注意:通知的显示方式很大程度上取决于设备制造商对此功能的实现。例如,在我的运行Android 13的TE Blade A73上,无法设置或更改图标。始终显示应用程序启动器图标。

当请求PARTIAL_WAKE_LOCK锁时,必须生成用户可见的通知。使用AquirePartialWakeLockAquirePartialWakeLockFromChannel函数时,此扩展会生成一个简单的通知。NotificationTitleNotificationTextNotificationIconNotificationIconAsset属性定义此通知的外观。

简单通知元素

有两种方法可以定义要创建的通知的图标。NotificationIconAsset属性可用于集成的上传图像文件(App Inventor中的Media部分)。或者,您可以使用系统图标之一。为此,将NotificationIcon属性设置为系统图标资源的名称。图标列表可以在这里找到。NotificationIconAsset属性覆盖NotificationIcon属性。

更改这些属性对已活动的通知没有影响。它们仅用作此扩展创建新通知的规范,即当提出新的相应WakeLock锁请求时。

如果扩展的简单选项不足以定义通知属性,可以集成UrsAI2Notifier扩展。UrsNotification和UrsIntent扩展为设计通知和相关操作提供了高级选项。有关详细信息,请参阅这些扩展的文档。然后使用UrsNotification扩展的属性和函数管理通知数据。

AquirePartialWakeLockExAquirePartialWakeLockFromNotification方法分别接受UrsNotification和UrsIntent扩展的实例来定义通知属性和要执行的操作。可以使用所有功能(BigPicture、LargeIcon、AddActionButton、Create(用于修改)等)。通知属性然后由传递的对象管理。

您可能会通过通知搞乱backstack。这可能导致App Inventor中的流控制问题(参见关于BackStack的信息)。

修改当前通知

对于已活动的通知,无论是内部生成还是由UrsNotification对象定义的,都可以使用CurrentNotificationTitleCurrentNotificationTextCurrentNotificationIcon属性读取和修改属性标题、文本和图标。这些更改不影响用于创建新通知的NotificationTitleNotificationTitleNotificationIcon属性。

通知操作 Intent

通知通常与点击时要执行的操作相关联。这通过Intent指定。Android使用Intent对象向系统发送命令。Intent包含执行指定操作所需的所有信息。例如,AI2的ActivityStarter在内部使用Intents来启动其他应用程序。

传递给CreateNotification函数的Intent对象用于指定点击通知时要执行的操作。

此组件是属性的集合。它既没有函数也没有事件。

ActionType指定使用Intent触发哪个操作:

  • Screen:点击通知时,打开应用程序的指定屏幕
  • Launcher:点击通知将打开任何应用程序。另请参阅App Inventor的ActivityStarter文档

S标记与ActionType Screen相关的字段,列L标记与ActionType Launcher相关的字段。

电池优化

此扩展提供以下属性和方法来管理电池优化:

  • IsIgnoringBatteryOptimizations:检查应用程序是否正在忽略电池优化
  • RequestIgnoreBatteryOptimizations:请求忽略电池优化
  • OpenBatteryOptimizationSettings:打开电池优化设置

请求 WiFi Lock

使用AcquireWifiLock函数获取WiFiLock,使用ReleaseWifiLock函数释放WiFiLock。

参考

属性 Properties

获取时唤醒 AcquireCausesWakeup
设置此属性为true会导致在获取WakeLock时唤醒设备。
通道描述 ChannelDescription
定义通知通道的描述文本。
通道重要性 ChannelImportance
定义通知通道的重要性级别(1-5)。
通道名称 ChannelName
定义通知通道的名称。
当前通知图标 CurrentNotificationIcon
获取当前活动通知的图标。
当前通知文本 CurrentNotificationText
获取当前活动通知的文本。
当前通知标题 CurrentNotificationTitle
获取当前活动通知的标题。
启用锁屏显示 EnableShowOnLockScreen
设置此属性为true时,启用在锁屏上显示应用程序的能力。
是否忽略电池优化 IsIgnoringBatteryOptimizations
返回应用程序是否正在忽略电池优化。
WakeLock是否活动 IsWakeLockActive
返回是否已设置WakeLock锁。
WiFiLock是否活动 IsWifiLockActive
返回是否已设置WiFiLock。
通知图标 NotificationIcon
定义通知的系统图标资源名称。
通知图标资源 NotificationIconAsset
定义通知的上传图像资源名称。
通知文本 NotificationText
定义通知的文本内容。
通知标题 NotificationTitle
定义通知的标题。
释放后执行 OnAfterRelease
设置为true时,在释放WakeLock后执行相关操作。
WakeLock类型 WakeLockType
返回当前活动WakeLock的类型(1-4)。

事件 Events

释放后 AfterRelease(请求代码)
WakeLock被释放后触发。

方法 Methods

获取完整唤醒锁 AquireFullWakeLock()
获取FULL_WAKE_LOCK,保持屏幕、键盘背光、CPU和WiFi活动。
获取部分唤醒锁 AquirePartialWakeLock()
获取PARTIAL_WAKE_LOCK,仅保持CPU活动。需要前台服务。
从通道获取部分唤醒锁 AquirePartialWakeLockFromChannel(通知通道对象)
使用指定的通知通道对象获取PARTIAL_WAKE_LOCK。
从通知获取部分唤醒锁 AquirePartialWakeLockFromNotification(通知对象,意图对象)
使用指定的通知和意图对象获取PARTIAL_WAKE_LOCK。
获取扩展部分唤醒锁 AquirePartialWakeLockEx(通知通道对象,通知对象,意图对象)
使用指定的通知通道、通知和意图对象获取PARTIAL_WAKE_LOCK。
获取屏幕明亮唤醒锁 AquireScreenBrightWakeLock()
获取SCREEN_BRIGHT_WAKE_LOCK,保持屏幕明亮和CPU活动。
获取屏幕调暗唤醒锁 AquireScreenDimWakeLock()
获取SCREEN_DIM_WAKE_LOCK,允许屏幕调暗并保持CPU活动。
获取WiFi锁 AcquireWifiLock()
获取WiFiLock以保持WiFi连接活动。
删除通道 DeleteChannel()
删除内部创建的通知通道。
打开电池优化设置 OpenBatteryOptimizationSettings()
打开电池优化设置页面。
释放唤醒锁 ReleaseWakeLock()
释放当前活动的WakeLock。
释放WiFi锁 ReleaseWifiLock()
释放当前活动的WiFiLock。
请求忽略电池优化 RequestIgnoreBatteryOptimizations()
请求系统忽略应用程序的电池优化。

错误代码

错误代码 含义
18001 扩展实例ID无效
18002 WakeLock类型无效
18003 PARTIAL_WAKE_LOCK已激活
18004 WakeLock未激活
18005 WiFiLock类型无效
18006 WiFiLock未激活

示例

UrsKeepAwakeServiceTest

KeepAwake服务测试

演示前台服务和PARTIAL_WAKELOCK使用的基本示例。

KeepAwake测试应用界面

KeepAwake_Notification

KeepAwake通知测试

展示如何结合通知功能使用KeepAwake扩展。

KeepAwake通知屏幕

UPDReceiver

UDP接收器示例

接收器界面

演示在后台保持网络连接的示例。

示例应用2界面

示例应用2通知


原文链接

原版英文文档:Ullis Roboter Seite - AI2 KeepAwake

文档反馈