向复杂功能公开数据

数据提供程序应用将信息公开给表盘复杂功能,提供包含文本、字符串、图像和数字的字段。

数据提供程序服务扩展了 ComplicationProviderService,以便直接向表盘提供有用的信息。

创建数据提供程序项目

要在 Android Studio 中为您的数据提供程序应用创建项目,请完成以下步骤

  1. 点击文件 > 新建 > 新建项目
  2. 项目模板窗口中,点击 Wear OS 选项卡,选择无活动,然后点击下一步
  3. 配置您的项目窗口中,为您的项目命名,填写标准的项目信息,然后点击完成
  4. Android Studio 会创建一个包含数据提供程序应用模块的项目。有关 Android Studio 中项目的更多信息,请参阅创建项目
  5. 通过创建一个扩展 BroadcastReceiver的新类来开始您的数据提供程序应用。该类的目的是监听来自 Wear OS 系统的复杂项更新请求。此外,创建一个扩展 ComplicationProviderService的新类,以根据相应的复杂项请求提供数据。有关更多信息,请参阅以下内容

    注意:为数据提供程序添加活动是可选的。例如,您可能希望仅在用户点击复杂项时启动活动。

实现更新请求的方法

当需要复杂项数据时,Wear OS 系统会向您的数据提供程序发送更新请求。这些请求由您的 BroadcastReceiver接收。为了响应更新请求,您的数据提供程序必须实现ComplicationProviderService类的 onComplicationUpdate()方法。

当 Wear OS 系统需要来自您提供程序的数据时(例如,使用您提供程序的复杂项变为活动状态或经过固定时间段时),它会调用onComplicationUpdate()。它将 ComplicationManager对象作为参数传递给onComplicationUpdate,该参数用于将数据发送回系统。

注意:当您的数据提供程序应用提供数据时,表盘会接收您发送的原始值,以便它可以绘制信息。

以下代码片段显示了onComplicationUpdate方法的示例实现

Kotlin

override fun onComplicationUpdate(
    complicationId: Int, dataType: Int, complicationManager: ComplicationManager) {

    Log.d(TAG, "onComplicationUpdate() id: $complicationId")

    // Used to create a unique key to use with SharedPreferences for this complication.
    val thisProvider = ComponentName(this, javaClass)

    // Retrieves your data; in this case, grabs an incrementing number from SharedPrefs.
    val preferences = getSharedPreferences(ComplicationTapBroadcastReceiver.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0)

    val number = preferences.getInt(
            ComplicationTapBroadcastReceiver.getPreferenceKey(
                    thisProvider, complicationId),
                    0)
    val numberText = String.format(Locale.getDefault(), "%d!", number)

    var complicationData: ComplicationData? = null

    when (dataType) {
        ComplicationData.TYPE_SHORT_TEXT -> complicationData = ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
                .setShortText(ComplicationText.plainText(numberText))
                .build()
        else -> if (Log.isLoggable(TAG, Log.WARN)) {
                    Log.w(TAG, "Unexpected complication type $dataType")
                }
    }

    if (complicationData != null) {
        complicationManager.updateComplicationData(complicationId, complicationData)
    } else {
        // If no data is sent, we still need to inform the ComplicationManager, so
        // the update job can finish and the wake lock isn't held any longer.
        complicationManager.noUpdateRequired(complicationId)
    }
}

Java

@Override
public void onComplicationUpdate(
       int complicationId, int dataType, ComplicationManager complicationManager) {

   Log.d(TAG, "onComplicationUpdate() id: " + complicationId);

   // Used to create a unique key to use with SharedPreferences for this complication.
   ComponentName thisProvider = new ComponentName(this, getClass());

   // Retrieves your data; in this case, grabs an incrementing number from SharedPrefs.
   SharedPreferences preferences =
     getSharedPreferences( ComplicationTapBroadcastReceiver.COMPLICATION_PROVIDER_PREFERENCES_FILE_KEY, 0);

   int number =
           preferences.getInt(
                   ComplicationTapBroadcastReceiver.getPreferenceKey(
                           thisProvider, complicationId),
                   0);
   String numberText = String.format(Locale.getDefault(), "%d!", number);

   ComplicationData complicationData = null;

   switch (dataType) {
       case ComplicationData.TYPE_SHORT_TEXT:
           complicationData =
                   new ComplicationData.Builder(ComplicationData.TYPE_SHORT_TEXT)
                           .setShortText(ComplicationText.plainText(numberText))
                           .build();
           break;
       default:
           if (Log.isLoggable(TAG, Log.WARN)) {
               Log.w(TAG, "Unexpected complication type " + dataType);
           }
   }

   if (complicationData != null) {
       complicationManager.updateComplicationData(complicationId, complicationData);

   } else {
       // If no data is sent, we still need to inform the ComplicationManager, so
       // the update job can finish and the wake lock isn't held any longer.
       complicationManager.noUpdateRequired(complicationId);
   }
}

清单声明和权限

数据提供程序应用必须在其应用清单中包含特定声明,才能被 Android 系统视为数据提供程序。本部分说明了数据提供程序应用所需的设置。

在您的应用清单中,声明服务并添加更新请求操作意图过滤器。清单还必须通过向服务添加BIND_COMPLICATION_PROVIDER权限来保护服务,以确保只有 Wear OS 系统才能绑定到提供程序服务。

此外,在service元素中包含android:icon属性,该属性提供单色白色图标。我们建议使用矢量可绘制对象作为图标。图标代表提供程序,并在提供程序选择器中显示。

这是一个示例

<service
    android:name=".provider.IncrementingNumberComplicationProviderService"
    android:icon="@drawable/icn_complications"
    android:label="@string/complications_provider_incrementing_number"
    android:permission="com.google.android.wearable.permission.BIND_COMPLICATION_PROVIDER">
    <intent-filter>
        <action
         android:name="android.support.wearable.complications.ACTION_COMPLICATION_UPDATE_REQUEST"/>
    </intent-filter>
</service>

指定元数据元素

在您的清单文件中,包含元数据以指定支持的类型、更新周期和配置操作,如下例所示

<meta-data
    android:name="android.support.wearable.complications.SUPPORTED_TYPES"
    android:value="RANGED_VALUE,SHORT_TEXT,LONG_TEXT" />

<meta-data
    android:name="android.support.wearable.complications.UPDATE_PERIOD_SECONDS"
    android:value="300" />

当您的复杂项数据提供程序处于活动状态时,UPDATE_PERIOD_SECONDS指定您希望系统多久检查一次数据的更新。如果复杂项中显示的信息不需要定期更新,例如当您使用推送更新时,请将此值设置为0

如果您未将UPDATE_PERIOD_SECONDS设置为0,则必须使用至少300(5分钟)的值,这是系统强制执行的最小更新周期,以节省设备电量。此外,请记住,当设备处于环境模式或未佩戴时,更新请求的频率会降低。

有关发送更新的更多详细信息,请参阅 ComplicationProviderService类在Wear OS API 参考中列出的键。

添加配置活动

如果需要,提供程序可以包含一个配置活动,当用户选择数据提供程序时会向用户显示该活动。要包含配置活动,请在清单中提供程序服务的声明中包含一个元数据项,并使用以下键

<meta-data
    android:name="android.support.wearable.complications.PROVIDER_CONFIG_ACTION"
    android:value="PROVIDER_CONFIG_ACTION"/>

该值可以是任何操作。

然后,使用该操作的意图过滤器创建配置活动。配置活动必须驻留在与提供程序相同的包中。配置活动必须返回RESULT_OKRESULT_CANCELED以告知系统是否应设置提供程序。

提供程序指定的安全表盘

提供程序可以将某些表盘指定为“安全”以接收其数据。这仅在表盘尝试将提供程序用作默认值且提供程序信任表盘应用时使用。

要将表盘声明为安全,提供程序会添加一个元数据,其键为android.support.wearable.complications.SAFE_WATCH_FACES。元数据值是 WatchFaceService组件名称(如果调用了ComponentName.flattenToString())或应用包名称的逗号分隔列表,在这种情况下,指定应用中的每个表盘都被视为安全。值列表中的空格将被忽略。例如

<meta-data
       android:name="android.support.wearable.complications.SAFE_WATCH_FACES"
       android:value="
          com.app.watchface/com.app.watchface.MyWatchFaceService,
          com.anotherapp.anotherwatchface/com.something.WatchFaceService,
          com.something.text"/>

提供防烧屏图像

在易受烧屏影响的屏幕上,应避免在环境模式下使用纯色块。如果您的图标或图像包含纯色块,也请提供防烧屏版本。

当您使用 ComplicationData.Builder#setIcon提供图标时,请使用 ComplicationData.Builder#setBurnInProtectionIcon包含防烧屏版本。

当您使用 ComplicationData.Builder#setSmallImage提供图像时,请使用 ComplicationData.Builder#setBurnInProtectionSmallImage包含防烧屏版本。

使用推送更新

作为在应用清单中为复杂项指定常量、非零更新间隔的替代方法,您可以使用 ComplicationDataSourceUpdateRequester的实例来动态请求更新。要请求更新复杂项的用户可见内容,请调用requestUpdate()

注意:为了节省设备电量,请不要平均每 5 分钟以上就从ComplicationDataSourceUpdateRequester的实例中调用requestUpdate()

提供动态值

从 Wear OS 4 开始,某些复杂项可以显示基于平台直接可用的值更频繁地刷新的值。要在您的复杂项中提供此功能,请使用接受动态值 ComplicationData字段。平台会频繁评估和更新这些值,而无需复杂项提供程序运行。

示例字段包括 GoalProgressComplicationData的动态值字段,以及 DynamicComplicationText,它可以用于任何 ComplicationText字段。这些动态值基于 androidx.wear.protolayout.expression库。

在某些情况下,平台无法评估动态值

提供时间相关的值

某些复杂项需要显示与当前时间相关的值。例如,当前日期、下次会议之前的时间或另一个时区的时间。

不要每秒或每分钟更新一次复杂项以保持这些值最新。相反,使用时间相关文本将值指定为相对于当前日期或时间。您可以使用 ComplicationText类中的构建器来创建这些时间相关的值。

复杂项更新速率

您可能希望以较快的速度更新复杂功能。但是,这可能会影响设备的电池寿命。您可以选择使用特权的复杂功能请求 API,以便特定复杂功能更频繁地更新。但是,必须获得手表制造商的许可才能使用此 API。每家手表制造商都会决定哪些复杂功能可以比通常允许的速度更快地更新。