Ongoing Activity API를 사용하여 새로운 방식으로 Wear OS 사용자 관심 유도

1. 소개

a3457956a1735674.gif

위의 애니메이션 보기(진행 중인 활동 데모) 참고: 애니메이션 gif는 한 번만 실행됩니다. 애니메이션을 놓친 경우 페이지를 새로고침하세요.

시계 모드에서 타이머용 애니메이션 아이콘이 표시되고 사용자가 아이콘을 탭하면 타이머 앱이 실행됩니다.

진행 중인 활동(Ongoing Activity)은 Wear OS의 새로운 기능으로, 이 기능을 사용하면 Wear OS 사용자 인터페이스 내의 추가 영역에 지속적인 알림(Ongoing Notification)을 표시하여 사용자가 장기 실행 활동에 더 오래 머물게 할 수 있습니다.

지속적인 알림은 일반적으로 사용자가 활발하게 참여(예: 음악 연주)하거나 특정 방식으로 대기하면서 기기를 점유(예: 파일 다운로드, 동기화 작업, 활성 네트워크 연결)하는 백그라운드 작업이 있는 알림을 나타내는 데 사용됩니다.

예를 들어, Wear OS 사용자는 타이머 앱을 사용하여 이벤트 시간을 맞춘 다음 앱에서 벗어나 다른 작업을 시작할 수 있습니다(날씨 확인, 운동 시작 등).

사용자가 타이머 앱에서 벗어나면 일반적으로 앱은 일부 백그라운드 작업(서비스, 알람 관리자 등)에 연결된 지속적인 알림으로 전환되어 사용자에게 타이머의 남은 시간을 지속해서 알려줍니다.

사용자는 업데이트 알림을 보거나 알림과 상호작용할 수 있습니다.

하지만 사용자가 알림을 보려면 여전히 시계 모드 아래의 알림 트레이로 스와이프해야 하고, 올바른 알림을 찾는 방법이 다른 영역만큼 편리하지 않습니다.

Ongoing Activity API를 사용하면 앱은 편리하게 접근할 수 있는 여러 새 Wear OS 영역에 정보를 노출하여 사용자의 참여를 유지할 수 있습니다.

타이머 앱의 경우에는 사용자의 시계 화면에 탭할 수 있는 아이콘으로 정보를 표시할 수 있습니다(스크린샷 하단의 활동 표시기).

b65ade9bf43c526e.png

타이머 앱은 진행 중인 활동 목록을 표시하는 전역 앱 런처의 최근 섹션에도 표시될 수 있습니다.

1bc84dd2bd2d2b5d.png

전역 런처

가장 좋은 점은 이 작업을 위해 약 10줄의 코드만 추가하면 된다는 것입니다.

학습할 내용

  • 진행 중인 활동 생성 및 맞춤설정
  • 진행 중인 활동지속적인 알림에 연결
  • 기기와 에뮬레이터에서 진행 중인 활동 테스트
  • 진행 중인 활동에 상호작용(탭) 추가

빌드할 항목

기본 시계 모드 및 앱 런처의 최근 섹션에 현재 걷고 있는 지점을 표시하는 맞춤 진행 중인 활동을 사용하여 기존의 도보 추적 앱을 확장합니다.

기본 요건

2. 설정

이 단계에서는 환경을 설정하고 시작 프로젝트를 다운로드해 보겠습니다.

필요한 항목

  • Android 스튜디오
  • Wear OS 에뮬레이터(API 수준 30 이상)
  • 진행 중인 활동은 API 수준 30 이상에서만 사용할 수 있습니다.
  • 에뮬레이터를 처음 사용하시나요? 설정하는 방법은 여기를 참고하세요.

코드 다운로드

git이 설치되어 있으면 아래 명령어를 실행하여 이 저장소의 코드를 클론하면 됩니다. git이 설치되어 있는지 확인하려면 터미널이나 명령줄에 git --version을 입력하여 올바르게 실행되는지 확인합니다.

git clone https://github.com/android/codelab-ongoing-activity.git
cd ongoing-activity

git이 없는 경우 다음 버튼을 클릭하여 이 Codelab을 위한 모든 코드를 다운로드할 수 있습니다.

툴바에서 실행 구성을 변경하여 언제든지 Android 스튜디오에서 둘 중 하나의 모듈을 실행할 수 있습니다.

b059413b0cf9113a.png

Android 스튜디오에서 프로젝트 열기

  1. 'Welcome to Android Studio' 창에서 Open을 선택합니다.
  2. [Download Location] 폴더를 선택합니다.
  3. Android 스튜디오에서 프로젝트를 가져오면 Wear OS 에뮬레이터 또는 실제 기기에서 startfinished 모듈을 실행할 수 있는지 테스트합니다.
  4. start 모듈은 아래 스크린샷과 같이 표시됩니다. 이 모듈에서 모든 작업을 진행합니다.

a40cc0c7e7e28bcf.png

걷기 운동을 시작하여 앱을 사용해보겠습니다. 약 3초마다 포인트가 적립되기 시작합니다. 앱에서는 모의 데이터를 사용하므로 실제로 걸어 다닐 필요는 없습니다.

스와이프하여 앱을 닫습니다. 시계 화면 아래의 탐색 트레이로 이동하면 걷고 있는 지점을 계속 추적하는 지속적인 알림을 발견할 수 있습니다.

알림을 탭하면 다음과 같이 나타납니다.

ac48b3ddc2a093bb.png

36fed11735ef4807.png

걷기를 멈춰도 됩니다.

이 Codelab을 마치면 시계 모드와 전역 앱 런처의 최근 섹션에 동일한 걷기 정보가 표시됩니다.

시계 화면에 표시되는 앱의 모습은 다음과 같습니다(하단의 활동 표시기 참고).

59747518d70b053a.png

앱 런처최근 섹션에 표시되는 앱의 모습은 다음과 같습니다.

4817a55e6722629d.png

시작 코드 살펴보기

start 모듈에 포함된 파일은 다음과 같습니다.

  • build.gradle에는 기본 앱 구성이 포함되어 있습니다. 이 파일에는 진행 중인 활동을 생성하는 데 필요한 종속 항목이 포함됩니다.
  • manifest > AndroidManifest.xml에는 이를 Wear OS 애플리케이션으로 표시하는 데 필요한 요소가 포함되어 있습니다.
  • java > ... > data > WalkingWorkoutsRepository.ktWalkingWorkoutsDataStore.kt 클래스에 연결되어 걷고 있는 지점과 걷기 운동의 상태를 저장합니다. 이 Codelab에서는 이러한 클래스에 관해 자세히 검토하지 않아도 됩니다.
  • java > ... > MainApplication.kt는 저장소의 싱글톤을 만듭니다. 이 Codelab에서는 이러한 클래스에 관해 자세히 검토하지 않아도 됩니다.
  • java > ... > ForegroundOnlyWalkingWorkoutService.kt에는 걷기 운동 시작을 시작하고 중지하는 코드가 포함되어 있습니다. 운동이 진행 중이고 사용자가 앱에서 벗어나면 앱은 활동과의 바인딩이 해제되고 지속적인 알림을 시작하여 운동 지점에 관한 정보가 계속 사용자에게 전달됩니다(모의 데이터 사용). 알림 코드 근처에 진행 중인 활동 코드를 추가합니다.
  • java > ... > MainActivity.kt에는 사용자가 걷기 운동을 시작하고 중지할 수 있는 UI가 포함됩니다. 이 활동은 위의 서비스에 바인딩되어 운동과 관련된 모든 작업을 처리합니다.
  • java > ... > MainViewModel.ktMainActivity.kt의 UI가 아닌 코드를 처리하는 간단한 ViewModel입니다. 이 Codelab에서는 이러한 클래스에 관해 자세히 검토하지 않아도 됩니다.

3. 앱 검토

이 앱은 이미 작동하는 걷기 운동 앱입니다.

이전 단계에서 본 것처럼 앱을 실행하고 걷기 운동을 시작하거나 중지할 수 있습니다. 운동하는 중에 시간이 지날수록 걷고 있는 지점이 축적됩니다.

새로운 걷기 동작마다 걷고 있는 지점이 재설정됩니다.

운동 중에 앱에서 벗어난 경우 아래로 스와이프하면 지속적인 알림을 통해 업데이트된 진행 상황을 계속 확인할 수 있습니다.

이 알림에서 운동을 중지하거나 앱을 열 수 있습니다.

일반적으로, 독자적인 알고리즘을 사용하여 위치와 센서 데이터에서 걷고 있는 지점을 계산합니다. 여기에서는 모의 데이터를 처리하여 작업을 간단히 합니다.

기본 원리

MainActivity는 사용자 인터페이스를 생성하고, 운동 상태와 걷고 있는 지점을 업데이트하기 위해 ViewModel에 연결하며, 서비스에 바인딩합니다.

운동을 시작하거나 중지하면 MainActivity는 운동을 추적하는 복잡한 작업을 처리하기 위해 서비스에서 시작 또는 중지 역할을 하는 메서드를 호출합니다.

사용자가 다른 곳으로 이동하면 MainActivity는 간단히 서비스에서 바인딩을 해제합니다.

대부분의 놀라운 작업은 ForegroundOnlyWalkingWorkoutService에서 이뤄집니다. 이 클래스는 운동을 시작하거나 중지하고 상태나 걷고 있는 지점의 변경사항을 저장소에 저장합니다.

또한, 사용자가 세션 중에 MainActivity에서 벗어나면 서비스는 포그라운드 서비스로 전환되고 자체적으로 지속적인 알림에 연결됩니다.

지속적인 알림은 운동을 추적하는 작업을 실행하며 위의 서비스에 포그라운드 서비스로 연결됩니다.

일부 세부사항을 이해하지 못해도 괜찮습니다. 이 앱이 이미 빌드된 알림을 사용하여 작동하는 앱이라는 것을 이해하는 것이 중요합니다. Google은 진행 중인 활동을 통해 이 알림이 더 많은 영역에 표시되도록 확장하려고 합니다.

이 알림 코드는 ForegroundOnlyWalkingWorkoutService에 있으며 여기서 이 Codelab의 모든 작업을 실행합니다.

4. 진행 중인 활동 만들기

종속 항목 검토

이 단계에서는 코드를 작성하지 않습니다. 대신, 진행 중인 활동의 종속 항목을 검토합니다.

start 모듈에서 app/build.gradle 파일을 열고 'TODO: Review dependencies for Ongoing Activity'를 검색합니다.

다음과 같은 항목이 표시됩니다.

1단계

    // TODO: Review dependencies for Ongoing Activity.
    implementation libs.androidx.wear.ongoing
    // Includes LocusIdCompat and new Notification categories for Ongoing Activity.
    implementation libs.androidx.core.ktx

첫 번째 종속 항목은 Wear OS의 Ongoing Activity API를 사용하는 데 필요합니다.

두 번째 종속 항목은 진행 중인 활동과 함께 사용되는 다양한 기능을 지원하는 Notification API의 최신 기능을 가져옵니다. 다음 두 기능은 지속적인 알림에 적용할 수 있으므로 진행 중인 활동에도 적용할 수 있습니다.

  • 카테고리: Android는 사용자가 방해 금지 모드를 설정한 경우 사전에 정의된 일부 시스템 범위의 카테고리를 사용하여 어떤 알림을 사용자에게 알릴지 결정합니다. 카테고리는 시계 모드에 표시되는 진행 중인 활동의 우선순위를 결정합니다. 최근 Wear를 지원하기 위해 새로운 카테고리가 추가되었습니다.
  • LocusId: Locus는 Android 10(API 수준 29)에 도입된 새로운 개념으로 Android 시스템에서 다양한 하위 시스템 간의 상태 연관성(예: 콘텐츠 캡처, 바로가기, 알림)을 볼 수 있습니다. 런처가 여러 개 있는 경우 Locus ID를 사용하여 진행 중인 활동을 특정한 동적 Shortcut에 연결할 수 있으므로 진행 중인 활동이 앱 런처의 최근 섹션에 적절하게 표시됩니다.

지속적인 알림 코드 검토

이 단계에서는 코드를 작성하지 않습니다. 대신, 알림 코드만 검토합니다.

start 모듈에서 ForegroundOnlyWalkingWorkoutService.kt 파일을 열고 'TODO: Review Notification builder code'를 검색합니다.

다음과 같은 항목이 표시됩니다.

2단계

// TODO: Review Notification builder code.
val notificationBuilder = notificationCompatBuilder
    .setStyle(bigTextStyle)
    .setContentTitle(titleText)
    .setContentText(mainText)
    .setSmallIcon(R.mipmap.ic_launcher)
    .setDefaults(NotificationCompat.DEFAULT_ALL)
    // Makes Notification an Ongoing Notification (a Notification with a background task).
    .setOngoing(true)
    // Android uses some pre-defined system-wide categories to determine whether to
    // disturb the user with a given notification when the user has enabled Do Not Disturb
    // mode. The Category determines the priority of the Ongoing Activity and new
    // categories were added recently to support Wear
    .setCategory(NotificationCompat.CATEGORY_WORKOUT)
    .setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
    .addAction(
        R.drawable.ic_walk, getString(R.string.launch_activity),
        activityPendingIntent
    )
    .addAction(
        R.drawable.ic_cancel,
        getString(R.string.stop_walking_workout_notification_text),
        servicePendingIntent
    )

// TODO: Create an Ongoing Activity.
// SKIP TODO FOR REVIEW STEP

return notificationBuilder.build()

위의 코드를 검토하고 주석을 읽습니다(뒤에 나오는 TODO 섹션은 이후 단계를 위한 것이므로 건너뜀).

이 청크 위에는 이 빌더에 필요한 모든 항목을 설정하는 알림 코드가 더 많이 있습니다.

하지만, 이 Codelab에서는 알림 빌더의 setOngoing()setCategory() 호출에만 집중하면 됩니다.

카테고리는 Wear OS가 시계 모드에 표시되는 알림의 우선순위를 결정하는 데 도움이 됩니다.

setOngoing() 호출은 알림을 지속적인 알림, 즉 사용자가 적극적으로 참여하고 있는 백그라운드 작업(예: 걷기 운동)이 있는 알림으로 변경합니다.

사용자가 걷기 운동을 하고 있으면서 MainActivity에서 벗어나면 이 알림을 만듭니다.

진행 중인 활동 만들기

진행 중인 활동지속적인 알림에 연결되어야 합니다. 지속적인 알림이 있으므로 이제 진행 중인 활동을 만들어 보겠습니다.

'TODO: Create an Ongoing Activity'을 찾아 '// SKIP TODO FOR REVIEW STEP' 행을 아래 코드로 바꿉니다.

4단계

// TODO: Create an Ongoing Activity.
val ongoingActivityStatus = Status.Builder()
    // Sets the text used across various surfaces.
    .addTemplate(mainText)
    .build()

val ongoingActivity =
    OngoingActivity.Builder(applicationContext, NOTIFICATION_ID, notificationBuilder)
        // Sets icon that will appear on the watch face in active mode. If it isn't set,
        // the watch face will use the static icon in active mode.
        .setAnimatedIcon(R.drawable.animated_walk)
        // Sets the icon that will appear on the watch face in ambient mode.
        // Falls back to Notification's smallIcon if not set. If neither is set,
        // an Exception is thrown.
        .setStaticIcon(R.drawable.ic_walk)
        // Sets the tap/touch event, so users can re-enter your app from the
        // other surfaces.
        // Falls back to Notification's contentIntent if not set. If neither is set,
        // an Exception is thrown.
        .setTouchIntent(activityPendingIntent)
        // In our case, sets the text used for the Ongoing Activity (more options are
        // available for timers and stop watches).
        .setStatus(ongoingActivityStatus)
        .build()

// Applies any Ongoing Activity updates to the notification builder.
// This method should always be called right before you build your notification,
// since an Ongoing Activity doesn't hold references to the context.
ongoingActivity.apply(applicationContext)

진행 중인 활동을 만들기 전에 먼저 다양한 Wear OS 영역에 표시될 텍스트를 포함하는 진행 중인 활동 Status를 만듭니다.

Status.Builder.addTemplate()을 사용하여 텍스트를 알림에 사용하는 기본 텍스트로 설정합니다.

텍스트가 표시되는 모양(예: 색상, 굵기 등)을 맞춤설정할 수 있지만, 이 Codelab에서는 텍스트를 단순하게 유지합니다. 자세히 알아보려면 진행 중인 활동 가이드를 읽어보세요.

다음으로, OngoingActivity를 직접 만듭니다. 이 코드 위에서 생성한 컨텍스트, 알림 ID, 알림 빌더를 OngoingActivity.Builder()의 생성자로 전달합니다.

알림 ID와 NotificationCompat.Builder 인스턴스는 OngoingActivity를 지속적인 알림에 연결하는 중요한 역할을 합니다.

먼저 활성 모드의 시계 모드용 애니메이션 아이콘과 대기 모드의 시계 모드용 정적 아이콘을 설정합니다.

그런 다음 터치 이벤트를 설정하고 마지막으로 .build()로 문을 닫기 전에 이전에 만든 Status 객체를 사용하여 텍스트를 설정합니다.

OngoingActivity 사용자 인터페이스는 아이콘과 Status의 텍스트를 사용하여 제공됩니다. 터치 이벤트를 사용하면 사용자가 시계 모드 또는 전역 앱 런처의 최근 섹션에서 탭하여 앱으로 다시 돌아갈 수 있습니다.

마지막으로, 진행 중인 활동에 관해 apply()를 호출하고 컨텍스트를 전달합니다. 이는 진행 중인 활동의 변경사항을 알림 빌더에 적용하는 마지막 단계입니다.

이것으로 모든 작업을 완료했습니다.

이제 이 알림을 포함하는 notificationManager.notify(NOTIFICATION_ID, notification)를 호출하면 새 영역에 알림이 표시됩니다.

이제 새 Wear OS 에뮬레이터나 기기에서 앱을 실행합니다.

앱에서 걷기를 시작한 다음 스와이프하여 앱을 종료합니다.

시계 화면에서 이제 다음과 같이 작은 걷는 사람 아이콘(애니메이션 아님)이 표시됩니다.

59747518d70b053a.png

아이콘을 탭하면 앱으로 돌아갑니다.

이제 앱을 다시 나온 후 Wear OS 기기에서 앱 런처 버튼을 탭합니다.

다음과 같이 표시됩니다.

4817a55e6722629d.png

최근 섹션에서 걷기 앱을 탭했다면 앱을 다시 입력해야 합니다.

5. 축하합니다

축하합니다. Wear OS에서 진행 중인 활동을 빌드하는 방법을 알아보았습니다.

진행 중인 활동은 사용자를 Wear의 새로운 영역에 참여하도록 하는 좋은 방법입니다.

다음 단계

다른 Wear OS Codelab을 확인해 보세요.

추가 자료