KeepAwake 保持唤醒扩展
下载
.aix拓展文件:
de.ullisroboterseite.ursai2keepawake.aix
.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
原则上,有三种使用场景:
- 在特定时间(也可以定期)应该运行某些操作,例如记录和保存测量值
- 应用程序应该对外部事件做出反应,例如注意传入的MQTT消息
- 显示屏不应变暗,例如显示食谱时
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
有不同的方法来设置各种锁。AquireFullWakeLock、AquireScreenBrightWakeLock和AquireScreenDimWakeLock获取名称中指定的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。如果请求第二个,任何已使用的锁将首先被清除。
AcquireCausesWakeup、OnAfterRelease和EnableShowOnLockScreen属性影响设置或清除锁时应用程序的行为。
任何类型的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
使用AquirePartialWakeLock或AquirePartialWakeLockFromNotification函数时,扩展会创建一个通知通道。通道对用户可见的属性由ChannelName和ChannelDescription属性定义。通道在首次调用这两个函数之一时创建。
没有单独的函数来更新通道数据。属性更改会立即反映在通道中。这两个属性也在设计器中可用。这意味着每次启动应用程序时都会检查和更新此数据。因此,如果需要更改ChannelName或ChannelDescription,只需在设计器中调整数据并重新编译应用程序。一旦应用程序在设备上更新,下次启动应用程序时会自动更新通道详细信息。ChannelImportance定义了显示通知的条件。
如果您不希望应用程序通过内部创建的通道处理通知,可以使用DeleteChannel函数删除它。
内部创建的通道的ChannelId是常量KEEPAWAKE。
如果扩展的简单选项不足以定义通知属性,还可以集成UrsAI2Notifier扩展。UrsAI2NotificationChannel扩展为设计通知通道提供了高级选项。有关详细信息,请参阅此扩展的文档。然后使用UrsAI2NotificationChannel扩展的属性和函数管理通道数据。AquirePartialWakeLockEx和AquirePartialWakeLockFromChannel函数允许通过UrsAI2NotificationChannel对象指定通道。
Notification
⚠️ 注意:通知的显示方式很大程度上取决于设备制造商对此功能的实现。例如,在我的运行Android 13的TE Blade A73上,无法设置或更改图标。始终显示应用程序启动器图标。
当请求PARTIAL_WAKE_LOCK锁时,必须生成用户可见的通知。使用AquirePartialWakeLock或AquirePartialWakeLockFromChannel函数时,此扩展会生成一个简单的通知。NotificationTitle、NotificationText和NotificationIcon或NotificationIconAsset属性定义此通知的外观。

有两种方法可以定义要创建的通知的图标。NotificationIconAsset属性可用于集成的上传图像文件(App Inventor中的Media部分)。或者,您可以使用系统图标之一。为此,将NotificationIcon属性设置为系统图标资源的名称。图标列表可以在这里找到。NotificationIconAsset属性覆盖NotificationIcon属性。
更改这些属性对已活动的通知没有影响。它们仅用作此扩展创建新通知的规范,即当提出新的相应WakeLock锁请求时。
如果扩展的简单选项不足以定义通知属性,可以集成UrsAI2Notifier扩展。UrsNotification和UrsIntent扩展为设计通知和相关操作提供了高级选项。有关详细信息,请参阅这些扩展的文档。然后使用UrsNotification扩展的属性和函数管理通知数据。
AquirePartialWakeLockEx和AquirePartialWakeLockFromNotification方法分别接受UrsNotification和UrsIntent扩展的实例来定义通知属性和要执行的操作。可以使用所有功能(BigPicture、LargeIcon、AddActionButton、Create(用于修改)等)。通知属性然后由传递的对象管理。
您可能会通过通知搞乱backstack。这可能导致App Inventor中的流控制问题(参见关于BackStack的信息)。
修改当前通知
对于已活动的通知,无论是内部生成还是由UrsNotification对象定义的,都可以使用CurrentNotificationTitle、CurrentNotificationText和CurrentNotificationIcon属性读取和修改属性标题、文本和图标。这些更改不影响用于创建新通知的NotificationTitle、NotificationTitle和NotificationIcon属性。
通知操作 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

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

KeepAwake_Notification

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

UPDReceiver


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


扫码添加客服咨询