정보 표시에 데이터 노출

데이터 제공자 앱은 텍스트, 문자열, 이미지, 숫자를 포함한 필드를 제공하는 시계 화면 정보 표시에 정보를 노출합니다.

데이터 제공자 서비스는 ComplicationProviderService를 확장하여 유용한 정보를 시계 화면에 직접 전달합니다.

데이터 제공자 프로젝트 만들기

Android 스튜디오에서 데이터 제공자 앱용 프로젝트를 만들려면 다음 단계를 완료하세요.

  1. File > New > New project를 클릭합니다.
  2. Project Template 창에서 Wear OS 탭을 클릭하고 No Activity를 선택한 후 Next를 클릭합니다.
  3. Configure Your Project 창에서 프로젝트 이름을 지정하고 표준 프로젝트 정보를 입력한 다음 Finish를 클릭합니다.
  4. Android 스튜디오는 데이터 제공자용 앱 모듈로 프로젝트를 만듭니다. Android 스튜디오의 프로젝트에 관한 자세한 내용은 프로젝트 만들기를 참고하세요.
  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 시스템에서 데이터 제공자로 간주될 수 있습니다. 이 섹션에서는 데이터 제공자 앱의 필수 설정에 관해 설명합니다.

앱 매니페스트에 서비스를 선언하고 업데이트 요청 작업의 인텐트 필터를 추가합니다. 또한 매니페스트는 Wear OS 시스템만 제공자 서비스에 결합할 수 있도록 BIND_COMPLICATION_PROVIDER 권한을 추가하여 이 서비스를 보호해야 합니다.

또한 단일 색상 흰색 아이콘을 제공하는 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_SECONDS0으로 설정하지 않으면 300(5분) 이상의 값을 사용해야 합니다. 이 값은 기기 배터리 수명을 보존하기 위해 시스템에서 시행하는 최소 업데이트 기간입니다. 또한 기기가 대기 모드에 있거나 기기를 착용하지 않은 경우에는 업데이트 요청이 줄어듭니다.

업데이트 전송에 관한 자세한 내용은 Wear OS API 참조 ComplicationProviderService 클래스와 관련해 나열된 키를 참고하세요.

구성 활동 추가

필요한 경우 제공자는 사용자가 데이터 제공자를 선택할 때 사용자에게 표시되는 구성 활동을 포함할 수 있습니다. 구성 활동을 포함하려면 다음 키와 함께 메타데이터 항목을 매니페스트의 제공자 서비스 선언에 포함하세요.

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

값은 어떤 작업이든 될 수 있습니다.

그런 다음, 해당 작업에 대한 인텐트 필터로 구성 활동을 만듭니다. 구성 활동은 제공자와 동일한 패키지 내에 있어야 합니다. 구성 활동은 제공자 설정 여부를 시스템에 알리기 위해 RESULT_OK 또는 RESULT_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를 사용하여 번인 안전 버전을 포함합니다.

푸시 업데이트 사용

앱 매니페스트에서 정보 표시가 지속적이며 1회 이상의 간격으로 업데이트되도록 지정하는 대신 ComplicationDataSourceUpdateRequester 인스턴스를 사용하여 동적으로 업데이트를 요청할 수 있습니다. 사용자에게 표시되는 정보 표시 콘텐츠의 업데이트를 요청하려면 requestUpdate()를 호출합니다.

주의: 기기 배터리 수명을 보존하려면 ComplicationDataSourceUpdateRequester의 인스턴스에서 requestUpdate()를 평균 5분 간격보다 더 자주 호출하지 마세요.

동적 가치 제공

Wear OS 4부터 일부 정보 표시는 플랫폼에 직접 제공되는 값을 기반으로 더 자주 새로고침되는 값을 표시할 수 있습니다. 정보 표시에 이 기능을 제공하려면 동적 값을 허용하는 ComplicationData 필드를 사용하세요. 플랫폼은 정보 표시 제공자를 실행할 필요 없이 이러한 값을 자주 평가하고 업데이트합니다.

예시 필드로는 GoalProgressComplicationData의 동적 값 필드와 모든 ComplicationText 필드에 사용할 수 있는 DynamicComplicationText가 있습니다. 이러한 동적 값은 androidx.wear.protolayout.expression 라이브러리를 기반으로 합니다.

다음과 같은 특정 상황에서는 플랫폼이 동적 가치를 평가할 수 없습니다.

  • 동적 값을 사용할 수 없는 경우가 있음: 예를 들어 기기를 손목에 착용하지 않는 경우에 이러한 문제가 발생합니다. 이러한 상황에서 플랫폼은 NoDataComplicationData의 자리표시자 필드에서 동적 값 무효화 대체 필드의 값을 대신 사용합니다.
  • 동적 값을 사용할 수 없음: 이전 버전의 Wear OS 4를 실행 중인 기기에서 발생합니다. 이 상황에서 플랫폼은 getFallbackValue()와 같은 컴패니언 대체 필드를 사용합니다.

시간 종속 값 제공

일부 정보 표시에는 현재 시간에 관련된 값이 표시되어야 합니다. 그 예로는 현재 날짜, 다음 미팅까지의 시간 또는 다른 시간대의 시간이 있습니다.

이러한 값을 최신 상태로 유지하기 위해 정보 표시를 1초 또는 1분마다 업데이트하지 마세요. 그 대신, 시간 종속 텍스트를 사용하여 현재 날짜나 시간에 상대적인 값을 지정하세요. ComplicationText 클래스에서 빌더를 사용하여 이러한 시간 종속 값을 만들 수 있습니다.

정보 표시 업데이트 속도

빠른 속도로 정보 표시를 업데이트할 수 있습니다. 하지만 이렇게 하면 기기의 배터리 수명에 영향을 줄 수 있습니다. 특정 정보 표시가 더 자주 업데이트되도록 하는, 권한이 있는 정보 표시 요청 API를 사용할 수 있습니다. 하지만 이 API를 사용하려면 시계 제조업체에서 허용해야 합니다. 각 시계 제조업체는 일반적으로 허용된 속도보다 더 빠르게 업데이트할 수 있는 정보 표시를 결정합니다.