数据提供程序应用会通过提供包含文本、字符串、图片和数字的字段,向表盘复杂功能提供信息。
数据提供程序服务扩展了 ComplicationProviderService
,可直接将有用的信息提供给表盘。
创建数据提供程序项目
如需在 Android Studio 中为您的数据提供程序应用创建项目,请执行以下操作:
- 依次点击 File > New > New project。
- 在 Create Android Project 窗口中,接受默认值,然后点击 Next。
- 在 Target Android Devices 窗口中,仅选择 Wear 选项,然后在 SDK 版本列表中选择最新的可用版本。点击 Next。
- 在 Add an Activity to Wear 窗口中,选择 Add No Activity,然后点击 Finish。
Android Studio 会使用
app
模块为您的数据提供程序创建项目。如需详细了解 Android Studio 中的项目,请参阅创建项目。 - 通过创建扩展
BroadcastReceiver
的新类来开始创建您的数据提供程序应用。该类的作用是监听来自 Wear OS 系统的复杂功能更新请求。此外,您还需创建一个扩展ComplicationProviderService
的新类,以便实际根据相应复杂功能的请求提供数据。如需了解详情,请参阅以下内容:- 实现更新请求的方法
- 以下 Codelab 中的
ComplicationTapBroadcastReceiver
和CustomComplicationProviderService
类:向复杂功能提供数据 ComplicationToggleReceiver
、LongTextProviderService
和测试套件示例中的其他类
注意:为数据提供程序添加 Activity 是可选操作。举例来说,您可能希望添加仅在用户点按某个复杂功能时才会启动的 Activity。
实现更新请求的方法
当 Wear OS 系统需要复杂功能数据时,它会向您的数据提供程序发送更新请求。这些请求会被您的 BroadcastReceiver
接收。为了响应更新请求,您的数据提供程序必须实现 ComplicationProviderService
类的 onComplicationUpdate()
方法。Wear OS 系统会在需要提供程序提供数据时调用此方法,即当使用您的提供程序的复杂功能变为活动状态时,或者在一段固定时间结束后。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, we grab 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, we grab 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 系统可以绑定到提供程序服务,以此来保护该服务。
此外,您必须在服务元素中添加一个 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 API 参考文档中所列的 ComplicationProviderService
类的键。
添加配置 Activity
如果需要,提供程序可以包含配置 Activity,该 Activity 会在用户选择数据提供程序时显示给用户。要包含配置 Activity,请在清单中的提供程序服务声明中添加一个具有以下键的元数据项:
<meta-data android:name="android.support.wearable.complications.PROVIDER_CONFIG_ACTION" android:value="PROVIDER_CONFIG_ACTION"/>
其中的“value”可以是您选择的操作。
然后,创建包含该操作的 Intent 过滤器的配置 Activity。配置 Activity 必须与提供程序位于同一个软件包中。配置 Activity 必须返回 RESULT_OK
或 RESULT_CANCELED
,以告知系统是否应设置提供程序。
提供程序指定的安全表盘
提供程序可以将某些表盘指定为“安全”,以便接收其数据。这仅适用于表盘会尝试将提供程序用作默认提示(参见下文)并且提供程序信任表盘应用的情况。
为了声明表盘是安全的,提供程序需要添加具有 android.support.wearable.complications.SAFE_WATCH_FACES
键的元数据。元数据值应为逗号分隔的列表(不含空格)。列表中的条目可以是 WatchFaceServices
的组件名(假设调用了 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
添加防烙印版本。
使用推送更新
除了在应用清单中为复杂功能指定非零的常量更新间隔,您还可以使用 ProviderUpdateRequester
实例来动态请求更新。要请求更新复杂功能的用户可见内容,请调用 onComplicationUpdate()
。
注意:为了节省设备的电池电量,您的 ProviderUpdateRequester
实例调用 onComplicationUpdate()
的平均频率不应超过 5 分钟一次。
提供具有时效性的值
一些复杂功能需要显示与当前时间相关的值,例如当前日期、距离下次会议召开还剩下的时间或另一个时区的时间。
请不要为了确保这些值是最新的,就每秒或每分钟都要更新一次复杂功能;一项复杂功能不会需要如此频繁地更新。请使用具有时效性的文本来指定与当前日期或时间相关的值。您可以使用 ComplicationText
类中的构建器来创建此类具有时效性的值。