Alarm 闹钟扩展:在指定时间启动App的强大工具

« 返回首页

Alarm 闹钟扩展

下载

.aix拓展文件:

de.ullisroboterseite.ursai2alarm.aix

.aia示例文件:

UrsAlarmTest.aia

版本历史

版本 修改内容
1.0 (2021-04-26) 初始版本
2.0 (2021-05-15) 当包名更改时,ScreenToOpen 在Kodular上无法工作
2.1 (2021-06-12) - AlarmIntent 中的 FlagNewTask 属性未正确设置。从Android 10开始,此标志必须设置为 true 才能从闹钟启动新活动
- AlarmIntent 中的 FlagNewTask 属性默认值更改为 true
- 方法 CreateAlarm... 中的 WakeUp 参数未正确评估
2.2 (2021-07-21) 在较长的闹钟时间且屏幕关闭时,闹钟无法可靠唤醒设备:
- 闹钟接收器设置WakeLock以获得足够时间启动计划的活动
- EnableShowOnLockScreen 方法启用在锁屏上显示的功能
参见”要启动活动的规则”部分
2.3 (2022-10-13) 适配SDK31(Android 12):
所有 PendingIntent 都获得 FLAG_IMMUTABLE 标志
请求 android.permission.SCHEDULE_EXACT_ALARM 权限
捕获全局异常并写入日志

动机

尽管Android文档强烈建议使用通知(参见 developer.android.com),但在某些情况下,仍然需要在特定时间启动应用程序。使用此扩展,可以在指定时间启动应用程序。如果您想定时生成通知,必须使用扩展 UrsAI2Notifier

⚠️ 重要提示

Android 10及以上版本用户注意:

在闹钟时间,扩展的一个类在后台启动。从Android 10开始,如果应用程序想在后台运行时启动另一个应用程序,需要额外的权限 (SYSTEM_ALERT_WINDOW)(参见 从后台启动活动的限制,最后一点)。此权限无法通过程序设置,必须通过对话框由用户确认(参见 Android 10和小米设备的额外权限)。示例中展示了解决此问题的可能方案。

为了启动新活动,`AlarmIntent` 中的 `FlagNewTask` 属性必须设置为 true!

小米设备制造商用户注意:

在闹钟时间,扩展的一个类在后台启动。对于小米设备,无论安装的Android版本如何,如果应用程序想在后台运行时启动另一个应用程序,都需要额外的权限。此权限无法通过程序设置,必须通过对话框由用户确认(参见 Android 10和小米设备的额外权限)。程序无法查询是否已授予此权限。示例中展示了解决此问题的可能方案。

使用Android 10及更新版本的小米设备用户必须授予两个权限。

⚠️ 注意:此扩展在AI伴侣中不起作用。闹钟通过广播消息触发。为了使应用程序在关闭时也能接收广播消息,应用程序必须提供广播接收器。此接收器必须在应用程序的清单中声明。这在AI伴侣中无法实现。

使用方法

要通过操作系统执行的任务通过意图(intent)提交。意图是要执行的操作的抽象描述。闹钟时间要执行的操作由这样的意图指定。

扩展包含两个模块:

  • UrsAI2Alarm:提供生成闹钟的属性和方法
  • AlarmIntent:指定闹钟发生时要执行的操作

闹钟 Alarms

UrsAI2Alarm 模块可以生成和删除闹钟。闹钟通过请求代码唯一标识。创建闹钟时,必须指定请求代码,以后可以用来删除闹钟。

不幸的是,Android没有提供找出哪些闹钟仍在等待触发的方法。您必须自己管理这些。通知闹钟测试示例展示了如何做到这一点。

CreateAlarmCreateAlarmEx 在指定的延迟后生成闹钟。Android AlarmManager 即使应用程序关闭也会执行存储的操作。CreateAlarmAt 在特定时间生成闹钟。

CancelAlarm 取消尚未触发的闹钟。

意图 Intents

Android使用Intent对象向系统提交任务。Intent包含执行任务所需的所有信息。例如,AI2的ActivityStarter在内部使用Intents来启动其他应用程序。

传递给CreateAlarm...函数的AlarmIntent对象用于指定闹钟触发时要执行的操作。

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

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

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

要启动活动的规则

为了使应用程序(活动)可靠地唤醒设备,要启动的应用程序必须相应地配备。首先,应用程序必须具有适当的权限。对于小米设备,这必须通过单独的对话框由用户授予(参见下一节)。

然后,启动的活动(在App Inventor中这是Screen)必须请求打开显示,并显示在锁屏上。还必须关闭输入PIN码。这可以通过EnableShowOnLockScreen函数为AI2或Kodular应用程序实现。此外,活动必须设置WakeLock,否则设备将立即返回锁定状态。

如果选择AI2屏幕作为目标,建议为Screen.Initialize事件使用以下代码块:

Screen初始化代码块

Android 10和小米设备的额外权限

注意:使用Android 10及更新版本的小米设备用户必须授予两个权限!

Android 10

从Android 10开始,如果应用程序想在后台运行时启动另一个应用程序,需要额外的权限(SYSTEM_ALERT_WINDOW)(参见 从后台启动活动的限制,最后一点)。此权限无法通过程序设置,必须通过对话框由用户确认(参见 Android 10和小米设备的额外权限)。

扩展提供了CheckBackgroundLaunchPermission方法。该方法检查安装的Android版本是否具有API级别29(Android 10)或更高,以及是否已授予SYSTEM_ALERT_WINDOW权限。如果需要授予权限,将打开授予权限的对话框:

德语变体 英语变体
德语变体 英语变体

权限请求的结果通过AfterBackgroundPermssion事件返回。关闭授权对话框后,权限的新状态不会立即可用。因此,事件在关闭对话框后短时间延迟后触发(属性PermissionDelay,默认500毫秒)。在此期间,权限的状态未定义。建议确保不显示无意义的数据或在此期间不能进行有问题的输入。最好将所有相关的屏幕元素放入VerticalArrangement。这可以暂时切换为不可见,或者通过UrsAI2ComponentGroup扩展的EnableArrangement方法禁用(参见下面的示例)。

有关此权限的进一步详细处理,您可以使用:

  • 属性VersionSDK:返回安装的API级别(Android 10为29)
  • 属性CanDrawOverlays:返回是否已授予SYSTEM_ALERT_WINDOW权限
  • 属性CanLaunchFromBackground:返回此应用程序在后台运行时是否可以启动其他应用程序,即API级别小于29或已授予SYSTEM_ALERT_WINDOW权限

小米设备

对于小米设备,无论安装的Android版本如何,如果应用程序想在后台运行时启动另一个应用程序,都需要额外的权限。此权限无法通过程序设置,必须通过对话框由用户确认(参见 Android 10和小米设备的额外权限)。程序无法查询是否已授予此权限。

以下是处理此问题的可用元素:

  • 属性Manufacturer:返回制造商名称(例如 “Xiaomi”)
  • 属性IsXiaomi:返回设备是否来自制造商小米
  • 属性CurrentLanguage:返回设置的语言(”de”、”en” 等参见 ISO 639-1代码列表)。有助于显示相关信息(参见示例)
  • 方法OpenMiuiPermissionEditor:打开特殊的小米权限编辑器

小米权限编辑器:

德语变体 英语变体
德语变体 英语变体

示例项目展示了处理这些权限的一种方法。

您也可以通过设置应用程序获取权限。此博客条目展示了如何操作:在新小米手机上启用”显示弹出窗口”。另一种访问方式:长按应用程序图标,然后选择”应用信息”。

参考

属性 Properties

可绘制覆盖层 CanDrawOverlays
返回是否已授予 SYSTEM_ALERT_WINDOW 权限。
可从后台启动 CanLaunchFromBackground
返回是否允许从后台启动应用程序。
当前语言 CurrentLanguage
返回当前语言,例如 ‘de’ 或 ‘en’(参见 ISO 639-1代码列表)。
是否小米设备 IsXiaomi
返回这是否是小米设备。
制造商 Manufacturer
返回设备的制造商名称。
权限延迟 PermissionDelay
权限对话框关闭后内部请求 CanLaunchFromBackground 的延迟时间(参见 Android 10和小米设备的额外权限)。默认值为500毫秒。
版本 Version
返回扩展的版本名称。
版本SDK VersionSDK
返回运行的Android SDK版本(API级别)。

事件 Events

后台权限后 AfterBackgroundPermssion(结果)
返回 CheckBackgroundLaunchPermission 的结果。权限对话框关闭后有 PermissionDelay 毫秒的延迟(参见 Android 10和小米设备的额外权限)。

方法 Methods

取消闹钟 CancelAlarm(请求代码)
取消尚未触发的闹钟。RequestCode:此闹钟的唯一数字ID。
检查后台启动权限 CheckBackgroundLaunchPermission()
检查是否允许从后台启动应用程序,如果不允许,请求权限。
创建闹钟 CreateAlarm(请求代码,延迟,类型,唤醒,闹钟意图对象)
Delay 指定的延迟后执行由 AlarmIntentObject 定义的操作。

RequestCode:此闹钟的唯一数字ID。
Delay:延迟时间(秒)。
Type:精度指示。WakeUp:时间到期时唤醒设备。AlarmIntentObject:定义闹钟时间要创建的通知的属性。

类型说明Type 的值为0..3。根据 Type 调用不同的方法:

  • 0AlarmManager.set(自API级别1)
    从API 19开始,传递给此方法的触发时间被视为不精确:闹钟不会在此时间之前发送,但可以推迟并在稍后时间发送。
  • 1AlarmManager.setExact(自API级别19)
    闹钟尽可能接近所需时间触发。
  • 2AlarmManager.setAndAllowWhileIdle(自API级别23)
    当系统处于打盹模式时也会触发此闹钟。
  • 3AlarmManager.setExactAndAllowWhileIdle(自API级别23)
    闹钟尽可能接近所需时间触发,并且当系统处于打盹模式时也会触发。

如果当前API级别不足,类型会被调整:1020310

如果 Delay 的值小于零,不会创建通知,并触发 Screen.ErrorOccurred,错误号为17007。

如果 AlarmIntentObject 参数中指定的对象不是 AlarmIntent 类型,不会创建通知,并触发 Screen.ErrorOccurred,错误号为17006。

在指定时间创建闹钟 CreateAlarmAt(请求代码,毫秒时间,类型,唤醒,闹钟意图对象)
Millis 指定的时间执行由 AlarmIntentObject 定义的操作。

RequestCode:此闹钟的唯一数字ID。
Millis:闹钟的时间(自1970年1月1日以来的毫秒数)。
Type:精度指示。WakeUp:时间到期时唤醒设备。AlarmIntentObject:定义闹钟时间要创建的通知的属性。

Type 的值和调整规则与 CreateAlarm 方法相同。

Millis的值可以使用时钟组件的GetMillis方法获取。

获取毫秒时间

如果 Millis 的值小于当前系统时间,不会创建通知,并触发 Screen.ErrorOccurred,错误号为17008。

如果 AlarmIntentObject 参数中指定的对象不是 AlarmIntent 类型,不会创建通知,并触发 Screen.ErrorOccurred,错误号为17006。

创建闹钟扩展 CreateAlarmEx(请求代码,延迟,类型,唤醒,闹钟意图对象)
Delay 指定的延迟后执行由 AlarmIntentObject 定义的操作。返回生成通知的时间。

RequestCode:此闹钟的唯一数字ID。
Delay:延迟时间(秒)。
Type:精度指示。WakeUp:时间到期时唤醒设备。AlarmIntentObject:定义闹钟时间要创建的通知的属性。

返回值:闹钟时间(自1970年1月1日以来的毫秒数)。此值可以传递给时钟组件的MakeInstantFromMillis方法以创建可读的日期时间格式。

从毫秒创建时刻

Type 的值和调整规则与 CreateAlarm 方法相同。

启用锁屏显示 EnableShowOnLockScreen()
启用在锁屏上显示应用程序的能力。如果需要,这会请求必要的权限并显示系统密钥保护对话框。此方法应在应用程序的Screen.Initialize事件中使用。

AlarmIntent参考

⚠️ 注意:从Android 10开始,FlagNewTask 属性必须设置为 true

⚠️ 问题:如果目标不是Screen1并且使用control.close application关闭屏幕,连续生成类型为Screen的意图的闹钟存在问题。原因是App Inventor程序中的内部进程。最好通过闹钟启动Screen1,评估control.get start value参数,并通过control.open another screenScreen1打开请求的屏幕。

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

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

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

属性表格 Properties Table

名称 类型 S L 功能 默认值
ActionType choice
(仅设计器)
X X 指定操作类型。可能的值为 ScreenLauncher。根据 ActionType 评估不同的字段 None
ActivityAction text - X 指定将用于启动 Activity 的操作 -none-
ActivityClass text - X 指定要启动的特定组件的类部分。ActivityPackageActivityClass 定义点击通知时要启动的 Activity -none-
ActivityPackage text - X 指定要启动的特定组件的包部分。ActivityPackageActivityClass 定义点击通知时要启动的 Activity -none-
DataType text - X 指定要传递给Activity的MIME类型 -none-
DataUri text - X 指定将用于启动活动的数据URI -none-
FlagClearTask boolean X X 此标志将导致在活动启动之前清除与该活动关联的任何现有任务 false
FlagClearTop boolean X X 如果设置,并且正在启动的 Activity 已在当前任务中运行,则不会启动该 Activity 的新实例,而是关闭其上方的所有其他活动,并将此 Intent 作为新的 Intent 传递给(现在在顶部的)旧 Activity false
FlagExcludeFromRecent boolean X X 如果设置,新的 Activity 不会保留在最近启动活动的列表中 false
FlagNewTask boolean X X 如果设置,此 Activity 将成为此历史堆栈上新任务的开始。
从Android 10开始,此标志必须设置为 true
false
FlagNoAnimation boolean X X 此标志将阻止系统应用 Activity 过渡动画到下一个活动状态 false
FlagNoHistory boolean X X 如果设置,新的 Activity 不会保留在历史堆栈中。一旦用户离开它,活动即结束 false
FlagPreviousIsTop boolean X X 如果设置并使用此 Intent 从现有活动启动新 Activity,则当前 Activity 将不被视为决定是否应将新 Intent 传递到顶部而不是启动新活动的顶部 Activity。将使用前一个 Activity 作为顶部,假设当前 Activity 将立即完成 false
FlagReorderToFront boolean X X 如果正在运行的 Activity 已在运行,此标志将导致启动的 Activity 被带到其任务历史堆栈的前面 false
FlagResetTaskIfNeeded boolean X X 如果设置,并且此 Activity 要么在新任务中启动,要么将现有任务带到前面,则它将作为任务的前门启动。这将导致应用任何必要的亲和力来使该任务处于适当状态(要么将活动移入或移出,要么只是根据需要将该任务重置为其初始状态) false
FlagSingleTop boolean X X 如果设置,如果 Activity 已在历史堆栈顶部运行,则不会启动 false
FlagTaskOnHome boolean X X 此标志将导致新启动的任务置于当前家庭活动任务(如果有的话)之上。也就是说,从任务按回将始终返回用户到家庭,即使那不是他们看到的最后一个活动。这只能与 FLAG_ACTIVITY_NEW_TASK 结合使用 false
ScreenStartValue text X - 要传输到要打开的 Screen 的启动值。通过 Control.getStartValue 可用 -none-
ScreenToOpen text X - 点击通知时要打开的 Screen 的名称。参见本节开头的说明 “Screen1”

示例

下载压缩包包含一个示例项目:

Alarm测试 UrsAlarmTest

⚠️ 注意:此扩展在AI伴侣中不起作用。闹钟通过广播消息触发。为了使应用程序在关闭时也能发送广播消息,应用程序必须提供广播接收器。此接收器必须在应用程序的清单中声明。这在AI伴侣中无法实现。

屏幕有两个按钮:

  • 闹钟打开URS:创建一个闹钟,延迟10秒后打开标准浏览器并显示 “Ullis Roboter Seite”
  • 闹钟打开Screen2:创建一个闹钟,延迟10秒后打开此应用程序的 Screen2

每次生成闹钟后都会关闭应用程序。因此闹钟在应用程序未打开时执行。

不幸的是,Android没有提供确定哪些闹钟仍在等待的方法。通知闹钟测试示例展示了如何管理闹钟。

AppLauncher扩展的示例展示了如何在Android 10或小米设备上请求特殊权限。

工具

对于开发自己的扩展,我收集了一些提示:AI2 FAQ:开发扩展


原文链接

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

文档反馈