These docs are for v1.0. Click to read the latest docs for v2.0.

Get Started

๐Ÿšง

์ˆ˜๋ฉด ์ธก์ • ์‹œ ์•ˆ๋‚ด ์‚ฌํ•ญ์„ ๋”ฐ๋ผ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค.

Asleep์˜ ์ˆ˜๋ฉด ์ธก์ •/๋ถ„์„ ๊ธฐ๋Šฅ์„ ์ •ํ™•ํ•˜๊ฒŒ ํ…Œ์ŠคํŠธํ•˜๋ ค๋ฉด, โ€จํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ ๊ฐ€์ด๋“œ๋ฅผ ๋ฐ˜๋“œ์‹œ ๋”ฐ๋ผ์ฃผ์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค. ์ด ๊ฐ€์ด๋“œ๋ฅผ ์ค€์ˆ˜ํ•˜์ง€ ์•Š์€ ํ™˜๊ฒฝ์—์„œ ์–ป์€ ์ˆ˜๋ฉด ๋ถ„์„ ๊ฒฐ๊ณผ๋Š” โ€จ์‹ค์ œ ์ˆ˜๋ฉด ํŒจํ„ด๊ณผ ์ •ํ™•ํ•˜๊ฒŒ ์ผ์น˜ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ์Œ์„ ์œ ์˜ํ•ด์ฃผ์„ธ์š”.

  • ์ˆ˜๋ฉด ์ธก์ •์€ ์ตœ์†Œ 20๋ถ„ ์ด์ƒ์˜ ์˜ค๋””์˜ค๊ฐ€ ์—…๋กœ๋“œ ๋˜์–ด์•ผ ๋ถ„์„์ด ์‹œ์ž‘๋˜๋ฉฐ, ๊ทธ ์ดํ›„๋กœ๋Š” ํ”Œ๋žœ(๊ณ„์•ฝ ์กฐ๊ฑด)์— ๋”ฐ๋ผ 5๋ถ„ ๋˜๋Š” 20๋ถ„ ๊ฐ„๊ฒฉ์œผ๋กœ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ”— Test Environment Guideline ํ™•์ธํ•˜๊ธฐ

1. Requirements

1.1 Minimum requirements on Asleep SDK for Android

๐Ÿšง

  • Android 8.0 (API level 26) ํ˜น์€ ๋” ๋†’์€ ๋ฒ„์ „
  • Java 1.8 ํ˜น์€ ๋” ๋†’์€ ๋ฒ„์ „
  • Android Gradle plugin 8.0 ํ˜น์€ ๋” ๋†’์€ ๋ฒ„์ „

1.2 API Key

์—์ด์Šฌ๋ฆฝ SDK๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” API key๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

API key๋ฅผ ๋ฐœ๊ธ‰ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ๋Š” ์ด ๋งํฌ Generate API key๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

2. Getting Ready

2.1 Install Asleep SDK and Settings

  1. Android Studio๋ฅผ ์ด์šฉํ•˜์—ฌ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
  2. ์ƒ์„ฑ๋œ ํ”„๋กœ์ ํŠธ ํด๋”์˜ [root]/app/libs ํด๋”์— AsleepSDK.aar ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  3. 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" />
		...
    

๐Ÿ“˜

REQUEST_IGNORE_BATTERY_OPTIMIZATIONS ๊ถŒํ•œ์€ ํ•„์ˆ˜๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค.

๋‹ค๋งŒ, ๋„์ฆˆ ๋ชจ๋“œ์— ๋น ์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ํ•ด๋‹น ๊ถŒํ•œ์ด ์žˆ์œผ๋ฉด ๋„์›€์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

https://developer.android.com/training/monitoring-device-state/doze-standby

๐Ÿ“˜

FOREGROUND_SERVICE ๊ถŒํ•œ์€ ์•ฑ ๊ฐœ๋ฐœ์‹œ ํ•„์š”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ฐœ๋ฐœํ•  ์•ฑ์ด ์‚ฌ์šฉ์ž๊ฐ€ ์ž ์ž๋Š” ์‹œ๊ฐ„์—๋„ ๋™์ž‘ํ•˜๊ฒŒ ํ•˜๋ ค๋ฉด ์ด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜์—ฌ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

https://developer.android.com/guide/components/foreground-services

  1. ์•ฑ ์ˆ˜์ค€์˜ build.gradle ํŒŒ์ผ์„ ์—ด์–ด okhttp, gson, npy ๋ฐ libs ํด๋”์˜ *.aar์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
plugins {
  ...
}

android {
	...
}

dependencies {
		...
    implementation 'org.jetbrains.bio:npy:0.3.5'
    implementation 'com.squareup.okhttp3:okhttp:4.9.0'
    implementation 'com.google.code.gson:gson:2.9.1'
    implementation fileTree(dir: 'libs', include: ['*.aar', '*.jar'], exclude: [])
}
  1. ์ ์ ˆํ•œ ์œ„์น˜์— permission ํš๋“์„ ์œ„ํ•œ source code๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.RECORD_AUDIO), 0)

3. Sleep Tracking with Asleep SDK

3.1 Step 1: Initialize the Asleep SDK

initAsleepConfig ํ•˜์—ฌ AsleepConfig ๋ฐ›์•„์˜ต๋‹ˆ๋‹ค.

apiKey, userId(๊ธฐ์กด์— ๋ฐ›์€ ๊ฒƒ์ด ์—†๋‹ค๋ฉด null), baseUrl(proxy server์˜ ์ฃผ์†Œ, ์—†๋‹ค๋ฉด null), callbackUrl(์„ธ์…˜์ด ๋ถ„์„๋œ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๋Š” ์ฃผ์†Œ), service(๊ฐœ๋ฐœํ•  ์•ฑ์˜ ๋‹‰๋„ค์ž„)์„ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

userId๊ฐ€ ์—†๋‹ค๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑํ•˜์—ฌ onSuccess()์—์„œ ๋ฐ˜ํ™˜ํ•ด์ฃผ๊ณ , ๊ธฐ์กด ์‚ฌ์šฉํ•˜๋˜ userId๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๊ฒ€์ฆ์„ ๊ฑฐ์นœ ํ›„ onSuccess()์—์„œ ๋ฐ˜ํ™˜ํ•ด์ค๋‹ˆ๋‹ค.

๋งŒ์•ฝ, ๊ธฐ์กด ์‚ฌ์šฉํ•˜๋˜ userId๊ฐ€ Tracking ์ค‘์ด๋ผ๋ฉด SDK๋‚ด๋ถ€์—์„œ ์ข…๋ฃŒ ์‹œํ‚ต๋‹ˆ๋‹ค.

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 = "",  
    baseUrl = null,  
    callbackUrl = "",  
    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

  1. ์ธก์ • ์‹œ์ž‘ํ•˜๊ธฐ

์‹œ์ž‘์„ ํ•˜๋ฉด SleepTrackingManager ์ƒ์„ฑ์‹œ ๋“ฑ๋กํ•œ listener์˜ onUploadํ•จ์ˆ˜์—์„œ 30์ดˆ์— ํ•œ๋ฒˆ์”ฉ ์‹œํ€€์Šค ๋„˜๋ฒ„๊ฐ€ ์ฝœ๋ฐฑ๋ฉ๋‹ˆ๋‹ค.

sleepTrackingManager?.startSleepTracking()
  1. ์ธก์ • ์ค‘ ๋ถ„์„ํ•˜๊ธฐ
sleepTrackingManager?.requestAnalysis(object : SleepTrackingManager.AnalysisListener {  
    override fun onSuccess(session: Session) {  
        Log.d("", "${session.toString()}")  
    }
}

session์— ๋Œ€ํ•œ ์ •๋ณด๋Š” API>Data API>Get a session ์ฐธ์กฐ

3.4 Step 4: Stop Tracking

์ •์ง€๋ฅผ ํ•˜๋ฉด SleepTrackingManager ์ƒ์„ฑ์‹œ ๋“ฑ๋กํ•œ listener์˜ onCloseํ•จ์ˆ˜์—์„œ sessionId๊ฐ€ ์ฝœ๋ฐฑ๋ฉ๋‹ˆ๋‹ค.

sleepTrackingManager?.stopSleepTracking()

3.5 Step 5: Create Reports

initAsleepConfig์—์„œ ๋ฐ›์•„์˜จ AsleepConfig๋ฅผ ํŒŒ๋ผ๋ฉ”ํ„ฐ๋กœ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

val reports = Asleep.createReports(asleepConfig)

3.6 Step 6: Get Report

  1. sessionId ํ•˜๋‚˜์˜ ๊ฒฐ๊ณผ ๋ฐ›์•„์˜ค๊ธฐ

sleepTracking์„ ์ •์ง€ํ–ˆ ๋•Œ ๋ฐ›์•„์˜จ sessionId๋ฅผ ํŒŒ๋ผ๋ฉ”ํ„ฐ๋กœ ์ž…๋ ฅํ•ฉ๋‹ˆ๋‹ค.

reports?.getReport(sessionId, object : Reports.ReportListener {
    override fun onSuccess(report: Report?) {
    }

    override fun onFail(errorCode: Int, detail: String) {
    }
})
  1. ๋‚ ์งœ๋กœ ๊ฒฐ๊ณผ ๋ฐ›์•„์˜ค๊ธฐ
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

  1. ์ธก์ • ๊ธฐ๋ก ์‚ญ์ œํ•˜๊ธฐ

sessionId๋ฅผ ์ž…๋ ฅํ•˜์—ฌ ํ•ด๋‹น ์ธก์ • ๊ธฐ๋ก์„ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.

reports?.deleteReport(sessionId, object : Reports.DeleteReportListener {
    override fun onSuccess(sessionId: String?) {
    }

    override fun onFail(errorCode: Int, detail: String) {
    }
})
  1. ๋‚˜์˜ ์ •๋ณด ์ „๋ถ€ ์‚ญ์ œํ•˜๊ธฐ

userId์™€ ์ธก์ •๋œ ๊ธฐ๋ก์„ ์ „๋ถ€ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค. ์‚ญ์ œ๋œ userId๋Š” ๋”์ด์ƒ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

Asleep.deleteUser(object : Asleep.DeleteUserIdListener {
    override fun onSuccess(userId: String?) {
    }

    override fun onFail(errorCode: Int, detail: String) {
    }
})