🪄 Wear OS | Complication 탭 액션 구현 및 타일/칩 UI 정리

개요 (Intro)
오늘의 목표는 Wear OS 관련 컴포넌트에서 사용자 인터랙션(특히 콤플리케이션 탭)을 통해 앱을 열 수 있도록 안정적인 동작을 구현하고, 타일(Tile) 및 칩(Chip) UI를 정리해 원형 기기에서 잘리지 않도록 개선하는 것이었습니다.
해결하려던 문제는 콤플리케이션을 탭했을 때 앱(MainActivity)으로 안전하게 진입하도록 PendingIntent와 Intent의 플래그/extra를 적절히 설정하고, 타일에서 불필요하게 전체 목록을 노출하던 부분을 3줄(앱 이름/완료수·대상수/앱으로 가기 버튼)으로 간소화하는 것입니다.
📅 날짜: 2025.11.19
🎯 목표: Complication 탭 액션(앱 진입) 안정화, Tile/Chip UI 간소화 및 원형 컷오프 방지
🧰 기술: Kotlin, Wear OS Tiles/Complications, Android PendingIntent, DataLayer
문제 정의 (Problem / Motivation)
프로젝트의 Wear 모듈에서 다음과 같은 문제가 있었습니다:
- 콤플리케이션을 탭했을 때 앱으로 넘어가는 동작이 불분명하거나 extras가 안정적으로 전달되지 않아 앱 쪽에서 출처를 알기 어려운 경우가 있음.
- 타일에서 습관 전체 목록을 나열하면 UI가 복잡해지고, 원형 기기에서는 칩이 가장자리에서 잘리는 현상이 관찰됨.
특히 콤플리케이션의 tapAction은 PendingIntent를 통해 앱을 여는 방식이지만, PendingIntent의 플래그나 Intent의 설정(FLAG_UPDATE_CURRENT, FLAG_IMMUTABLE, 추가 extras 등)에 따라 동작이 달라질 수 있어 이를 명확히 구현할 필요가 있었습니다.
// 예: MainComplicationService에서 PendingIntent 생성 부분
val intent = Intent(this, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra("from_complication", true)
action = "com.billcorea.habit1007.ACTION_OPEN_FROM_COMPLICATION"
}
val pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
val pendingIntent = PendingIntent.getActivity(this, 0, intent, pendingIntentFlags)
해결 과정 (How I Solved It)
시도한 접근법과 적용한 변경 사항은 다음과 같습니다.
- 콤플리케이션 탭 시 앱으로 진입하는 Intent에 출처 표시를 위한 extras를 추가했습니다. (putExtra("from_complication", true))
- Intent에 고유 action을 넣어 앱 내에서 호출 출처를 더 명확히 구분할 수 있게 했습니다. (action = "com.billcorea.habit1007.ACTION_OPEN_FROM_COMPLICATION")
- PendingIntent 생성 시 FLAG_UPDATE_CURRENT와 FLAG_IMMUTABLE를 조합해 기존 PendingIntent를 최신화하고 보안성을 보장했습니다.
- 타일(`MainTileService`)은 전체 습관 목록을 노출하는 대신 요약 정보(완료 건수 / 대상 건수)와 앱으로 가기 버튼(Chip)만 표시하도록 간소화했습니다.
- 원형 기기에서의 칩 잘림 문제는 칩 너비/높이를 화면 크기 기반으로 보수적으로 계산하고 내부 패딩/아이콘 크기 조정, 항목 간 간격을 늘려 대응했습니다.
// 핵심: Complication 탭 액션에 Intent extras + 안전한 PendingIntent 플래그 적용
val intent = Intent(this, MainActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putExtra("from_complication", true)
action = "com.billcorea.habit1007.ACTION_OPEN_FROM_COMPLICATION"
}
val pendingIntentFlags = PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
val pendingIntent = PendingIntent.getActivity(this, 0, intent, pendingIntentFlags)
ShortTextComplicationData.Builder(...).setTapAction(pendingIntent).build()
이유: extras와 action을 넣으면 앱(예: MainActivity)에서 Intent를 검사해 "콤플리케이션에서 왔음"을 판별하고, 필요 시 특정 화면으로 바로 이동시키는 로직을 실행할 수 있기 때문입니다. FLAG_UPDATE_CURRENT는 PendingIntent 갱신을 보장하고, FLAG_IMMUTABLE은 보안 권장사항입니다.
결과 (Result)
적용 결과는 다음과 같습니다.
- 콤플리케이션 탭 시 앱이 안정적으로 열리고, Intent extra("from_complication") 또는 action으로 호출 출처를 앱에서 판단할 수 있게 되었습니다.
- 타일은 더 간결해져 정보 전달이 명확해졌고, 원형 화면에서 칩이 잘리는 문제를 완화할 수 있는 구조로 수정했습니다.
✅ Complication 탭에서 MainActivity로 안전하게 진입하도록 구현 완료
✅ 타일 레이아웃을 3줄(앱 이름/완료수·대상수/앱으로 가기 버튼)로 간소화 완료
느낀 점 / 회고 (Reflection)
- Wear OS에서는 각 플랫폼 컴포넌트(Complication/Tile)의 동작 방식을 정확히 이해하는 것이 중요합니다. 특히 PendingIntent와 Intent 플래그, action/extras 관리가 핵심입니다.
- 작은 UI 요소(칩, 패딩)는 원형 기기에서 큰 영향을 줍니다 — 항상 원형 안전 영역을 고려해 크기와 패딩을 설계해야 합니다.
- 다음 개선: 앱 쪽(MainActivity)에서 Intent의 action과 extras를 핸들링해 "콤플리케이션에서 진입했을 때 특정 화면(예: 오늘의 습관 상세)로 바로 이동"하는 로직을 추가할 계획입니다.
참고자료 (References)
- Android PendingIntent documentation
- Android Intents and Task flags (참고용)
- Wear OS developer guides
- 프로젝트 코드:
habitwear/src/main/java/com/billcorea/habit1007/complication/MainComplicationService.kt,habitwear/src/main/java/com/billcorea/habit1007/tile/MainTileService.kt
'모바일 앱(안드로이드)' 카테고리의 다른 글
| 🩺 Android | Health Connect 걸음 수 집계 캐시 & 상단바 최소 높이 적용 (1) | 2025.11.21 |
|---|---|
| 🦾 Android | 서식 캔버스 폼 - 이 앱 개발의 기본 지식 정리 (2) | 2025.11.17 |
| 개발일기: Wear OS Complication 클릭 시 앱 실행하기 (1) | 2025.11.15 |
| Android | Jetpack Compose로 Photo Picker 구현 (백포트 없이) (1) | 2025.11.13 |
| 개발일기: Wear OS Tile Chip 너비 문제 해결 (2) | 2025.11.11 |