카드 버전 관리

Wear OS 기기에서 카드는 독립적인 버전 관리가 적용된 두 가지 주요 구성요소에 의해 렌더링됩니다. 앱 카드가 모든 기기에서 올바르게 작동하도록 하려면 이 기본 아키텍처를 이해하는 것이 중요합니다.

  • Jetpack 카드 관련 라이브러리: Wear 카드 및 Wear ProtoLayout을 비롯한 이러한 라이브러리는 앱에 삽입되며 개발자가 버전을 관리합니다. 앱은 이러한 라이브러리를 사용하여 시스템의 onTileRequest() 호출에 응답하여 TileBuilder.Tile 객체 (카드를 나타내는 데이터 구조)를 생성합니다.
  • ProtoLayout 렌더러: 이 시스템 구성요소는 디스플레이에 Tile 객체를 렌더링하고 사용자 상호작용을 처리합니다. 렌더러 버전은 앱 개발자가 제어하지 않으며 동일한 하드웨어를 사용하는 기기 간에 다를 수 있습니다.

카드의 모양이나 동작은 앱의 Jetpack Tiles 라이브러리 버전과 사용자 기기의 ProtoLayout 렌더러 버전에 따라 다를 수 있습니다. 예를 들어 한 기기는 회전 또는 심박수 데이터 표시를 지원할 수 있고 다른 기기는 지원하지 않을 수 있습니다.

이 문서에서는 앱이 Tiles 라이브러리 및 ProtoLayout 렌더러의 다양한 버전과 호환되도록 하는 방법과 더 높은 Jetpack 라이브러리 버전으로 이전하는 방법을 설명합니다.

호환성 고려

다양한 기기에서 올바르게 작동하는 카드를 만들려면 다음 사항을 고려해야 합니다.

렌더러 버전 감지

  • onTileRequest() 메서드에 전달된 DeviceParameters 객체의 getRendererSchemaVersion() 메서드를 사용합니다. 이 메서드는 기기의 ProtoLayout 렌더러의 주요 버전 및 부 버전 번호를 반환합니다.
  • 그런 다음 onTileRequest() 구현에서 조건부 로직을 사용하여 감지된 렌더러 버전에 따라 카드의 디자인이나 동작을 조정할 수 있습니다.
    • 예를 들어 특정 애니메이션이 지원되지 않는 경우 정적 이미지를 대신 표시할 수 있습니다.

@RequiresSchemaVersion 주석

  • ProtoLayout 메서드의 @RequiresSchemaVersion 주석은 해당 메서드가 문서화된 대로 작동하는 데 필요한 최소 렌더러 스키마 버전을 나타냅니다 ().
    • 기기에서 사용할 수 있는 것보다 높은 렌더러 버전이 필요한 메서드를 호출해도 앱이 비정상 종료되지는 않지만 콘텐츠가 표시되지 않거나 기능이 무시될 수 있습니다.

override fun onTileRequest(
    requestParams: TileService.TileRequest
): ListenableFuture<Tile> {
    val rendererVersion =
        requestParams.deviceConfiguration.rendererSchemaVersion
    val tile = Tile.Builder()

    if (
        rendererVersion.major > 1 ||
            (rendererVersion.major == 1 && rendererVersion.minor >= 300)
    ) {
        // Use a feature supported in renderer version 1.300 or later
        tile.setTileTimeline(/* ... */ )
    } else {
        // Provide fallback content for older renderers
        tile.setTileTimeline(/* ... */ )
    }

    return Futures.immediateFuture(tile.build())
}

다양한 렌더러 버전으로 테스트

다양한 렌더러 버전에서 카드를 테스트하려면 Wear OS 에뮬레이터의 다양한 버전에 카드를 배포합니다. (실제 기기에서는 ProtoLayout 렌더러 업데이트가 Play 스토어 또는 시스템 업데이트를 통해 제공됩니다. 특정 렌더러 버전을 강제로 설치할 수는 없습니다.)

Android 스튜디오의 카드 미리보기 기능은 코드가 종속되는 Jetpack ProtoLayout 라이브러리에 삽입된 렌더러를 사용하므로 카드를 테스트할 때 다른 Jetpack 라이브러리 버전에 종속되는 것도 한 가지 방법입니다.

Tiles 1.5 / ProtoLayout 1.3 (Material 3 Expressive)으로 이전

Jetpack 카드 라이브러리를 업데이트하여 카드가 시스템과 원활하게 통합되도록 하는 UI 변경사항을 비롯한 최신 개선사항을 활용하세요.

Jetpack Tiles 1.5 및 Jetpack ProtoLayout 1.3에는 몇 가지 주목할 만한 개선사항과 변경사항이 도입되었습니다. 예를 들면 다음과 같습니다.

  • UI를 설명하기 위한 Compose와 유사한 API입니다.
  • 하단을 감싸는 가장자리 버튼과 향상된 시각적 요소(Lottie 애니메이션, 더 많은 그라데이션 유형, 새로운 원호 선 스타일)를 지원하는 Material 3 Expressive 구성요소 - 참고: 일부 기능은 새 API로 이전하지 않고도 사용할 수 있습니다.

권장사항

  • 모든 카드를 동시에 이전합니다. 앱 내에서 카드 버전을 혼합하지 마세요. Material 3 구성요소는 별도의 아티팩트 (androidx.wear.protolayout:protolayout-material3)에 있으므로 기술적으로는 동일한 앱에서 M2.5 카드와 M3 카드를 모두 사용할 수 있지만, 꼭 필요한 경우가 아니라면 (예: 앱에 한 번에 모두 이전할 수 없는 카드가 많은 경우) 이 접근 방식을 사용하지 않는 것이 좋습니다.
  • 카드 UX 가이드를 채택합니다. 카드는 고도로 구조화되고 템플릿화된 특성을 가지고 있으므로 기존 샘플의 디자인을 자체 디자인의 시작점으로 사용하세요.
  • 다양한 화면 및 글꼴 크기에서 테스트합니다. 카드는 정보가 많기 때문에 텍스트가 오버플로 및 클리핑되기 쉽습니다 (특히 버튼에 배치된 경우). 이를 최소화하려면 사전 빌드된 구성요소를 사용하고 광범위한 맞춤설정을 피하세요. Android 스튜디오의 카드 미리보기 기능과 여러 실제 기기를 사용하여 테스트합니다.

마이그레이션 프로세스

종속 항목 업데이트

먼저 build.gradle.kts 파일을 업데이트합니다. 버전을 업데이트하고 protolayout-material 종속 항목을 protolayout-material3로 변경합니다(예 참고).

// In build.gradle.kts

//val tilesVersion = "1.4.1"
//val protoLayoutVersion = "1.2.1"

// Use these versions for M3.
val tilesVersion = "1.5.0-rc01"
val protoLayoutVersion = "1.3.0-rc01"

 dependencies {
     // Use to implement support for wear tiles
     implementation("androidx.wear.tiles:tiles:$tilesVersion")

     // Use to utilize standard components and layouts in your tiles
     implementation("androidx.wear.protolayout:protolayout:$protoLayoutVersion")

     // Use to utilize components and layouts with Material Design in your tiles
     // implementation("androidx.wear.protolayout:protolayout-material:$protoLayoutVersion")
     implementation("androidx.wear.protolayout:protolayout-material3:$protoLayoutVersion")

     // Use to include dynamic expressions in your tiles
     implementation("androidx.wear.protolayout:protolayout-expression:$protoLayoutVersion")

     // Use to preview wear tiles in your own app
     debugImplementation("androidx.wear.tiles:tiles-renderer:$tilesVersion")

     // Use to fetch tiles from a tile provider in your tests
     testImplementation("androidx.wear.tiles:tiles-testing:$tilesVersion")
 }

TileService는 크게 변경되지 않습니다.

이 이전의 주요 변경사항은 UI 구성요소에 영향을 미칩니다. 따라서 리소스 로드 메커니즘을 비롯한 TileService 구현은 최소한의 수정 또는 수정 없이도 작동합니다.

주요 예외는 카드 활동 추적과 관련이 있습니다. 앱에서 onTileEnterEvent() 또는 onTileLeaveEvent()를 사용하는 경우 onRecentInteractionEventsAsync()로 이전해야 합니다. API 36부터 이러한 이벤트가 일괄 처리됩니다.

레이아웃 생성 코드 조정

ProtoLayout 1.2 (M2.5)에서 onTileRequest() 메서드는 TileBuilders.Tile를 반환합니다. 이 객체에는 TimelineBuilders.Timeline를 비롯한 다양한 요소가 포함되어 있으며, 이 요소는 카드의 UI를 설명하는 LayoutElement를 보유하고 있습니다.

ProtoLayout 1.3 (M3)에서는 전반적인 데이터 구조와 흐름이 변경되지 않았지만 LayoutElement는 이제 정의된 슬롯 (위에서 아래로 titleSlot (일반적으로 기본 제목 또는 헤더용), mainSlot (핵심 콘텐츠용), bottomSlot (종종 가장자리 버튼과 같은 작업 또는 짧은 텍스트와 같은 보조 정보용))을 기반으로 하는 레이아웃을 사용하여 Compose에서 영감을 받은 접근 방식으로 구성됩니다. 이 레이아웃은 primaryLayout() 함수로 구성됩니다.

mainSlot, titleSlot, bottomSlot을 보여주는 카드의 레이아웃
그림 1.: 카드의 슬롯
레이아웃 M2.5와 M3 레이아웃 함수 비교

M2.5

fun myLayout(
    context: Context,
    deviceConfiguration: DeviceParametersBuilders.DeviceParameters
) =
    PrimaryLayout.Builder(deviceConfiguration)
        .setResponsiveContentInsetEnabled(true)
        .setContent(
            Text.Builder(context, "Hello World!")
                .setTypography(Typography.TYPOGRAPHY_BODY1)
                .setColor(argb(0xFFFFFFFF.toInt()))
                .build()
        )
        .build()

M3

fun myLayout(
    context: Context,
    deviceConfiguration: DeviceParametersBuilders.DeviceParameters,
) =
    materialScope(context, deviceConfiguration) {
        primaryLayout(mainSlot = { text("Hello, World!".layoutString) })
    }

주요 차이점을 강조 표시하려면 다음 단계를 따르세요.

  1. 빌더 삭제 Material3 UI 구성요소의 기존 빌더 패턴은 더 선언적인 Compose 기반 구문으로 대체되었습니다. String/Color/Modifiers와 같은 UI 외 구성요소에도 새로운 Kotlin 래퍼가 적용됩니다.
  2. 표준화된 초기화 및 레이아웃 함수 M3 레이아웃은 표준화된 초기화 및 구조 함수인 materialScope()primaryLayout()를 사용합니다. 이러한 필수 함수는 M3 환경 (테마 설정, materialScope를 통한 구성요소 범위)을 초기화하고 기본 슬롯 기반 레이아웃을 정의합니다 (primaryLayout를 통해). 둘 다 레이아웃당 정확히 한 번 호출해야 합니다.

테마 설정

색상

Material 3 Expressive의 두드러진 특징은 '동적 테마 설정'입니다. 이 기능을 사용 설정하는 카드 (기본적으로 사용 설정됨)는 시스템 제공 테마로 표시됩니다(사용자의 기기 및 구성에 따라 사용 가능 여부 다름).

M3의 또 다른 변경사항은 색상 토큰 수가 4개에서 29개로 늘어난 것입니다. 새 색상 토큰은 ColorScheme 클래스에서 확인할 수 있습니다.

서체

M2.5와 마찬가지로 M3은 사전 정의된 글꼴 크기 상수를 많이 사용합니다. 글꼴 크기를 직접 지정하는 것은 권장하지 않습니다. 이러한 상수는 Typography 클래스에 있으며 표현력이 더 뛰어난 옵션을 약간 확장된 범위로 제공합니다.

자세한 내용은 서체 문서를 참고하세요.

도형

대부분의 M3 구성요소는 색상뿐만 아니라 도형의 크기에 따라 다를 수 있습니다.

모양이 fulltextButton (mainSlot 내)

&#39;전체&#39; 도형 (모서리가 더 둥글게 처리됨)의 카드
그림 2.: '전체' 도형이 있는 타일

도형이 small인 동일한 textButton:

&#39;작은&#39; 도형 (모서리가 덜 둥글게 처리됨)의 카드
그림 3.: '작은' 도형이 있는 타일

구성요소

M3 구성요소는 M2.5 구성요소보다 훨씬 더 유연하고 구성할 수 있습니다. M2.5에서는 다양한 시각적 처리를 위해 고유한 구성요소가 필요한 경우가 많았지만, M3에서는 일반적이지만 구성이 매우 쉬운 '기본' 구성요소와 적절한 기본값을 자주 사용합니다.

이 원칙은 '루트' 레이아웃에 적용됩니다. M2.5에서는 PrimaryLayout 또는 EdgeContentLayout였습니다. M3에서 단일 최상위 MaterialScope가 설정된 후 primaryLayout() 함수가 호출됩니다. 이렇게 하면 루트 레이아웃이 직접 반환되며 (빌더가 필요하지 않음) titleSlot, mainSlot, bottomSlot과 같은 여러 '슬롯'에 LayoutElements를 허용합니다. 이러한 슬롯은 text(), button() 또는 card()에서 반환된 것과 같은 구체적인 UI 구성요소 또는 LayoutElementBuildersRow 또는 Column와 같은 레이아웃 구조로 채울 수 있습니다.

테마는 또 다른 주요 M3 개선사항을 나타냅니다. 기본적으로 UI 요소는 M3 스타일 지정 사양을 자동으로 준수하고 동적 테마 설정을 지원합니다.

M2.5 M3
상호작용 요소
Button 또는 Chip
텍스트
Text text()
진행률 표시기
CircularProgressIndicator circularProgressIndicator() 또는 segmentedCircularProgressIndicator()
레이아웃
PrimaryLayout 또는 EdgeContentLayout primaryLayout()
buttonGroup()
이미지
icon(), avatarImage() 또는 backgroundImage()

수정자

M3에서는 구성요소를 장식하거나 확장하는 데 사용하는 Modifiers가 Compose와 더 유사합니다. 이 변경사항은 적절한 내부 유형을 자동으로 생성하여 불필요한 코드를 줄일 수 있습니다. 이 변경사항은 M3 UI 구성요소 사용과는 무관합니다. 필요한 경우 ProtoLayout 1.2의 빌더 스타일 수정자를 M3 UI 구성요소와 함께 사용하거나 그 반대로 사용할 수 있습니다.

M2.5

// A Builder-style modifier to set the opacity of an element to 0.5
fun myModifier(): ModifiersBuilders.Modifiers =
    ModifiersBuilders.Modifiers.Builder()
        .setOpacity(TypeBuilders.FloatProp.Builder(0.5F).build())
        .build()

M3

// The equivalent Compose-like modifier is much simpler
fun myModifier(): LayoutModifier = LayoutModifier.opacity(0.5F)

두 API 스타일 중 하나를 사용하여 수정자를 구성할 수 있으며, toProtoLayoutModifiers() 확장 함수를 사용하여 LayoutModifierModifiersBuilders.Modifier로 변환할 수도 있습니다.

도우미 함수

ProtoLayout 1.3을 사용하면 Compose 기반 API를 사용하여 여러 UI 구성요소를 표현할 수 있지만 LayoutElementBuilders과 같은 기본 레이아웃 요소는 계속해서 빌더 패턴을 사용합니다. 이 스타일 차이를 해소하고 새 M3 구성요소 API와의 일관성을 높이려면 도우미 함수를 사용하는 것이 좋습니다.

도우미 없음

primaryLayout(
    mainSlot = {
        LayoutElementBuilders.Column.Builder()
            .setWidth(expand())
            .setHeight(expand())
            .addContent(text("A".layoutString))
            .addContent(text("B".layoutString))
            .addContent(text("C".layoutString))
            .build()
    }
)

도우미 포함

// Function literal with receiver helper function
fun column(builder: Column.Builder.() -> Unit) =
    Column.Builder().apply(builder).build()

primaryLayout(
    mainSlot = {
        column {
            setWidth(expand())
            setHeight(expand())
            addContent(text("A".layoutString))
            addContent(text("B".layoutString))
            addContent(text("C".layoutString))
        }
    }
)

Tiles 1.2 / ProtoLayout 1.0으로 이전

버전 1.2부터 대부분의 Tiles Layout API는 androidx.wear.protolayout 네임스페이스에 있습니다. 최신 API를 사용하려면 코드에서 아래와 같은 이전 단계를 완료하세요.

종속 항목 업데이트

앱 모듈의 빌드 파일에서 다음과 같이 변경합니다.

Groovy

  // Remove
  implementation 'androidx.wear.tiles:tiles-material:version'

  // Include additional dependencies
  implementation "androidx.wear.protolayout:protolayout:1.2.1"
  implementation "androidx.wear.protolayout:protolayout-material:1.2.1"
  implementation "androidx.wear.protolayout:protolayout-expression:1.2.1"

  // Update
  implementation "androidx.wear.tiles:tiles:1.4.1"

Kotlin

  // Remove
  implementation("androidx.wear.tiles:tiles-material:version")

  // Include additional dependencies
  implementation("androidx.wear.protolayout:protolayout:1.2.1")
  implementation("androidx.wear.protolayout:protolayout-material:1.2.1")
  implementation("androidx.wear.protolayout:protolayout-expression:1.2.1")

  // Update
  implementation("androidx.wear.tiles:tiles:1.4.1")

네임스페이스 업데이트

앱의 Kotlin 및 Java 기반 코드 파일에서 다음과 같이 업데이트합니다. 또는 네임스페이스 이름 변경 스크립트를 실행할 수 있습니다.

  1. 모든 androidx.wear.tiles.material.* 가져오기를 androidx.wear.protolayout.material.*로 바꿉니다. androidx.wear.tiles.material.layouts 라이브러리에서도 이 단계를 완료합니다.
  2. 대부분의 나머지 androidx.wear.tiles.* 가져오기를 androidx.wear.protolayout.*으로 바꿉니다.

    androidx.wear.tiles.EventBuilders, androidx.wear.tiles.RequestBuilders, androidx.wear.tiles.TileBuilders, androidx.wear.tiles.TileService의 가져오기는 동일하게 유지해야 합니다.

  3. TileService 및 TileBuilder 클래스의 지원 중단된 몇 가지 메서드의 이름을 바꿉니다.

    1. TileBuilders: getTimeline()에서 getTileTimeline()으로, setTimeline()에서 setTileTimeline()으로
    2. TileService: onResourcesRequest()에서 onTileResourcesRequest()
    3. RequestBuilders.TileRequest: getDeviceParameters()에서 getDeviceConfiguration()으로, setDeviceParameters()에서 setDeviceConfiguration()으로, getState()에서 getCurrentState()로, setState()에서 setCurrentState()