Health Connect๋?
Google์ Health Connect๋ ๋ค์ํ ๊ฑด๊ฐ ๊ด๋ จ ๋ฐ์ดํฐ๋ฅผ ํตํฉ ๊ด๋ฆฌํ ์ ์๋๋ก ๋์์ฃผ๋ API์ด๋ค.
์ด๋ฅผ ํ์ฉํ๋ฉด ์ผ์ฑ ํฌ์ค์ผ์ด ๊ฐ์ ์ฑ์์ ๊ฑธ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์์ ํ์ฉํ ์ ์๋ค.
1. ํ๋ก์ ํธ ์ค์ (Gradle ์ค์ ํฌํจ)
๋จผ์ build.gradle.kts(Module:app) ํ์ผ์ Health Connect ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ค.
dependencies {
implementation("androidx.health.connect:connect-client:1.1.0-alpha10")
}
2. Health Connect SDK ์ํ ํ์ธ ๋ฐ ์ค์น ์ ๋
Health Connect๊ฐ ๊ธฐ๊ธฐ์ ์ค์น๋์ง ์์๊ฑฐ๋ ์ต์ ๋ฒ์ ์ด ์๋๋ผ๋ฉด, Play Store์์ ์ค์นํ๋๋ก ์ ๋ํด์ผ ํ๋ค.
๋ค์ ์ฝ๋๋ ์ฑ์ด ์คํ๋ ๋ Health Connect๊ฐ ์ค์น๋์ง ์์๋ค๋ฉด Play Store๋ก ์ด๋ํ๋๋ก ์ฒ๋ฆฌํ๋ค.
private fun checkInstallHC() {
val providerPackageName = "com.google.android.apps.healthdata"
val availabilityStatus = HealthConnectClient.getSdkStatus(this, providerPackageName)
if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE ||
availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) {
Toast.makeText(this, "ํฌ์ค ์ปค๋ฅํธ ์ฑ์ ์ค์น ๋๋ ์
๋ฐ์ดํธ ํด์ฃผ์ธ์", Toast.LENGTH_SHORT).show()
openPlayStoreForHealthConnect()
}
}
private fun openPlayStoreForHealthConnect() {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("https://play.google.com/store/apps/details?id=com.google.android.apps.healthdata")
setPackage("com.android.vending")
}
startActivity(intent)
}
3. ๊ถํ ์์ฒญ ๋ฐ ์ฒ๋ฆฌ ๋ฐฉ๋ฒ
Health Connect๋ฅผ ํตํด ๊ฑธ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ค๋ ค๋ฉด READ ๋ฐ WRITE ๊ถํ์ด ํ์ํ๋ค.
์๋ ์ฝ๋์์ ๊ถํ์ ์์ฒญํ๋ ๋ฐฉ๋ฒ์ ํ์ธํ ์ ์๋ค.
val PERMISSIONS = setOf(
HealthPermission.getReadPermission(StepsRecord::class),
HealthPermission.getWritePermission(StepsRecord::class)
)
private fun requestHealthPermissions() {
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()
val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
if (granted.containsAll(PERMISSIONS)) {
readStepsByTimeRange()
} else {
Toast.makeText(this, "์ฑ ๊ถํ โ '๊ฑธ์ ์'๋ฅผ ํ์ฑํ ํด์ฃผ์ธ์.", Toast.LENGTH_LONG).show()
}
}
requestPermissions.launch(PERMISSIONS)
}
4. ๊ฑธ์ ์ ๋ฐ์ดํฐ ์ฝ๊ธฐ
์ด์ readStepsByTimeRange ํจ์๋ฅผ ๊ตฌํํ์ฌ ์ฌ์ฉ์์ ๊ฑธ์ ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.
private suspend fun readStepsByTimeRange() {
try {
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
StepsRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
if (response.records.isEmpty()) {
mViewModel.totalSteps.value = "0"
} else {
mViewModel.totalSteps.value = response.records[0].count.toString()
}
} catch (e: Exception) {
Log.e("HealthConnect", "๊ฑธ์ ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์ค ์ค๋ฅ ๋ฐ์: $e")
}
}
5. ViewModel์ ์ด์ฉํ ๋ฐ์ดํฐ ๊ด๋ฆฌ
ViewModel์ ํ์ฉํ๋ฉด ๊ฑธ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ฑ์ UI์์ ์ฝ๊ฒ ๊ด๋ฆฌํ ์ ์๋ค.
class MainViewModel: ViewModel() {
val totalSteps = MutableLiveData<String>()
}
6. ๊ฒฐ๊ณผ ํ์ธ ๋ฐ ๋ก๊ทธ ์ถ๋ ฅ
์ฑ์ ์คํํ๋ฉด Health Connect์์ ์ผ์ฑ ํฌ์ค์ผ์ด์ ๊ฑธ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ UI์ ๋ฐ์ํ ์ ์๋ค.
๋ก๊ทธ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ํ์ธํ ์ ์๋ค.
Log.v("Total Steps", "๊ฑธ์ ์: ${mViewModel.totalSteps.value}")
์ ์ฒด์ฝ๋
<MainActivity>
package com.lion.walk_hyein
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.health.connect.client.HealthConnectClient
import androidx.health.connect.client.PermissionController
import androidx.health.connect.client.permission.HealthPermission
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.request.ReadRecordsRequest
import androidx.health.connect.client.time.TimeRangeFilter
import androidx.lifecycle.lifecycleScope
import com.lion.test3.MainViewModel
import kotlinx.coroutines.launch
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneOffset
import kotlin.getValue
class MainActivity : AppCompatActivity() {
lateinit var requestPermissions : ActivityResultLauncher<Set<String>>
lateinit var healthConnectClient : HealthConnectClient
private val mViewModel: MainViewModel by viewModels()
val endTime = LocalDateTime.now()
val startTime = LocalDateTime.of(endTime.toLocalDate(), LocalTime.MIDNIGHT)
val startTimeInstant = startTime.atZone(ZoneOffset.UTC).toInstant()
val endTimeInstant = endTime.atZone(ZoneOffset.UTC).toInstant()
val PERMISSIONS = setOf(
HealthPermission.getReadPermission(StepsRecord::class),
HealthPermission.getWritePermission(StepsRecord::class))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
lifecycleScope.launch {
checkInstallHC()
}
}
//ํฌ์ค์ปค๋ฅํธ ์ค์น, ๋ฒ์ , ๊ถํ ์ฌ๋ถ ํ์ธ
private fun checkInstallHC (){
val providerPackageName = "com.google.android.apps.healthdata"
val availabilityStatus = HealthConnectClient.getSdkStatus(this, providerPackageName)
//ํฌ์ค ์ปค๋ฅํธ ์ฑ์ด ์์ ๋
if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) {
Toast.makeText(this, "ํฌ์ค ์ปค๋ฅํธ ์ฑ์ ์ค์น ๋๋ ์
๋ฐ์ดํธ ํด์ฃผ์ธ์", Toast.LENGTH_SHORT).show()
finish()
//ํฌ์ค ์ปค๋ฅํธ ํ๋ ์ด์คํ ์ด ์ด๋
openPlayStoreForHealthConnect()
}
//ํฌ์ค ์ปค๋ฅํธ ์ฑ์ด ์ต์ ๋ฒ์ ์ด ์๋๋
if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) {
Toast.makeText(this, "ํฌ์ค ์ปค๋ฅํธ ์ฑ์ ์ค์น ๋๋ ์
๋ฐ์ดํธ ํด์ฃผ์ธ์", Toast.LENGTH_SHORT).show()
finish()
//ํฌ์ค ์ปค๋ฅํธ ํ๋ ์ด์คํ ์ด ์ด๋
openPlayStoreForHealthConnect()
}
healthConnectClient = HealthConnectClient.getOrCreate(this)
// ๊ถํ(permission)์ด ๋ถ์ฌ๋์ด ์๋์ง ํ์ธ
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()
requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
//๊ถํ์ด ๋ถ์ฌ๋ ์ํ
if (granted.containsAll(PERMISSIONS)) {
Log.d("Permission", "PermissionO : $healthConnectClient")
lifecycleScope.launch {
Log.d("TimeRange", "Start Time: $startTimeInstant, End Time: $endTimeInstant")
readStepsByTimeRange(healthConnectClient)
}
}
//๊ถํ์ด ๋ถ์ฌ๋์ง ์์ ์ํ๋ผ๋ฉด
else {
Log.d("Permission", "PermissionX : $healthConnectClient")
//๊ถํ ์ค์ ํ๋ฉด์ผ๋ก ์ด๋
movePermissionSetting(this)
}
}
requestPermissions.launch(PERMISSIONS)
}
//ํฌ์ค ์ปค๋ฅํธ ํ๋ ์ด์คํ ์ด ์ด๋
private fun openPlayStoreForHealthConnect(){
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("https://play.google.com/store/apps/details?id=com.google.android.apps.healthdata")
setPackage("com.android.vending")
}
startActivity(intent)
}
//๊ถํ ์ค์ ํ๋ฉด์ผ๋ก ์ด๋
private fun movePermissionSetting(context: Context) {
val packageName = "com.google.android.apps.healthdata"
val intent = packageManager.getLaunchIntentForPackage(packageName)
context.startActivity(intent)
Toast.makeText(context, "์ฑ ๊ถํ โ '๊ฑธ์ ์'๋ฅผ ํ์ฑํ ํด์ฃผ์ธ์.", Toast.LENGTH_LONG).show()
}
private suspend fun readStepsByTimeRange(
healthConnectClient: HealthConnectClient,
) {
try {
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
StepsRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
mViewModel.totalSteps.value = response.records[0].count.toString()
// records๊ฐ ๋น์ด์๋์ง ํ์ธํ๊ณ , ๋ก๊ทธ ์ถ๋ ฅ
if (response.records.isEmpty()) {
Log.v("Total Steps", "๋ฐ์ดํฐ ์์ - records ๋น์ด์์")
mViewModel.totalSteps.value = "0"
} else {
mViewModel.totalSteps.value = response.records[0].count.toString()
Log.v("Total Steps", "์คํ๋จ : ${mViewModel.totalSteps.value}")
}
} catch (e: Exception) {
Log.v("Total Steps", "์คํ ์๋จ : $e")
}
}
}
<MainViewModel>
package com.lion.walk_hyein
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class MainViewModel: ViewModel() {
val totalSteps = MutableLiveData<String>()
}
<build.gradle.kts(Module:app)>
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
}
android {
namespace = "com.lion.walk_hyein"
compileSdk = 35
defaultConfig {
applicationId = "com.lion.walk_hyein"
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
implementation("androidx.health.connect:connect-client:1.1.0-alpha10")
}
โ ๏ธ ํฌ์ค์ปค๋ฅํฐ์ ์ฐ๋์ ๊ฐ์ธ์ฐจ๊ฐ ํฌ๋ค. ๋๋ ๊ตฌํ์ด ๋๋์๋ง์ ๋ฐ๋ก ์ฐ๋๋์ด ์ ์์ ์ผ๋ก ์๋ํ์์ง๋ง, ๋ค๋ฅธ ํ์๋ถ๋ค์ ๋ช์๊ฐ ๋ค์ ์ ์ ์๋ ๋๊ธฐ๋ ํ๊ณ , ๋ฉฐ์น ๋ค์ ์ ์์๋ ๋๊ธฐ๋ ํ์๋ค.
๐ ์์ฉํ์ฌ ์๋ชจ ์นผ๋ก๋ฆฌ, ์ฌ๋ฐ์, ์๋ฉด ๋ฐ์ดํฐ ๋ฑ ๋ค์ํ ๊ฑด๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ฌ์๋ ์๋ค
์ฐธ๊ณ ๋ฌธ์
https://developer.android.com/health-and-fitness/guides/health-connect/develop/get-started?hl=ko
ํฌ์ค ์ปค๋ฅํธ ์์ํ๊ธฐ | Android health & fitness | Android Developers
์ด ํ์ด์ง๋ Cloud Translation API๋ฅผ ํตํด ๋ฒ์ญ๋์์ต๋๋ค. ํฌ์ค ์ปค๋ฅํธ ์์ํ๊ธฐ ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ์ธ์. ์ด ๊ฐ์ด๋๋ Health Connect ๋ฒ์ 1.1
developer.android.com
https://developer.android.com/health-and-fitness/guides/health-connect?hl=ko
ํฌ์ค ์ปค๋ฅํธ | Android health & fitness | Android Developers
์ด ํ์ด์ง๋ Cloud Translation API๋ฅผ ํตํด ๋ฒ์ญ๋์์ต๋๋ค. ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ์ธ์. ์ฃผ์ ์ด์ ๊ณ ๊ฐ ํ๊ฐ ๋ด์ค ๋ฐ ๋์์ Google ํผํธ๋์ค ๊ฐ
developer.android.com
'๐ค ์๋๋ก์ด๋' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์๋๋ก์ด๋] ํ๋๊ทธ๋จผํธ ๊ฐ ๋ฐ์ดํฐ ๊ณต์ ํ๋ ๋ฐฉ๋ฒ (0) | 2025.03.20 |
---|---|
[์๋๋ก์ด๋] ๋ฆฌ์คํธ๋ทฐ (0) | 2024.07.18 |
[์๋๋ก์ด๋] ๋ค๋ก๊ฐ๊ธฐ ๋๋ฒ ํด๋ฆญ์ ์ข ๋ฃํ๋ ๋ฐฉ๋ฒ (0) | 2024.07.18 |
[์๋๋ก์ด๋] ๋ก๊ทธ (0) | 2024.07.18 |
[์๋๋ก์ด๋] ์ปค์คํ ํฐํธ ์ ์ฉ ๋ฐฉ๋ฒ (0) | 2024.07.18 |
Health Connect๋?
Google์ Health Connect๋ ๋ค์ํ ๊ฑด๊ฐ ๊ด๋ จ ๋ฐ์ดํฐ๋ฅผ ํตํฉ ๊ด๋ฆฌํ ์ ์๋๋ก ๋์์ฃผ๋ API์ด๋ค.
์ด๋ฅผ ํ์ฉํ๋ฉด ์ผ์ฑ ํฌ์ค์ผ์ด ๊ฐ์ ์ฑ์์ ๊ฑธ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์์ ํ์ฉํ ์ ์๋ค.
1. ํ๋ก์ ํธ ์ค์ (Gradle ์ค์ ํฌํจ)
๋จผ์ build.gradle.kts(Module:app) ํ์ผ์ Health Connect ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ๋ค.
dependencies {
implementation("androidx.health.connect:connect-client:1.1.0-alpha10")
}
2. Health Connect SDK ์ํ ํ์ธ ๋ฐ ์ค์น ์ ๋
Health Connect๊ฐ ๊ธฐ๊ธฐ์ ์ค์น๋์ง ์์๊ฑฐ๋ ์ต์ ๋ฒ์ ์ด ์๋๋ผ๋ฉด, Play Store์์ ์ค์นํ๋๋ก ์ ๋ํด์ผ ํ๋ค.
๋ค์ ์ฝ๋๋ ์ฑ์ด ์คํ๋ ๋ Health Connect๊ฐ ์ค์น๋์ง ์์๋ค๋ฉด Play Store๋ก ์ด๋ํ๋๋ก ์ฒ๋ฆฌํ๋ค.
private fun checkInstallHC() {
val providerPackageName = "com.google.android.apps.healthdata"
val availabilityStatus = HealthConnectClient.getSdkStatus(this, providerPackageName)
if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE ||
availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) {
Toast.makeText(this, "ํฌ์ค ์ปค๋ฅํธ ์ฑ์ ์ค์น ๋๋ ์
๋ฐ์ดํธ ํด์ฃผ์ธ์", Toast.LENGTH_SHORT).show()
openPlayStoreForHealthConnect()
}
}
private fun openPlayStoreForHealthConnect() {
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("https://play.google.com/store/apps/details?id=com.google.android.apps.healthdata")
setPackage("com.android.vending")
}
startActivity(intent)
}
3. ๊ถํ ์์ฒญ ๋ฐ ์ฒ๋ฆฌ ๋ฐฉ๋ฒ
Health Connect๋ฅผ ํตํด ๊ฑธ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ค๋ ค๋ฉด READ ๋ฐ WRITE ๊ถํ์ด ํ์ํ๋ค.
์๋ ์ฝ๋์์ ๊ถํ์ ์์ฒญํ๋ ๋ฐฉ๋ฒ์ ํ์ธํ ์ ์๋ค.
val PERMISSIONS = setOf(
HealthPermission.getReadPermission(StepsRecord::class),
HealthPermission.getWritePermission(StepsRecord::class)
)
private fun requestHealthPermissions() {
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()
val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
if (granted.containsAll(PERMISSIONS)) {
readStepsByTimeRange()
} else {
Toast.makeText(this, "์ฑ ๊ถํ โ '๊ฑธ์ ์'๋ฅผ ํ์ฑํ ํด์ฃผ์ธ์.", Toast.LENGTH_LONG).show()
}
}
requestPermissions.launch(PERMISSIONS)
}
4. ๊ฑธ์ ์ ๋ฐ์ดํฐ ์ฝ๊ธฐ
์ด์ readStepsByTimeRange ํจ์๋ฅผ ๊ตฌํํ์ฌ ์ฌ์ฉ์์ ๊ฑธ์ ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ฌ ์ ์๋ค.
private suspend fun readStepsByTimeRange() {
try {
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
StepsRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
if (response.records.isEmpty()) {
mViewModel.totalSteps.value = "0"
} else {
mViewModel.totalSteps.value = response.records[0].count.toString()
}
} catch (e: Exception) {
Log.e("HealthConnect", "๊ฑธ์ ์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ค๋ ์ค ์ค๋ฅ ๋ฐ์: $e")
}
}
5. ViewModel์ ์ด์ฉํ ๋ฐ์ดํฐ ๊ด๋ฆฌ
ViewModel์ ํ์ฉํ๋ฉด ๊ฑธ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ฑ์ UI์์ ์ฝ๊ฒ ๊ด๋ฆฌํ ์ ์๋ค.
class MainViewModel: ViewModel() {
val totalSteps = MutableLiveData<String>()
}
6. ๊ฒฐ๊ณผ ํ์ธ ๋ฐ ๋ก๊ทธ ์ถ๋ ฅ
์ฑ์ ์คํํ๋ฉด Health Connect์์ ์ผ์ฑ ํฌ์ค์ผ์ด์ ๊ฑธ์ ์ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ UI์ ๋ฐ์ํ ์ ์๋ค.
๋ก๊ทธ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ํ์ธํ ์ ์๋ค.
Log.v("Total Steps", "๊ฑธ์ ์: ${mViewModel.totalSteps.value}")
์ ์ฒด์ฝ๋
<MainActivity>
package com.lion.walk_hyein
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.health.connect.client.HealthConnectClient
import androidx.health.connect.client.PermissionController
import androidx.health.connect.client.permission.HealthPermission
import androidx.health.connect.client.records.StepsRecord
import androidx.health.connect.client.request.ReadRecordsRequest
import androidx.health.connect.client.time.TimeRangeFilter
import androidx.lifecycle.lifecycleScope
import com.lion.test3.MainViewModel
import kotlinx.coroutines.launch
import java.time.LocalDateTime
import java.time.LocalTime
import java.time.ZoneOffset
import kotlin.getValue
class MainActivity : AppCompatActivity() {
lateinit var requestPermissions : ActivityResultLauncher<Set<String>>
lateinit var healthConnectClient : HealthConnectClient
private val mViewModel: MainViewModel by viewModels()
val endTime = LocalDateTime.now()
val startTime = LocalDateTime.of(endTime.toLocalDate(), LocalTime.MIDNIGHT)
val startTimeInstant = startTime.atZone(ZoneOffset.UTC).toInstant()
val endTimeInstant = endTime.atZone(ZoneOffset.UTC).toInstant()
val PERMISSIONS = setOf(
HealthPermission.getReadPermission(StepsRecord::class),
HealthPermission.getWritePermission(StepsRecord::class))
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
lifecycleScope.launch {
checkInstallHC()
}
}
//ํฌ์ค์ปค๋ฅํธ ์ค์น, ๋ฒ์ , ๊ถํ ์ฌ๋ถ ํ์ธ
private fun checkInstallHC (){
val providerPackageName = "com.google.android.apps.healthdata"
val availabilityStatus = HealthConnectClient.getSdkStatus(this, providerPackageName)
//ํฌ์ค ์ปค๋ฅํธ ์ฑ์ด ์์ ๋
if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) {
Toast.makeText(this, "ํฌ์ค ์ปค๋ฅํธ ์ฑ์ ์ค์น ๋๋ ์
๋ฐ์ดํธ ํด์ฃผ์ธ์", Toast.LENGTH_SHORT).show()
finish()
//ํฌ์ค ์ปค๋ฅํธ ํ๋ ์ด์คํ ์ด ์ด๋
openPlayStoreForHealthConnect()
}
//ํฌ์ค ์ปค๋ฅํธ ์ฑ์ด ์ต์ ๋ฒ์ ์ด ์๋๋
if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) {
Toast.makeText(this, "ํฌ์ค ์ปค๋ฅํธ ์ฑ์ ์ค์น ๋๋ ์
๋ฐ์ดํธ ํด์ฃผ์ธ์", Toast.LENGTH_SHORT).show()
finish()
//ํฌ์ค ์ปค๋ฅํธ ํ๋ ์ด์คํ ์ด ์ด๋
openPlayStoreForHealthConnect()
}
healthConnectClient = HealthConnectClient.getOrCreate(this)
// ๊ถํ(permission)์ด ๋ถ์ฌ๋์ด ์๋์ง ํ์ธ
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()
requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
//๊ถํ์ด ๋ถ์ฌ๋ ์ํ
if (granted.containsAll(PERMISSIONS)) {
Log.d("Permission", "PermissionO : $healthConnectClient")
lifecycleScope.launch {
Log.d("TimeRange", "Start Time: $startTimeInstant, End Time: $endTimeInstant")
readStepsByTimeRange(healthConnectClient)
}
}
//๊ถํ์ด ๋ถ์ฌ๋์ง ์์ ์ํ๋ผ๋ฉด
else {
Log.d("Permission", "PermissionX : $healthConnectClient")
//๊ถํ ์ค์ ํ๋ฉด์ผ๋ก ์ด๋
movePermissionSetting(this)
}
}
requestPermissions.launch(PERMISSIONS)
}
//ํฌ์ค ์ปค๋ฅํธ ํ๋ ์ด์คํ ์ด ์ด๋
private fun openPlayStoreForHealthConnect(){
val intent = Intent(Intent.ACTION_VIEW).apply {
data = Uri.parse("https://play.google.com/store/apps/details?id=com.google.android.apps.healthdata")
setPackage("com.android.vending")
}
startActivity(intent)
}
//๊ถํ ์ค์ ํ๋ฉด์ผ๋ก ์ด๋
private fun movePermissionSetting(context: Context) {
val packageName = "com.google.android.apps.healthdata"
val intent = packageManager.getLaunchIntentForPackage(packageName)
context.startActivity(intent)
Toast.makeText(context, "์ฑ ๊ถํ โ '๊ฑธ์ ์'๋ฅผ ํ์ฑํ ํด์ฃผ์ธ์.", Toast.LENGTH_LONG).show()
}
private suspend fun readStepsByTimeRange(
healthConnectClient: HealthConnectClient,
) {
try {
val response = healthConnectClient.readRecords(
ReadRecordsRequest(
StepsRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
mViewModel.totalSteps.value = response.records[0].count.toString()
// records๊ฐ ๋น์ด์๋์ง ํ์ธํ๊ณ , ๋ก๊ทธ ์ถ๋ ฅ
if (response.records.isEmpty()) {
Log.v("Total Steps", "๋ฐ์ดํฐ ์์ - records ๋น์ด์์")
mViewModel.totalSteps.value = "0"
} else {
mViewModel.totalSteps.value = response.records[0].count.toString()
Log.v("Total Steps", "์คํ๋จ : ${mViewModel.totalSteps.value}")
}
} catch (e: Exception) {
Log.v("Total Steps", "์คํ ์๋จ : $e")
}
}
}
<MainViewModel>
package com.lion.walk_hyein
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
class MainViewModel: ViewModel() {
val totalSteps = MutableLiveData<String>()
}
<build.gradle.kts(Module:app)>
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android)
}
android {
namespace = "com.lion.walk_hyein"
compileSdk = 35
defaultConfig {
applicationId = "com.lion.walk_hyein"
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
}
dependencies {
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)
implementation(libs.androidx.activity)
implementation(libs.androidx.constraintlayout)
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
implementation("androidx.health.connect:connect-client:1.1.0-alpha10")
}
โ ๏ธ ํฌ์ค์ปค๋ฅํฐ์ ์ฐ๋์ ๊ฐ์ธ์ฐจ๊ฐ ํฌ๋ค. ๋๋ ๊ตฌํ์ด ๋๋์๋ง์ ๋ฐ๋ก ์ฐ๋๋์ด ์ ์์ ์ผ๋ก ์๋ํ์์ง๋ง, ๋ค๋ฅธ ํ์๋ถ๋ค์ ๋ช์๊ฐ ๋ค์ ์ ์ ์๋ ๋๊ธฐ๋ ํ๊ณ , ๋ฉฐ์น ๋ค์ ์ ์์๋ ๋๊ธฐ๋ ํ์๋ค.
๐ ์์ฉํ์ฌ ์๋ชจ ์นผ๋ก๋ฆฌ, ์ฌ๋ฐ์, ์๋ฉด ๋ฐ์ดํฐ ๋ฑ ๋ค์ํ ๊ฑด๊ฐ ๋ฐ์ดํฐ๋ฅผ ๋ถ๋ฌ์ฌ์๋ ์๋ค
์ฐธ๊ณ ๋ฌธ์
https://developer.android.com/health-and-fitness/guides/health-connect/develop/get-started?hl=ko
ํฌ์ค ์ปค๋ฅํธ ์์ํ๊ธฐ | Android health & fitness | Android Developers
์ด ํ์ด์ง๋ Cloud Translation API๋ฅผ ํตํด ๋ฒ์ญ๋์์ต๋๋ค. ํฌ์ค ์ปค๋ฅํธ ์์ํ๊ธฐ ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ์ธ์. ์ด ๊ฐ์ด๋๋ Health Connect ๋ฒ์ 1.1
developer.android.com
https://developer.android.com/health-and-fitness/guides/health-connect?hl=ko
ํฌ์ค ์ปค๋ฅํธ | Android health & fitness | Android Developers
์ด ํ์ด์ง๋ Cloud Translation API๋ฅผ ํตํด ๋ฒ์ญ๋์์ต๋๋ค. ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ์ธ์. ์ฃผ์ ์ด์ ๊ณ ๊ฐ ํ๊ฐ ๋ด์ค ๋ฐ ๋์์ Google ํผํธ๋์ค ๊ฐ
developer.android.com
'๐ค ์๋๋ก์ด๋' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์๋๋ก์ด๋] ํ๋๊ทธ๋จผํธ ๊ฐ ๋ฐ์ดํฐ ๊ณต์ ํ๋ ๋ฐฉ๋ฒ (0) | 2025.03.20 |
---|---|
[์๋๋ก์ด๋] ๋ฆฌ์คํธ๋ทฐ (0) | 2024.07.18 |
[์๋๋ก์ด๋] ๋ค๋ก๊ฐ๊ธฐ ๋๋ฒ ํด๋ฆญ์ ์ข ๋ฃํ๋ ๋ฐฉ๋ฒ (0) | 2024.07.18 |
[์๋๋ก์ด๋] ๋ก๊ทธ (0) | 2024.07.18 |
[์๋๋ก์ด๋] ์ปค์คํ ํฐํธ ์ ์ฉ ๋ฐฉ๋ฒ (0) | 2024.07.18 |