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.1.5")
}
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.1.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?