Android SDK 시작하기

Requirements

🚧

Minimum requirements on SleepTrack SDK for Android

  • Android 7.0 (API level 24) 혹은 더 높은 버전
  • Java 1.8 혹은 더 높은 버전
  • Android Gradle plugin 8.0 혹은 더 높은 버전

API Key

  • SleepTrack SDK를 사용하기 위해서는 API key가 필요합니다.
  • API key를 발급하는 방법에 대해서는 이 링크 API Key 생성하기를 참고하세요.

Getting Ready

Install SleepTrack SDK and Settings

  1. Android Studio를 이용하여 기본 프로젝트를 생성합니다.
  2. AndroidManifest.xml 파일을 열어 퍼미션을 추가합니다.
<manifest ...>
  	
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.RECORD_AUDIO" />
  <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
  <uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE"/>
  <uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>

  <application ...>
    ...
  </application>
</manifest>
    
  1. 앱 수준의 build.gradle 파일을 열어 lifecycle-service, okhttp, gson 및 asleepsdk를 추가합니다.
dependencies {
  ...
  implementation("androidx.lifecycle:lifecycle-service:2.8.7")
  implementation("com.squareup.okhttp3:okhttp:4.11.0")
  implementation("com.google.code.gson:gson:2.10")
  implementation("ai.asleep:asleepsdk:3.3.0")
}
dependencies {
		...
    implementation 'androidx.lifecycle:lifecycle-service:2.8.7'
    implementation 'com.squareup.okhttp3:okhttp:4.11.0'
    implementation 'com.google.code.gson:gson:2.10'
    implementation 'ai.asleep:asleepsdk:3.3.0'
}

Sleep Tracking with SleepTrack SDK

권한 획득

  • 필수 권한인 RECORD_AUDIO와 POST_NOTIFICATIONS(Android 13 이상)을 획득합니다.
class MainActivity : AppCompatActivity() {
  
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...

    ActivityCompat.requestPermissions(
      this@MainActivity,
      arrayOf(android.Manifest.permission.RECORD_AUDIO,
              android.Manifest.permission.POST_NOTIFICATIONS),
      0)
      ...
  }

UI 구성

  • 화면에 보여질 init, begin, end, report의 버튼을 만듭니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btn_init"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="200dp"
        android:text="init"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_begin"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="32dp"
        android:text="begin"
        app:layout_constraintEnd_toStartOf="@+id/btn_end"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_init" />

    <Button
        android:id="@+id/btn_end"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="32dp"
        android:text="end"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/btn_begin"
        app:layout_constraintTop_toBottomOf="@+id/btn_init" />

    <Button
        android:id="@+id/btn_report"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:text="report"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/btn_init" />
          
</androidx.constraintlayout.widget.ConstraintLayout>
  • 버튼을 변수로 선언합니다.
    ...
    private lateinit var btnInit: Button
    private lateinit var btnBegin: Button
    private lateinit var btnEnd: Button
    private lateinit var btnReport: Button

    ...
    btnInit = findViewById(R.id.btn_init)
    btnBegin = findViewById(R.id.btn_begin)
    btnEnd = findViewById(R.id.btn_end)
    btnReport = findViewById(R.id.btn_report)

SleepTrack SDK 초기화

  • apiKey의 [YOUR API KEY]에는 실제 발급받은 apiKey를 입력합니다.
  • userId가 null인 경우, SDK에서 새로운 userId를 생성합니다.
    실제 앱 구현 시, 생성된 userId는 저장 후 필요 시 가져와서 입력하는 방식으로 사용해야 합니다.
  • service는 개발할 앱의 서비스명이 있다면 입력하세요.
  • asleepConfigListener는 초기화에 성공, 실패 여부를 콜백합니다.
    • 성공시 userId와 asleepConfig가 반환됩니다.
val TAG = "[AsleepSDK]"
private var createdUserId: String? = null
private var createdAsleepConfig: AsleepConfig? = null
private var createdSessionId: String? = null

...
btnInit.setOnClickListener {
  Asleep.initAsleepConfig(
    context = this,
    apiKey = "[YOUR API KEY]",
    userId = null,
    service = "Test App",
    asleepConfigListener = object: Asleep.AsleepConfigListener {
      override fun onFail(errorCode: Int, detail: String) {
        Log.d(TAG, "initAsleepConfig onFail $errorCode $detail")
      }

      override fun onSuccess(userId: String?, asleepConfig: AsleepConfig?) {
        Log.d(TAG, "initAsleepConfig onSuccess $userId")
        createdUserId = userId
        createdAsleepConfig = asleepConfig
      }
    })
}

Begin SleepTracking

  • 수면 측정을 시작합니다.
    1. initAsleepConfig에서 생성된 asleepConfig와 수면 측정 상태를 확인할 수 있는 asleepTrackingListener를 입력합니다.
    2. 측정이 시작되면 onStart() 콜백이 호출됩니다.
    3. 매 30초마다 onPerform() 콜백이 호출되어 진행 상태를 제공합니다.
    4. 측정이 종료되면 onFinish() 콜백이 호출됩니다.
btnBegin.setOnClickListener {
  createdAsleepConfig?.let { asleepConfig ->

    Asleep.beginSleepTracking(
      asleepConfig = asleepConfig,
      asleepTrackingListener = object : Asleep.AsleepTrackingListener {
        override fun onFail(errorCode: Int, detail: String) {
          Log.d(TAG, "beginSleepTracking onFail $errorCode $detail")
        }

        override fun onFinish(sessionId: String?) {
          Log.d(TAG, "beginSleepTracking onFinish $sessionId")
        }

        override fun onPerform(sequence: Int) {
          Log.d(TAG, "beginSleepTracking onPerform $sequence")
        }

        override fun onStart(sessionId: String) {
          Log.d(TAG, "beginSleepTracking onStart $sessionId")
          createdSessionId = sessionId
        }
      })
  }
}

End SleepTracking

  • 수면 측정을 종료합니다.
btnEnd.setOnClickListener {
  Asleep.endSleepTracking()
}

Get Report

  • 측정된 수면 데이터를 받아옵니다.
    1. initAsleepConfig에서 생성된 asleepConfig를 파라메터로 입력하여 Reports 객체를 만듭니다.
    2. 수면 측정 시 생성된 sessionId를 입력합니다.
btnReport.setOnClickListener {
  createdSessionId?.let { sessionId ->

    val reports = Asleep.createReports(createdAsleepConfig)

    reports?.getReport(
      sessionId = sessionId,
      reportListener = object : Reports.ReportListener {
        override fun onFail(errorCode: Int, detail: String) {
          Log.d(TAG, "getReport onFail $errorCode $detail")
        }
        override fun onSuccess(report: Report?) {
          Log.d(TAG, "getReport onSuccess $report")
        }
      })
  }
}

Logcat 확인

  • logcat 로그에 아래와 같이 userId, sessionId, report가 성공적으로 생성되었다면, SDK가 정상적으로 동작하고 있는 것입니다.

⚠️

앱 개발시 주의점

  • 포그라운드 서비스 사용
    수면 측정을 위해, 앱은 밤 동안 지속적인 레코딩, 데이터 처리, 네트워크 작업 등을 수행해야 합니다. 이러한 작업이 중단되지 않도록 하기 위해, **포그라운드 서비스(Foreground Service)**를 활용하여 앱을 개발하는 것이 필수적입니다.
    더 자세한 내용은 Android 포그라운드 서비스 가이드를 참조하세요.
    저희 SDK는 두 가지 개발 방식을 지원합니다
    1. Begin-End 방식
      포그라운드 서비스를 SDK 내부에 포함하여, 수면 측정과 관련된 모든 작업을 추상화했습니다.
      개발자는 포그라운드 서비스를 앱에서 구현할 필요가 없고 beginSleepTracking() 및 endSleepTracking() 함수만 호출하여 간편하게 수면 측정 기능을 구현할 수 있습니다. Begin-End 방식 샘플 앱을 참고하세요.
    2. SleepTrackingManager 방식
      포그라운드 서비스를 직접 구현하여 더 많은 제어를 제공하는 방식입니다.
      이 방식은 다소 복잡할 수 있으나, 슬립 스테이지(Sleep Stage)에 따라 하드웨어를 제어하거나 특정 커스텀 작업이 필요한 경우 적합합니다. FGS 프로세스 분리 샘플 앱을 참고하세요.
      개발하려는 앱의 요구 사항에 따라 적합한 방식을 선택하세요.
      다양한 통합 방식별 브랜치는 빠른 시작의 샘플앱 브랜치 안내를 참고하세요.
  • 인앱 업데이트 기능 권장 인앱 업데이트 가이드
    1. 안드로이드 사용자 설정에 따라 수면측정 시작 후 앱 업데이트가 자동으로 이뤄지게 되면 의도치 않은 앱 종료로 수면 측정중 비정상 종료가 발생하게 됩니다. 이러한 상황을 방지하고자 미리 업데이트를 받을 수 있는 인앱 업데이트라는 기능을 사용하게 되면 의도치 않은 상황을 줄일 수 있습니다.
  • 배터리 최적화 예외 권한 안내 doze-standby
    1. 수면 측정의 안정성을 보장하기 위해 배터리 최적화 예외 권한이 필요합니다.
      이 권한은 수면 측정 중 Doze 모드로 전환되는 것을 방지하기 위해 사용되며, REQUEST_IGNORE_BATTERY_OPTIMIZATIONS 권한을 통해 설정됩니다.

Did this page help you?