构建微件主机

在大多数 Android 设备上都可用的 Android 主屏幕允许用户嵌入应用微件(或简称微件),以便快速访问内容。如果您正在构建主屏幕替代应用或类似应用,也可以通过实现 AppWidgetHost 让用户嵌入微件。大多数应用不需要这样做,但如果您要创建自己的主机,了解主机隐含同意的合约义务非常重要。

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

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

  • 应用微件主机AppWidgetHost 为在其 UI 中嵌入微件的应用提供与 AppWidget 服务的交互。每个 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() 方法修改微件的包。这两个方法都会触发对 AppWidgetProvideronAppWidgetOptionsChanged() 回调。

绑定微件

当用户将微件添加到主机时,会发生一个称为绑定的过程。绑定是指将特定的应用微件 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。

  • 添加微件时,检查是否需要启动配置 Activity。通常,如果微件的配置 Activity 存在且未通过指定 configuration_optionalreconfigurable 标志标记为可选,则主机需要启动它。有关详细信息,请参阅从配置 Activity 更新微件。对于许多微件来说,这是它们显示之前必要的步骤。

  • 微件在 AppWidgetProviderInfo 元数据中指定默认宽度和高度。这些值以单元格为单位定义(从 Android 12 开始,如果指定了 targetCellWidthtargetCellHeight),或者以 dps 为单位(如果只指定了 minWidthminHeight)。请参阅微件尺寸属性

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

除了上一节中列出的要求外,特定的平台版本还引入了一些功能,这些功能为主机带来了新的职责。

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

Android 12

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

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

Android 12 还引入了以 dps 为单位的 maxResizeWidthmaxResizeHeight 属性。我们建议使用这些属性中至少一个的微件不要超过属性指定的尺寸。

其他资源

  • 请参阅 Glance 参考文档。