构建小部件主机

Android 主屏幕(在大多数 Android 设备上可用)允许用户嵌入应用小部件(或小部件)以快速访问内容。如果您正在构建主屏幕替换或类似的应用,您还可以通过实现AppWidgetHost来允许用户嵌入小部件。这并非大多数应用需要执行的操作,但如果您正在创建自己的主机,则务必了解主机隐式同意的合同义务。

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

以下是实现自定义AppWidgetHost涉及的关键类和概念概述

  • 应用小部件主机AppWidgetHost 为在 UI 中嵌入小部件的应用提供与应用小部件服务的交互。一个AppWidgetHost必须具有在其自身包中唯一的 ID。此 ID 在主机的所有使用中都保持不变。ID 通常是您在应用中分配的硬编码值。

  • 应用小部件 ID:每个小部件实例在绑定时都会分配一个唯一的 ID。请参阅bindAppWidgetIdIfAllowed(),以及更多详细信息,请参阅以下的绑定小部件部分。主机使用allocateAppWidgetId()获取唯一 ID。此 ID 在小部件的生命周期内一直存在,直到它从主机中删除。任何主机特定的状态(例如小部件的大小和位置)都必须由托管包持久化并与应用小部件 ID 关联。

  • 应用小部件主机视图:将AppWidgetHostView视为小部件每次需要显示时都包裹在其中的框架。每次主机加载小部件时,都会将小部件与AppWidgetHostView关联。

    • 默认情况下,系统会创建AppWidgetHostView,但主机可以通过扩展它来创建自己的AppWidgetHostView子类。
    • 从 Android 12(API 级别 31)开始,AppWidgetHostView引入了用于处理动态重载颜色的setColorResources()resetColorResources()方法。主机负责向这些方法提供颜色。
  • 选项捆绑包AppWidgetHost 使用选项捆绑包将信息传达给AppWidgetProvider,关于小部件如何显示(例如,尺寸范围列表)以及小部件是否位于锁屏或主屏幕上。此信息允许AppWidgetProvider根据小部件的显示方式和位置调整小部件的内容和外观。您可以使用updateAppWidgetOptions()updateAppWidgetSize()修改小部件的捆绑包。这两种方法都会触发onAppWidgetOptionsChanged()回调到AppWidgetProvider

绑定小部件

当用户将小部件添加到主机时,会发生一个称为绑定的过程。绑定是指将特定应用小部件 ID 与特定主机和特定AppWidgetProvider关联。

绑定 API 还使主机能够提供用于绑定的自定义 UI。要使用此过程,您的应用必须在主机清单中声明BIND_APPWIDGET权限

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

但这仅仅是第一步。在运行时,用户必须明确授予您的应用权限,以允许它将小部件添加到主机。要测试您的应用是否具有添加小部件的权限,请使用bindAppWidgetIdIfAllowed()方法。如果bindAppWidgetIdIfAllowed()返回false,则您的应用必须显示一个对话框,提示用户授予权限:“允许”当前的小部件添加,或“始终允许”以涵盖所有未来的小部件添加。

此代码段提供了一个如何显示对话框的示例

Kotlin

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

Java

Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.componentName);
// This is the options bundle described in the preceding section.
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
startActivityForResult(intent, REQUEST_BIND_APPWIDGET);

主机必须检查用户添加的小部件是否需要配置。有关更多信息,请参阅允许用户配置应用小部件

主机职责

您可以使用AppWidgetProviderInfo元数据为小部件指定许多配置设置。您可以从与小部件提供程序关联的AppWidgetProviderInfo对象中检索这些配置选项,在以下部分中将详细介绍。

无论您定位的是哪个版本的 Android,所有主机都承担以下责任

  • 添加小部件时,如前所述分配小部件 ID。当从主机中删除小部件时,请调用deleteAppWidgetId()以释放小部件 ID。

  • 添加小部件时,请检查是否需要启动配置活动。通常,如果配置活动存在且未通过同时指定configuration_optionalreconfigurable标志而标记为可选,则主机需要启动小部件的配置活动。请参阅从配置活动更新小部件以获取详细信息。在许多小部件显示之前,这是必要的步骤。

  • 小部件在AppWidgetProviderInfo元数据中指定默认宽度和高度。这些值以单元格定义——从 Android 12 开始,如果指定了targetCellWidthtargetCellHeight——或者如果仅指定了minWidthminHeight则以 dp 定义。请参阅小部件大小属性

    确保小部件至少以这么多 dp 进行布局。例如,许多主机将图标和小部件对齐到网格中。在这种情况下,默认情况下,主机使用满足minWidthminHeight约束的最小单元格数添加小部件。

除了上一节中列出的要求外,特定平台版本还引入了使主机承担新责任的功能。

根据目标 Android 版本确定您的方法

Android 12

Android 12(API 级别 31)捆绑了一个额外的List<SizeF>,其中包含小部件实例在选项捆绑包中可以采用的可能大小(以 dp 为单位)的列表。提供的尺寸数量取决于主机实现。主机通常为手机提供两种尺寸(纵向和横向),为折叠屏提供四种尺寸。

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

Android 12 还引入了以 dp 为单位的maxResizeWidthmaxResizeHeight 属性。我们建议使用至少一个这些属性的小部件不要超过属性指定的大小。

其他资源

  • 请参阅 Glance 参考文档。