将数据公开给复杂功能

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

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

创建数据提供方项目

如需在 Android Studio 中为数据提供方应用创建项目,请完成以下步骤

  1. 点击 File > New > New project
  2. Project Template 窗口中,点击 Wear OS 标签页,选择 No Activity,然后点击 Next
  3. Configure Your Project 窗口中,为项目命名,填写标准项目信息,然后点击 Finish
  4. Android Studio 会为您的数据提供方创建一个包含应用模块的项目。有关 Android Studio 中项目的更多信息,请参阅创建项目
  5. 通过创建扩展 BroadcastReceiver 的新类来启动您的数据提供方应用。该类的目的是监听来自 Wear OS 系统的复杂功能更新请求。此外,创建一个扩展 ComplicationProviderService 的新类,以按适当的复杂功能请求提供数据。如需了解详情,请参阅以下内容

    注意:为数据提供方添加 activity 是可选的。例如,您可能希望一个 activity 仅在用户点按复杂功能时启动。

实现用于更新请求的方法

当需要复杂功能数据时,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 系统视为数据提供方。本部分介绍了数据提供方应用的所需设置。

在您的应用清单中,声明服务并添加一个更新请求操作 intent 过滤器。清单还必须通过添加 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 分钟)的值,这是系统为节省设备电池续航而强制执行的最小更新周期。此外,请记住,当设备处于环境模式或未佩戴时,更新请求的频率会降低。

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

添加配置 activity

如果需要,提供方可以包含一个配置 activity,该 activity 在用户选择数据提供方时显示给用户。要包含配置 activity,请在清单中的提供方服务声明中包含一个元数据项,并使用以下键:

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

该值可以是任何操作。

然后,使用该操作的 intent 过滤器创建配置 activity。配置 activity 必须与提供方位于同一个软件包中。配置 activity 必须返回 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 的动态值字段,以及可在任何 ComplicationText 字段中使用的 DynamicComplicationText。这些动态值基于 androidx.wear.protolayout.expression 库。

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

提供时间相关值

有些复杂功能需要显示与当前时间相关的值。示例包括当前日期、距离下一次会议的时间或另一时区的时间。

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

复杂功能更新频率

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