构建 widget 托管应用

Android 主屏幕(在大多数搭载 Android 的设备上可用)可让用户嵌入应用 widget(或 widget),以便快速访问内容。如果您要构建主屏幕替代应用或类似应用,还可以通过实现 AppWidgetHost 让用户嵌入 widget。大多数应用都不需要执行此操作,但如果您要创建自己的宿主,请务必了解宿主隐式同意的合同义务。

本页重点介绍实现自定义 AppWidgetHost 所涉及的职责。如需查看有关如何实现 AppWidgetHost 的具体示例,请参阅 Android 主屏幕 LauncherAppWidgetHost 的源代码。

下面简要介绍了实现自定义 AppWidgetHost 所涉及的关键类和概念:

  • 应用 widget 托管应用:AppWidgetHost 为在其界面中嵌入 widget 的应用提供与 AppWidget 服务的交互。AppWidgetHost 必须具有在宿主自己的软件包中唯一的 ID。此 ID 在主机的所有使用过程中保持不变。该 ID 通常是您在应用中分配的硬编码值。

  • 应用 widget ID:每个 widget 实例在绑定时都会分配一个唯一 ID。请参阅 bindAppWidgetIdIfAllowed(),如需了解详情,请参阅下文中的绑定 widget 部分。主机使用 allocateAppWidgetId() 获取唯一 ID。此 ID 在微件的整个生命周期内保持不变,直到微件从宿主中删除。任何特定于宿主的状态(例如 widget 的大小和位置)都必须由宿主软件包保留,并与应用 widget ID 相关联。

  • 应用 widget 托管视图:将 AppWidgetHostView 视为一个框架,每当需要显示 widget 时,它都会封装在其中。每次 widget 被宿主膨胀时,都会与一个 AppWidgetHostView 相关联。

    • 默认情况下,系统会创建 AppWidgetHostView,但主机可以通过扩展 AppWidgetHostView 来创建自己的子类。
    • 从 Android 12(API 级别 31)开始,AppWidgetHostView 引入了 setColorResources() 和 resetColorResources() 方法,用于处理动态过载的颜色。宿主负责为这些方法提供颜色。
  • 选项 bundle:AppWidgetHost 使用选项 bundle 向 AppWidgetProvider 传达有关 widget 显示方式的信息(例如尺寸范围列表),以及 widget 是在锁定屏幕上还是在主屏幕上。AppWidgetProvider 可以根据微件的显示方式和位置,利用这些信息定制微件的内容和外观。您可以使用 updateAppWidgetOptions() 和 updateAppWidgetSize() 修改 widget 的 bundle。这两种方法都会触发对 AppWidgetProvider 的 onAppWidgetOptionsChanged() 回调。

绑定微件

当用户将 widget 添加到宿主时,会发生一个称为“绑定”的过程。绑定是指将特定应用 widget ID 与特定宿主和特定 AppWidgetProvider 相关联。

借助绑定 API,宿主还可以提供自定义绑定界面。如需使用此流程,您的应用必须在主机的清单中声明 BIND_APPWIDGET 权限:

<uses-permission android:name="android.permission.BIND_APPWIDGET" />

但是,这只是第一步。在运行时,用户必须明确向您的应用授予权限,以允许其向宿主添加 widget。如需测试您的应用是否有权添加该 widget,请使用 bindAppWidgetIdIfAllowed() 方法。如果 bindAppWidgetIdIfAllowed() 返回 false,您的应用必须显示一个对话框,提示用户授予权限:针对当前 widget 添加操作选择“允许”,或针对日后所有 widget 添加操作选择“始终允许”。

以下代码段举例说明了如何显示该对话框:

val intent = Intent(AppWidgetManager.ACTION_APPWIDGET_BIND).apply {
    putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId)
    putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.provider)
    // This is the options bundle described in the preceding section.
    putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options)
}
startActivityForResult(intent, REQUEST_BIND_APPWIDGET)

宿主必须检查用户添加的 widget 是否需要配置。如需了解详情,请参阅让用户能够配置应用 widget。

主持人职责

您可以使用 AppWidgetProviderInfo 元数据为 widget 指定多项配置设置。您可以从与 widget 提供程序关联的 AppWidgetProviderInfo 对象中检索这些配置选项(以下各部分将更详细地介绍这些选项)。

所有主持人均承担以下责任:

  • 添加 widget 时,请按照前文所述分配 widget ID。从宿主中移除 widget 时,请调用 deleteAppWidgetId() 以取消分配 widget ID。

  • 添加 widget 时,请检查是否需要启动配置 activity。通常,如果 widget 的配置 activity 存在,且未通过同时指定 configuration_optional 和 reconfigurable 标志标记为可选,则宿主需要启动该 activity。如需了解详情,请参阅通过配置 activity 更新 widget。对于许多 widget 来说,这是显示之前必须执行的步骤。

  • 微件在 AppWidgetProviderInfo 元数据中指定默认宽度和高度。这些值以单元格(从 Android 12 开始,如果指定了 targetCellWidth 和 targetCellHeight)或 dp(如果仅指定了 minWidth 和 minHeight)为单位进行定义。请参阅微件大小调整属性。

    确保该 widget 的布局至少具有这么多 dp。例如,许多宿主会在网格中对齐图标和 widget。在这种情况下,默认情况下,宿主会使用满足 minWidth 和 minHeight 约束条件的最小单元格数添加 widget。

关于接近方式的提示

除了上一部分中列出的要求之外,请注意以下提示:

选项 bundle 可以包含一个 List<SizeF>,其中包含 widget 实例可以采用的可能尺寸(以 dp 为单位)的列表。提供的尺寸数量取决于主机实现。宿主通常会为手机提供两种尺寸(竖屏和横屏),为可折叠设备提供四种尺寸。

AppWidgetProvider 可向 RemoteViews 提供的不同 RemoteViews 数量上限为 MAX_INIT_VIEW_COUNT (16)。由于 AppWidgetProvider 对象会将 RemoteViews 对象映射到 List<SizeF> 中的每个尺寸,因此请勿提供超过 MAX_INIT_VIEW_COUNT 个尺寸。

当微件以 dp 为单位指定 maxResizeWidth 和 maxResizeHeight 属性时,我们建议使用其中至少一个属性的微件不要超过这些属性指定的大小。

其他资源

  • 请参阅 Glance 参考文档。