원격 Compose 개념 및 아키텍처

원격 Compose는 앱에서 Compose 스타일 API를 사용하여 UI를 빌드하고 앱 위젯이나 Wear OS 위젯과 같은 시스템 프로세스에 표시할 수 있는 Jetpack 라이브러리입니다. 앱은 UI를 압축된 문서로 기록하고 호스트 프로세스의 플레이어는 앱을 다시 호출하지 않고도 로컬에서 UI를 렌더링하고 상호작용, 상태 변경, 애니메이션을 처리합니다.

이 가이드에서는 원격 Compose 아키텍처와 표준 Jetpack Compose와의 차이점을 설명합니다. 이 가이드에서는 구성요소로 UI를 빌드하는 방법을 중점적으로 설명합니다.

원격 Compose 사용 사례

Remote Compose는 지원되는 플레이어가 있는 모든 표시 경로에서 사용할 수 있습니다. Android에서는 앱 위젯과 Wear OS 위젯을 지원합니다.

작동 방식: 3블록 아키텍처

원격 Compose와 표준 Jetpack Compose의 근본적인 아키텍처 차이는 세 가지 상위 수준 블록에서 UI 정의를 실행과 분리하는 데 있습니다.

  • 문서 만들기: 앱이 @RemoteComposable 함수를 실행하여 문서를 기록합니다. 문서는 레이아웃, 원격 상태, 작업을 포함한 UI의 간결하고 직렬화된 설명입니다. 데이터가 변경되면 앱에서 새 문서를 기록하고 전송할 수 있습니다.
  • 원격 호스트로 문서 전송: 앱이 문서를 호스트에 전달합니다. 호스트는 런처나 Wear OS와 같이 문서를 표시하는 프로세스입니다.
  • 문서 재생: 호스트의 원격 Compose 플레이어가 문서를 렌더링하고 앱을 다시 호출하지 않고도 레이아웃, 입력, UX 상태 변경, 애니메이션을 로컬에서 처리합니다.

이 아키텍처는 지연 시간을 직접 줄이는 다음과 같은 주요 이점을 제공합니다.

  • 작은 문서 크기: 직렬화된 문서 스냅샷은 작고 가볍습니다.
  • 왕복 감소: 원격 호스트 플레이어가 상호작용과 상태 변경을 로컬에서 처리하므로 애플리케이션 또는 서버로의 왕복 통신이 최소화됩니다.

웹페이지/HTML 비유: 원격 Compose는 웹페이지를 제공하는 것과 유사하게 작동합니다. 앱 서버는 HTML/문서 구조를 한 번 생성하고 전송하며, 브라우저 호스트는 백엔드를 지속적으로 쿼리하지 않고도 이를 렌더링하고 로컬에서 상호작용을 처리합니다.

원격 Compose를 위한 앱 프로세스에서 원격 호스트 프로세스로의 통신
그림 1. 원격 Compose 아키텍처의 세 가지 블록

구성요소

원격 Compose는 레이아웃을 구성하는 상위 수준 UI 구성요소를 제공합니다. 표준 Compose 구성요소 대신 원격 Compose 구성요소와 RemoteModifier를 사용합니다. 여기에는 기본 레이아웃 컨테이너와 동적 화면 크기를 처리하도록 특별히 설계된 적응형 구성요소가 포함됩니다.

  • 기본 레이아웃 구성요소: RemoteBox, RemoteRow, RemoteColumn와 같은 일반적인 Compose 유사 레이아웃 요소입니다.
  • 적응형 레이아웃 구성요소: 원격 표시 경로 전반에서 깔끔하게 조정되도록 설계된 RemoteFitBox, RemoteCollapsibleRow, RemoteCollapsibleColumn와 같은 특수 구성요소입니다.
  • Material Design 테마 설정: 테마 설정은 Wear OS 위젯에서도 동일하게 작동하며 RemoteMaterialTheme에서 제공하는 색상 및 서체 계층 구조를 사용합니다. 이를 통해 앱과 위젯 전반에 일관된 브랜딩 및 디자인 시스템 구현이 가능합니다.

RemoteCanvas를 사용한 맞춤 그리기

맞춤 그래픽 및 시간 기반 애니메이션의 경우 플레이어가 호스트에서 실행하는 그리기 명령어를 기록하는 RemoteCanvas를 사용합니다. 이 가이드에서는 구성요소로 UI를 빌드하는 방법을 중점적으로 설명합니다.

주요 차이점

다음 핵심 개념을 검토하여 원격 Compose가 상태, 로직, 작업을 관리하는 방법을 알아보세요.

기호 상태 참조

표준 Compose에서 상태 컨테이너는 이벤트가 발생할 때 앱 코드 (람다)에 의해 변경되는 로컬 앱 메모리에 활성 상태의 읽기 가능한 값을 보유합니다. 원격 Compose에서 상태 선언은 기호 참조 역할을 합니다. 로컬 앱 메모리에 활성 값을 보유하는 대신 원격 플레이어가 런타임에 로컬로 관리하고 업데이트하는 바인딩을 선언합니다. 원격 Compose에서 상태를 선언할 때는 다음 사항에 유의하세요.

  • 원격 Compose 팩토리 함수를 사용하여 rememberMutableRemoteInt, rememberMutableRemoteFloat 또는 rememberMutableRemoteString와 같은 상태를 선언합니다.
  • 앱 코드는 컴포지션 중에 원격 상태 변수의 값을 직접 검사하거나 읽을 수 없습니다.
  • 플레이어는 사용자가 문서와 상호작용할 때 이러한 값을 로컬에 저장하고 업데이트합니다.

원격 상태와 Kotlin 제어 흐름

Kotlin 코드는 앱이 문서를 만들 때만 실행됩니다. if, when, for와 같은 Kotlin 문은 목록의 각 항목에 대해 행을 반복하는 등 당시 알려진 값을 기반으로 문서를 형성할 수 있지만 나중에 변경되는 원격 상태에 반응할 수는 없습니다. 원격 Compose에서 작업할 때는 다음 사항에 유의하세요.

  • 분기 로직: 동적 UI 전환은 상태를 다양한 RemoteComposable 슬롯에 매핑하여 RemoteStateLayout를 사용하여 실행됩니다.
  • 텍스트 평가: 문서를 만들 때만 평가되는 표준 Kotlin 문자열 보간("$remoteValue")을 사용하지 마세요. 대신 RemoteString를 RemoteText에 전달합니다.

RemoteModifier를 사용한 동적 스타일 지정

호스트의 동적 스타일 지정은 컴포지션을 다시 실행하지 않습니다. 대신 원격 상태 변수가 RemoteModifier.background(remoteColor)와 같은 수정자에 직접 전달됩니다.

원격 시스템 컨텍스트

LocalConfiguration 또는 LocalDensity와 같은 CompositionLocal 제공자는 문서가 기록되는 순간의 로컬 앱 환경만 반영합니다. 표면의 크기가 조절되거나, 디스플레이 상태가 변경되거나, 시간이 지남에 따라 원격 호스트에서 동적으로 업데이트되지 않습니다. 대신 구성요소의 현재 크기, RemoteConfiguration 또는 RemoteDensity와 같이 플레이어가 런타임에 호스트에서 확인하는 값을 사용합니다.

선언적 작업

표준 Compose에서 클릭 핸들러는 앱에서 실행되는 람다입니다. 호스트는 앱의 코드를 실행할 수 없으므로 원격 Compose에서는 대신 작업을 연결합니다(예: RemoteModifier.clickable(action) 사용). 작업은 valueChange를 사용하여 호스트에서 직접 원격 상태를 업데이트하거나 pendingIntentAction 또는 hostAction를 사용하여 앱 또는 호스트에 전달할 수 있습니다. 한 번의 클릭으로 여러 작업을 실행하려면 combinedAction를 사용합니다.

개략적인 패러다임 비교

특성 도메인

표준 Jetpack Compose

원격 작성

클릭 및 터치 이벤트

In-process synchronous lambdas

선언적 직렬화된 Action 객체

조건부 로직

Kotlin if 및 when 제어 흐름

표준 Kotlin if/when는 문서를 생성할 때 알려진 정적 상태에 대해 정상적으로 작동합니다.

동적 브랜치는 RemoteStateLayout를 사용합니다(UI 트리의 경우).

제어 흐름 루프

표준 Kotlin for 및 while 루프

표준 Kotlin 루프 (repeat, for, forEach)는 문서가 생성될 때만 실행됩니다. 호스트의 원격 상태를 반복할 수 없음

실행 호스트

앱 프로세스

런처 (AppWidget), Wear OS 위젯 또는 지원 플레이어가 있는 모든 폼 팩터

프로세스 수명 주기

재구성 및 렌더링을 위해 프로세스가 활성 상태로 유지되어야 함

프로세스가 UI 스냅샷 문서를 기록합니다. 원격 플레이어 엔진이 구성요소 트리를 파싱하고, 상태 변형을 추적하고, 앱을 다시 호출하지 않고 로컬에서 다시 그립니다.

부작용

코루틴 수명 주기 (LaunchedEffect)

호스트에서 사용할 수 없습니다. 컴포지션은 앱에서 실행되어 문서를 생성하므로 통합에서 컴포지션을 열어 두지 않는 한 코루틴 효과는 원격 UI를 구동할 수 없습니다.

상태 패러다임

로컬 메모리 상태 값

원시 값 대신 기호 상태 참조를 반환하는 팩토리 함수 (rememberMutableRemoteInt(), rememberNamedRemoteColor())