1. 개발 환경 설정

필요한 도구

  • Android Studio (최신 버전)
  • Wear OS SDK
  • Kotlin Plugin (기본 포함)

Android Studio 설정

  1. Android Studio 설치
  2. SDK Manager에서 Wear OS SDK 설치
  3. Virtual Device Manager에서 Wear OS 에뮬레이터 생성

2. 프로젝트 생성

New Project 생성

File → New → New Project → Wear OS → Empty Activity

프로젝트 구조

wear/
├── src/main/
│   ├── kotlin/
│   │   └── com.example.wearapp/
│   │       └── MainActivity.kt
│   ├── res/
│   │   └── layout/
│   │       └── activity_main.xml
│   └── AndroidManifest.xml
└── build.gradle.kts

3. build.gradle.kts 설정

plugins {
    id("com.android.application")
    id("org.jetbrains.kotlin.android")
}
 
android {
    namespace = "com.example.wearapp"
    compileSdk = 34
 
    defaultConfig {
        applicationId = "com.example.wearapp"
        minSdk = 30  // Wear OS 3.0
        targetSdk = 34
        versionCode = 1
        versionName = "1.0"
    }
}
 
dependencies {
    // Wear OS 기본 라이브러리
    implementation("androidx.wear:wear:1.3.0")
 
    // Jetpack Compose for Wear OS
    implementation("androidx.wear.compose:compose-material:1.3.0")
    implementation("androidx.wear.compose:compose-foundation:1.3.0")
 
    // Activity
    implementation("androidx.activity:activity-compose:1.8.2")
 
    // Kotlin
    implementation("org.jetbrains.kotlin:kotlin-stdlib:1.9.22")
}

4. MainActivity.kt 기본 구조

전통적인 View 방식

package com.example.wearapp
 
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.wear.widget.WearableLinearLayoutManager
import androidx.wear.widget.WearableRecyclerView
 
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        // Wear OS 특화 UI 초기화
    }
}

Jetpack Compose 방식 (권장)

package com.example.wearapp
 
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.wear.compose.material.*
 
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            WearApp()
        }
    }
}
 
@Composable
fun WearApp() {
    MaterialTheme {
        Scaffold(
            timeText = { TimeText() }
        ) {
            Column(
                modifier = Modifier.fillMaxSize(),
                verticalArrangement = Arrangement.Center,
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Text(
                    text = "Hello Wear OS!",
                    textAlign = TextAlign.Center,
                    style = MaterialTheme.typography.title2
                )
                Spacer(modifier = Modifier.height(8.dp))
                Button(onClick = { /* 버튼 클릭 처리 */ }) {
                    Text("Click Me")
                }
            }
        }
    }
}

5. AndroidManifest.xml 설정

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
 
    <uses-feature android:name="android.hardware.type.watch" />
 
    <!-- 권한 설정 -->
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.VIBRATE" />
 
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.DeviceDefault">
 
        <!-- Wear OS 기능 선언 -->
        <uses-library
            android:name="com.google.android.wearable"
            android:required="true" />
 
        <meta-data
            android:name="com.google.android.wearable.standalone"
            android:value="true" />
 
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
 
</manifest>

6. Wear OS UI 컴포넌트

ScalingLazyColumn (스크롤 리스트)

@Composable
fun WearableList() {
    ScalingLazyColumn(
        modifier = Modifier.fillMaxSize()
    ) {
        items(10) { index ->
            Chip(
                onClick = { /* 항목 클릭 */ },
                label = { Text("Item $index") }
            )
        }
    }
}

Card (카드 UI)

@Composable
fun WearableCard() {
    Card(
        onClick = { /* 카드 클릭 */ }
    ) {
        Text(
            text = "Card Content",
            modifier = Modifier.padding(16.dp)
        )
    }
}

TimeText (상단 시간 표시)

@Composable
fun AppWithTime() {
    Scaffold(
        timeText = {
            TimeText(
                timeTextStyle = TimeTextDefaults.timeTextStyle(
                    fontSize = MaterialTheme.typography.caption1.fontSize
                )
            )
        }
    ) {
        // 앱 콘텐츠
    }
}

7. 센서 및 하드웨어 활용

심박수 센서

import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
import android.hardware.SensorManager
 
class HeartRateMonitor(context: Context) : SensorEventListener {
    private val sensorManager = context.getSystemService(Context.SENSOR_SERVICE) as SensorManager
    private val heartRateSensor = sensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE)
 
    fun startMonitoring() {
        sensorManager.registerListener(
            this,
            heartRateSensor,
            SensorManager.SENSOR_DELAY_NORMAL
        )
    }
 
    override fun onSensorChanged(event: SensorEvent?) {
        event?.let {
            val heartRate = it.values[0]
            // 심박수 처리
        }
    }
 
    override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
 
    fun stopMonitoring() {
        sensorManager.unregisterListener(this)
    }
}

가속도계

val accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)

8. 알림 및 컴플리케이션

알림 표시

import android.app.NotificationChannel
import android.app.NotificationManager
import androidx.core.app.NotificationCompat
 
fun showNotification(context: Context) {
    val channelId = "wear_channel"
    val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
 
    val channel = NotificationChannel(
        channelId,
        "Wear Notifications",
        NotificationManager.IMPORTANCE_DEFAULT
    )
    notificationManager.createNotificationChannel(channel)
 
    val notification = NotificationCompat.Builder(context, channelId)
        .setContentTitle("Wear OS 알림")
        .setContentText("메시지 내용")
        .setSmallIcon(R.drawable.ic_notification)
        .build()
 
    notificationManager.notify(1, notification)
}

9. 실행 및 디버깅

에뮬레이터에서 실행

  1. AVD Manager에서 Wear OS 디바이스 생성
  2. Run → Run ‘wear’ 선택
  3. 에뮬레이터에서 앱 확인

실제 기기에서 실행

  1. 갤럭시 워치에서 개발자 옵션 활성화
  2. ADB 디버깅 활성화
  3. USB 또는 Wi-Fi로 연결
  4. Android Studio에서 기기 선택 후 실행

로그 확인

import android.util.Log
 
Log.d("WearApp", "Debug message")
Log.e("WearApp", "Error message")

10. 최적화 팁

배터리 효율

  • 센서는 필요할 때만 활성화
  • 백그라운드 작업 최소화
  • doze 모드 고려

UI/UX

  • 원형 디스플레이 고려 (Round/Square 대응)
  • 터치 영역 충분히 크게 (최소 48dp)
  • 짧은 인터랙션 설계
  • Ambient 모드 지원

성능

  • 가벼운 이미지 사용
  • 불필요한 애니메이션 제거
  • 메모리 사용 최소화

11. 유용한 라이브러리

// Health Services (건강 데이터)
implementation("androidx.health:health-services-client:1.0.0-beta03")
 
// DataStore (데이터 저장)
implementation("androidx.datastore:datastore-preferences:1.0.0")
 
// Navigation (화면 전환)
implementation("androidx.wear.compose:compose-navigation:1.3.0")

12. 참고 자료