Get Started
์๋ฉด ์ธก์ ์ ์๋ด ์ฌํญ์ ๋ฐ๋ผ์ฃผ์๊ธฐ ๋ฐ๋๋๋ค.
AsleepTrack์ ์๋ฉด ์ธก์ /๋ถ์ ๊ธฐ๋ฅ์ ์ ํํ๊ฒ ํ ์คํธํ๋ ค๋ฉด, โจํ ์คํธ ํ๊ฒฝ ๊ฐ์ด๋๋ฅผ ๋ฐ๋์ ๋ฐ๋ผ์ฃผ์๊ธฐ ๋ฐ๋๋๋ค. ์ด ๊ฐ์ด๋๋ฅผ ์ค์ํ์ง ์์ ํ๊ฒฝ์์ ์ป์ ์๋ฉด ๋ถ์ ๊ฒฐ๊ณผ๋ โจ์ค์ ์๋ฉด ํจํด๊ณผ ์ ํํ๊ฒ ์ผ์นํ์ง ์์ ์ ์์์ ์ ์ํด์ฃผ์ธ์.
- ์๋ฉด ์ธก์ ์ ์ต์ 20๋ถ ์ด์์ ์ค๋์ค๊ฐ ์ ๋ก๋ ๋์ด์ผ ๋ถ์์ด ์์๋๋ฉฐ, ๊ทธ ์ดํ๋ก๋ ํ๋(๊ณ์ฝ ์กฐ๊ฑด)์ ๋ฐ๋ผ 5๋ถ ๋๋ 20๋ถ ๊ฐ๊ฒฉ์ผ๋ก ๋ถ์ํฉ๋๋ค.
๐ Test Environment Guideline ํ์ธํ๊ธฐ- AsleepTrack์ ์๋ฉด ์ธก์ /๋ถ์ ๊ธฐ๋ฅ์ ํ์ธํด ๋ณผ ์ ์๋ ๋ํ ์ํ ์ฝ๋๋ฅผ ์ ๊ณตํฉ๋๋ค.
๐ Sample App ํ์ธํ๊ธฐ- Android SDK๋ฅผ ์ด์ฉํ ์๋ฉด ๋ชจ๋ํฐ๋ง ์ฑ์ ์ฌ์ฉํ ๋ ๋ค๋ฅธ ๋ น์/๋ นํ ์ฑ๊ณผ ๊ฐ์ด ์คํ ์ค์ด๋ฉด ์๋ฉด ์ธก์ ์ด ์ ์์ ์ผ๋ก ์๋ํ์ง ์์ต๋๋ค.
- OS version 9 ์ดํ ์์๋ ์ค์ง ํ ๊ฐ์ ์ฑ์์๋ง Audio ๋ น์ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ฉฐ, ๋จผ์ ์คํ๋ ์ฑ์์๋ง ๋ ์ ์ด ๊ฐ๋ฅํ๊ณ ๋ค๋ฅธ ์ฑ์์๋ Audio ๋ น์ ์คํ์ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค.
- OS version 10 ์ด์์์๋ ๋ ๊ฐ ์ด์์ Audio ๋ น์์ฑ ์คํ์ ๊ฐ์ฅ ๋์ค์ ์คํ๋ Audio ๊ด๋ จ๋ ์ฑ์์ ์ ์์ ์ผ๋ก ๋ น์์ด ๋๊ณ ์ด์ ์ ์คํ๋ ์ฑ๋ค์ Silence ์ฒ๋ฆฌ๋์ด ์๋ฉด ๋ชจ๋ํฐ๋ง ๋ถ์์ ์ ์์ ์ธ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์๊ฐ ์์ต๋๋ค.
Android Developer Site
์ธ์ฑ ์ ๋ฐ์ดํธ
์ฑ ์ฌ์ฉ์ ์ค์ ์ ๋ฐ๋ผ ์ฑ ์๋ ์ ๋ฐ์ดํธ๊ฐ ์ด๋ค์ง ์ ์์ต๋๋ค. ์๋ฉด์ธก์ ์์ ํ ์ฑ ์ ๋ฐ์ดํธ๊ฐ ์๋์ผ๋ก ์ด๋ค์ง๊ฒ ๋๋ฉด ์๋์น ์์ ์ฑ ์ข ๋ฃ๋ก ์๋ฉด ์ธก์ ์ค ๋น์ ์ ์ข ๋ฃ๊ฐ ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค.
์ด๋ฌํ ์ํฉ์ ๋ฏธ์ฐ์ ๋ฐฉ์งํ๊ณ ์ ๋ฏธ๋ฆฌ ์ ๋ฐ์ดํธ๋ฅผ ๋ฐ์ ์ ์๋ ์ธ์ฑ ์ ๋ฐ์ดํธ๋ผ๋ ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ฒ ๋๋ฉด ์๋์น ์์ ์ํฉ์ ์ค์ผ ์ ์์ต๋๋ค.
1. Requirements
1.1 Minimum requirements on AsleepTrack SDK for Android
- Android 8.0 (API level 26) ํน์ ๋ ๋์ ๋ฒ์
- Java 1.8 ํน์ ๋ ๋์ ๋ฒ์
- Android Gradle plugin 8.0 ํน์ ๋ ๋์ ๋ฒ์
1.2 API Key
- AsleepTrack SDK๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด์๋ API key๊ฐ ํ์ํฉ๋๋ค.
- API key๋ฅผ ๋ฐ๊ธํ๋ ๋ฐฉ๋ฒ์ ๋ํด์๋ ์ด ๋งํฌ Generate API key๋ฅผ ์ฐธ๊ณ ํ์ธ์.
2. Getting Ready
2.1 Install AsleepTrack SDK and Settings
- Android Studio๋ฅผ ์ด์ฉํ์ฌ ํ๋ก์ ํธ๋ฅผ ์์ฑํฉ๋๋ค.
- AndroidManifest.xml ํ์ผ์ ์ด์ด ํผ๋ฏธ์ ์ ์ถ๊ฐํฉ๋๋ค.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<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"/>
...
FOREGROUND_SERVICE ๊ถํ์ ์ฑ ๊ฐ๋ฐ์ ํ์ํฉ๋๋ค.
๊ฐ๋ฐํ ์ฑ์ด ๋ฐค ์ค์ ๋๊น์์ด ์๋ฉด์ ์ธก์ ํ๊ฒ ํ๋ ค๋ฉด FOREGROUND_SERVICE๋ก SDK๋ฅผ ์ฌ์ฉํ์ฌ์ผ ํฉ๋๋ค.
https://developer.android.com/guide/components/foreground-services
์ฑ์์ Asleep SDK๋ฅผ ์ ์ฉํ ๋, Google ๋ผ์ด๋ธ๋ฌ๋ฆฌ(gms, chrome)์ ์ ๋ฐ์ดํธ๋ก ์ธํด ์๋ฉด ์ธก์ ์ค ์๋์น ์๊ฒ ์ฑ์ด ๊ฐ์ ๋ก ์ข ๋ฃ๋๋ ํ์์ ๋ฐฉ์งํ๊ธฐ ์ํด foreground service์ process๋ฅผ ๋ถ๋ฆฌํ๋ ์์ ์ด ํ์ํฉ๋๋ค.
์ด์ ๋ํ FGS ํ๋ก์ธ์ค๊ฐ ๋ถ๋ฆฌ๋ ์ํ ์ฑ์ ์ฝ๋๋ฅผ ์ฐธ๊ณ ํ์๊ธฐ ๋ฐ๋๋๋ค.
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS ๊ถํ์ ์์ ์ ์ธ ์๋ฉด์ธก์ ์ ์ํด ํ์ํฉ๋๋ค.
๋์ฆ ๋ชจ๋์ ๋น ์ง๋ ๊ฒ์ ๋ฐฉ์งํ๊ธฐ ์ํด ํด๋น ๊ถํ์ด ํ์ํฉ๋๋ค.
https://developer.android.com/training/monitoring-device-state/doze-standby
- ์ฑ ์์ค์ build.gradle ํ์ผ์ ์ด์ด okhttp, gson ๋ฐ asleepsdk๋ฅผ ์ถ๊ฐํฉ๋๋ค.
plugins {
...
}
android {
...
}
dependencies {
...
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
implementation 'com.google.code.gson:gson:2.10'
implementation 'ai.asleep:asleepsdk:2.4.3'
}
- ๋ง์ดํฌ ๋ น์ ๊ธฐ๋ฅ๊ณผ FGS์ notification์ ์ํ ๊ถํ ์์ค์ฝ๋๋ฅผ ์์ฑํฉ๋๋ค.
ActivityCompat.requestPermissions(requireActivity(),
arrayOf(android.Manifest.permission.RECORD_AUDIO,
android.Manifest.permission.POST_NOTIFICATIONS),
0)
3. Sleep Tracking with AsleepTrack SDK
3.1 Step 1: Initialize the AsleepTrack SDK
- 1.2์์ ๋ฐ๊ธ๋ฐ์ apiKey๋ฅผ ์ ๋ ฅํฉ๋๋ค.
- userId๊ฐ null์ด๋ฉด ์๋ก์ด userId๊ฐ ์์ฑ๋ฉ๋๋ค.
- baseUrl์๋ ํ๋ก์ ์๋ฒ์ url ์ ๋ ฅํ์ธ์. null์ด๋ฉด default base url์ด ์ฌ์ฉ๋ฉ๋๋ค.
- callbackUrl์ ๋ถ์ ๊ฒฐ๊ณผ๋ฅผ ์ง์ ๋ฐ๋ ์๋ฒ์ url์ ์ ๋ ฅํ์ธ์. null์ด๋ฉด ์ฝ๋ฐฑ์ด ์์ต๋๋ค.
- service๋ ๊ฐ๋ฐํ ์ฑ์ ๋๋ค์์ด ์๋ค๋ฉด ์ ๋ ฅํ์ธ์.
import ai.asleep.asleepsdk.Asleep
import ai.asleep.asleepsdk.data.AsleepConfig
import ai.asleep.asleepsdk.AsleepErrorCode
...
Asleep.initAsleepConfig(
context = applicationContext,
apiKey = "[input your apiKey]",
userId = null,
baseUrl = null,
callbackUrl = null,
service = "[input your AppName]",
object : Asleep.AsleepConfigListener {
override fun onSuccess(userId: String?, asleepConfig: AsleepConfig?) {
...
/* save userId and asleepConfig */
}
override fun onFail(errorCode: Int, detail: String) {
...
}
})
3.2 Step 2: Create SleepTrackingManager
- initAsleepConfig์์ ๋ฐ์์จ AsleepConfig๋ฅผ ํ๋ผ๋ฉํฐ๋ก ์ ๋ ฅํฉ๋๋ค.
import ai.asleep.asleepsdk.tracking.SleepTrackingManager
...
var sleepTrackingManager = Asleep.createSleepTrackingManager(asleepConfig, object : SleepTrackingManager.TrackingListener {
override fun onCreate() {
}
override fun onUpload(sequence: Int) {
}
override fun onClose(sessionId: String) {
...
/* save sessionId */
}
override fun onFail(errorCode: Int, detail: String) {
}
})
3.3 Step 3: Start Tracking
- ์ธก์ ์์ํ๊ธฐ
- ์์์ ํ๋ฉด SleepTrackingManager ์์ฑ ์ ๋ฑ๋กํ ๋ฆฌ์ค๋์ onUpload ํจ์์์ 30์ด๋ง๋ค ์ํ์ค ๊ฐ์ด ์ฝ๋ฐฑ๋ฉ๋๋ค.
sleepTrackingManager?.startSleepTracking()
- ์ธก์ ์ค ๋ถ์ํ๊ธฐ
- session์ ๋ํ ์ ๋ณด๋ session data type ์ฐธ์กฐํ์ธ์.
sleepTrackingManager?.requestAnalysis(object : SleepTrackingManager.AnalysisListener {
override fun onSuccess(session: Session) {
Log.d("", "${session.toString()}")
}
}
3.4 Step 4: Stop Tracking
- ์ ์ง๋ฅผ ํ๋ฉด SleepTrackingManager ์์ฑ ์ ๋ฑ๋กํ ๋ฆฌ์ค๋์ onCloseํจ์์์ sessionId๊ฐ ์ฝ๋ฐฑ๋ฉ๋๋ค.
sleepTrackingManager?.stopSleepTracking()
3.5 Step 5: Create Reports
- initAsleepConfig์์ ๋ฐ์์จ AsleepConfig๋ฅผ ํ๋ผ๋ฉํฐ๋ก ์ ๋ ฅํฉ๋๋ค.
val reports = Asleep.createReports(asleepConfig)
3.6 Step 6: Get Report
- sessionId ํ๋์ ๊ฒฐ๊ณผ ๋ฐ์์ค๊ธฐ
- sleepTracking์ ์ ์งํ์ ๋ ๋ฐ์์จ sessionId๋ฅผ ํ๋ผ๋ฉํฐ๋ก ์ ๋ ฅํฉ๋๋ค.
reports?.getReport(sessionId, object : Reports.ReportListener {
override fun onSuccess(report: Report?) {
}
override fun onFail(errorCode: Int, detail: String) {
}
})
- ๋ ์ง๋ก ๊ฒฐ๊ณผ ๋ฐ์์ค๊ธฐ
val today = LocalDate.now()
reports?.getReports(today.minusDays(7).toString(), today.toString(), "DESC", 0, 20, object : Reports.ReportsListener {
override fun onSuccess(reports: List<SleepSession>?) {
}
override fun onFail(errorCode: Int, detail: String) {
}
})
3.7 Step 7: Remove Session
- ์ธก์ ๊ธฐ๋ก ์ญ์ ํ๊ธฐ
- sessionId๋ฅผ ์ ๋ ฅํ์ฌ ์ธก์ ๊ธฐ๋ก์ ์ญ์ ํฉ๋๋ค.
reports?.deleteReport(sessionId, object : Reports.DeleteReportListener {
override fun onSuccess(sessionId: String?) {
}
override fun onFail(errorCode: Int, detail: String) {
}
})
- ๋์ ์ ๋ณด ์ ๋ถ ์ญ์ ํ๊ธฐ
- userId์ ์ธก์ ๋ ๊ธฐ๋ก์ ์ ๋ถ ์ญ์ ํฉ๋๋ค. ์ญ์ ๋ userId๋ ๋ ์ด์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
Asleep.deleteUser(object : Asleep.DeleteUserIdListener {
override fun onSuccess(userId: String?) {
}
override fun onFail(errorCode: Int, detail: String) {
}
})
3.8 Step 8: Continue Session
- v2.3.0 ์ด์๋ถํฐ ์ฌ์ฉ ๊ฐ๋ฅ
์๋๋ก์ด๋ OS์์๋ Google Play ์๋น์ค ํจํค์ง๊ฐ ์ ๋ฐ์ดํธ๋ ๋๊ฐ ์๋๋ฐ, ์ด๋ ๋์ ์ค์ธ ์ฑ์ foreground service๊ฐ ์์คํ ์ ์ํด ๊ฐ์ ๋ก ์ข ๋ฃ ํ ์ฌ์์ ๋ฉ๋๋ค. ์ด๋ sleepTrackingManager์ ๋์์ ์ด์ดํ ์ ์๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
์ฐ์ , foreground service๊ฐ ์์คํ ์ ์ํด ์ฌ์์๋๋ฉด LifecycleService()์ onStartCommand ํจ์๊ฐ ํธ์ถ์ด ๋ฉ๋๋ค.
์ด๋, Asleep.hasUnfinishedSession ํจ์๋ฅผ ์ด์ฉํ์ฌ ์ข ๋ฃ๋์ง ์์ ์ธ์ ์ด ์กด์ฌํ๋ค๋ฉด, AsleepSDK๋ด๋ถ์ ์ ์ฅ๋ AsleepConfig๋ฅผ ๊ฐ์ ธ์ sleepTrackingManager๋ฅผ ๋ค์ ์์ฑํ๊ณ startSleepTracking์ ํธ์ถํ์ฌ tracking์ ์ด์ดํ ์ ์์ต๋๋ค.
private var asleepConfig: AsleepConfig? = null
private var sleepTrackingManager: SleepTrackingManager? = null
...
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
if(Asleep.hasUnfinishedSession(applicationContext)) {
asleepConfig = Asleep.getSavedAsleepConfig(applicationContext, BuildConfig.ASLEEP_API_KEY)
sleepTrackingManager = Asleep.createSleepTrackingManager(asleepConfig, object : SleepTrackingManager.TrackingListener {
override fun onCreate() {
...
}
override fun onUpload(sequence: Int) {
...
}
override fun onClose(sessionId: String) {
...
}
override fun onFail(errorCode: Int, detail: String) {
...
}
}
...
sleepTrackingManager?.startSleepTracking()
}
...
}
Updated 20 days ago