Panduan ini kompatibel dengan Health Connect versi 1.1.0-alpha12.
Rute olahraga memungkinkan pengguna melacak rute GPS untuk aktivitas olahraga terkait dan membagikan peta olahraga mereka ke aplikasi lain.
Panduan ini memberikan informasi tentang cara meminta izin dari pengguna dan juga menguraikan cara aplikasi menerima izin untuk menulis data rute sebagai bagian dari sesi latihan.
Fungsi baca dan tulis untuk rute latihan mencakup:
- Aplikasi membuat izin tulis baru untuk rute olahraga.
- Penyisipan dilakukan dengan menulis sesi olahraga beserta rute sebagai kolomnya.
- Membaca:
- Untuk pemilik sesi, data diakses menggunakan pembacaan sesi.
- Dari aplikasi pihak ketiga, melalui dialog yang memungkinkan pengguna memberikan pembacaan rute satu kali.
Jika pengguna tidak memiliki izin tulis dan rute tidak ditetapkan, rute tidak akan diperbarui.
Jika aplikasi Anda memiliki izin tulis rute dan mencoba memperbarui sesi dengan meneruskan objek sesi tanpa rute, rute yang sudah ada akan dihapus.
Memeriksa ketersediaan Health Connect
Sebelum mencoba menggunakan Health Connect, aplikasi Anda harus memverifikasi bahwa Health Connect tersedia di perangkat pengguna. Health Connect mungkin tidak diinstal sebelumnya di semua perangkat atau dapat dinonaktifkan.
Anda dapat memeriksa ketersediaan menggunakan metode HealthConnectClient.getSdkStatus()
.
Cara memeriksa ketersediaan Health Connect
fun checkHealthConnectAvailability(context: Context) { val providerPackageName = "com.google.android.apps.healthdata" // Or get from HealthConnectClient.DEFAULT_PROVIDER_PACKAGE_NAME val availabilityStatus = HealthConnectClient.getSdkStatus(context, providerPackageName) if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE) { // Health Connect is not available. Guide the user to install/enable it. // For example, show a dialog. return // early return as there is no viable integration } if (availabilityStatus == HealthConnectClient.SDK_UNAVAILABLE_PROVIDER_UPDATE_REQUIRED) { // Health Connect is available but requires an update. // Optionally redirect to package installer to find a provider, for example: val uriString = "market://details?id=$providerPackageName&url=healthconnect%3A%2F%2Fonboarding" context.startActivity( Intent(Intent.ACTION_VIEW).apply { setPackage("com.android.vending") data = Uri.parse(uriString) putExtra("overlay", true) putExtra("callerId", context.packageName) } ) return } // Health Connect is available, obtain a HealthConnectClient instance val healthConnectClient = HealthConnectClient.getOrCreate(context) // Issue operations with healthConnectClient }
Bergantung pada status yang ditampilkan oleh getSdkStatus()
, Anda dapat memandu pengguna
untuk menginstal atau mengupdate Health Connect dari Google Play Store jika perlu.
Ketersediaan fitur
Untuk menentukan apakah perangkat pengguna mendukung latihan fisik terencana di Health Connect, periksa ketersediaanFEATURE_PLANNED_EXERCISE
di klien:
if (healthConnectClient
.features
.getFeatureStatus(
HealthConnectFeatures.FEATURE_PLANNED_EXERCISE
) == HealthConnectFeatures.FEATURE_STATUS_AVAILABLE) {
// Feature is available
} else {
// Feature isn't available
}
Izin yang diperlukan
Akses ke rute latihan dilindungi oleh izin berikut:
android.permission.health.READ_EXERCISE_ROUTES
android.permission.health.WRITE_EXERCISE_ROUTE
READ_EXERCISE_ROUTES
berbentuk jamak, sedangkan
WRITE_EXERCISE_ROUTE
berbentuk tunggal.
Untuk menambahkan kemampuan rute latihan ke aplikasi Anda, mulailah dengan meminta
izin tulis untuk jenis data ExerciseSession
.
Berikut adalah izin yang harus Anda deklarasikan agar dapat menulis rute olahraga:
<application>
<uses-permission
android:name="android.permission.health.WRITE_EXERCISE_ROUTE" />
...
</application>
Untuk membaca rute latihan, Anda perlu meminta izin berikut:
<application>
<uses-permission
android:name="android.permission.health.READ_EXERCISE_ROUTES" />
...
</application>
Anda juga harus mendeklarasikan izin olahraga, karena setiap rute dikaitkan dengan sesi olahraga (satu sesi = satu olahraga).
Untuk meminta izin, gunakan
metode PermissionController.createRequestPermissionResultContract()
saat
Anda pertama kali menghubungkan aplikasi ke Health Connect. Beberapa izin yang mungkin
ingin Anda minta adalah:
- Membaca data kesehatan dan kebugaran, termasuk data rute:
HealthPermission.getReadPermission(ExerciseSessionRecord::class)
- Menulis data kesehatan dan kebugaran, termasuk data rute:
HealthPermission.getWritePermission(ExerciseSessionRecord::class)
- Menulis data rute olahraga:
HealthPermission.PERMISSION_WRITE_EXERCISE_ROUTE
Meminta izin dari pengguna
Setelah membuat instance klien, aplikasi Anda perlu meminta izin dari pengguna. Pengguna harus diizinkan untuk memberikan atau menolak izin kapan saja.
Untuk melakukannya, buat kumpulan izin untuk jenis data yang diperlukan. Pastikan izin dalam kumpulan dideklarasikan dalam manifes Android Anda terlebih dahulu.
// Create a set of permissions for required data types
val PERMISSIONS =
setOf(
HealthPermission.getReadPermission(ExerciseSessionRecord::class),
HealthPermission.getWritePermission(ExerciseSessionRecord::class)
)
Gunakan getGrantedPermissions
untuk mengetahui apakah aplikasi Anda sudah
mendapatkan izin yang diperlukan. Jika belum, gunakan
createRequestPermissionResultContract
untuk meminta
izin tersebut. Tindakan ini akan menampilkan layar izin Health Connect.
// Create the permissions launcher
val requestPermissionActivityContract = PermissionController.createRequestPermissionResultContract()
val requestPermissions = registerForActivityResult(requestPermissionActivityContract) { granted ->
if (granted.containsAll(PERMISSIONS)) {
// Permissions successfully granted
} else {
// Lack of required permissions
}
}
suspend fun checkPermissionsAndRun(healthConnectClient: HealthConnectClient) {
val granted = healthConnectClient.permissionController.getGrantedPermissions()
if (granted.containsAll(PERMISSIONS)) {
// Permissions already granted; proceed with inserting or reading data
} else {
requestPermissions.launch(PERMISSIONS)
}
}
Karena pengguna dapat memberikan atau mencabut izin kapan saja, aplikasi Anda harus memeriksa izin yang diberikan secara berkala dan menangani skenario saat izin tersebut hilang.
Informasi yang disertakan dalam catatan sesi latihan
Setiap catatan sesi latihan berisi informasi berikut:
- Jenis latihan, misalnya, bersepeda.
- Rute latihan, yang berisi informasi seperti lintang, bujur, dan ketinggian.
Agregasi yang didukung
Nilai gabungan berikut tersedia untuk
ExerciseSessionRecord
:
Contoh penggunaan
Cuplikan kode berikut menunjukkan cara membaca dan menulis rute latihan.
Baca rute olahraga
Aplikasi Anda tidak dapat membaca data rute latihan yang dibuat oleh aplikasi lain saat berjalan di latar belakang.
Saat aplikasi Anda berjalan di latar belakang dan mencoba membaca rute latihan yang dibuat
oleh aplikasi lain, Health Connect akan menampilkan respons ExerciseRouteResult.ConsentRequired
meskipun aplikasi Anda memiliki akses Selalu izinkan ke data rute
latihan.
Oleh karena itu, sebaiknya Anda meminta rute saat pengguna berinteraksi dengan aplikasi Anda secara sengaja, saat pengguna berinteraksi aktif dengan UI aplikasi Anda.
Untuk mempelajari lebih lanjut pembacaan latar belakang, lihat Contoh pembacaan latar belakang.
Cuplikan kode berikut menunjukkan cara membaca sesi di Health Connect dan meminta rute dari sesi tersebut:
suspend fun readExerciseSessionAndRoute() {
val endTime = Instant.now()
val startTime = endTime.minus(Duration.ofHours(1))
val grantedPermissions =
healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
HealthPermission.getReadPermission(ExerciseSessionRecord::class))) {
// The user doesn't allow the app to read exercise session data.
return
}
val readResponse =
healthConnectClient.readRecords(
ReadRecordsRequest(
ExerciseSessionRecord::class,
TimeRangeFilter.between(startTime, endTime)
)
)
val exerciseRecord = readResponse.records.first()
val recordId = exerciseRecord.metadata.id
// See https://developer.android.com/training/basics/intents/result#launch
// for appropriately handling ActivityResultContract.
val requestExerciseRouteLauncher = fragment.registerForActivityResul
(ExerciseRouteRequestContract()) { exerciseRoute: ExerciseRoute? ->
if (exerciseRoute != null) {
displayExerciseRoute(exerciseRoute)
} else {
// Consent was denied
}
}
val exerciseSessionRecord =
healthConnectClient.readRecord(ExerciseSessionRecord::class, recordId).record
when (val exerciseRouteResult = exerciseSessionRecord.exerciseRouteResult) {
is ExerciseRouteResult.Data ->
displayExerciseRoute(exerciseRouteResult.exerciseRoute)
is ExerciseRouteResult.ConsentRequired ->
requestExerciseRouteLauncher.launch(recordId)
is ExerciseRouteResult.NoData -> Unit // No exercise route to show
else -> Unit
}
}
fun displayExerciseRoute(route: ExerciseRoute?) {
val locations = route.route.orEmpty()
for (location in locations) {
// Handle location.
}
}
Menulis rute latihan
Kode berikut menunjukkan cara merekam sesi yang menyertakan rute olahraga:
suspend fun InsertExerciseRoute(healthConnectClient: HealthConnectClient) {
val grantedPermissions =
healthConnectClient.permissionController.getGrantedPermissions()
if (!grantedPermissions.contains(
getWritePermission(ExerciseSessionRecord::class))) {
// The user doesn't allow the app to write exercise session data.
return
}
val sessionStartTime = Instant.now()
val sessionDuration = Duration.ofMinutes(20)
val sessionEndTime = sessionStartTime.plus(sessionDuration)
val exerciseRoute =
if (grantedPermissions.contains(PERMISSION_WRITE_EXERCISE_ROUTE)) ExerciseRoute(
listOf(
ExerciseRoute.Location(
// Location times must be on or after the session start time
time = sessionStartTime,
latitude = 6.5483,
longitude = 0.5488,
horizontalAccuracy = Length.meters(2.0),
verticalAccuracy = Length.meters(2.0),
altitude = Length.meters(9.0),
), ExerciseRoute.Location(
// Location times must be before the session end time
time = sessionEndTime.minusSeconds(1),
latitude = 6.4578,
longitude = 0.6577,
horizontalAccuracy = Length.meters(2.0),
verticalAccuracy = Length.meters(2.0),
altitude = Length.meters(9.2),
)
)
)
else
// The user doesn't allow the app to write exercise route data.
null
val exerciseSessionRecord = ExerciseSessionRecord(
startTime = sessionStartTime,
startZoneOffset = ZoneOffset.UTC,
endTime = sessionEndTime,
endZoneOffset = ZoneOffset.UTC,
exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_BIKING,
title = "Morning Bike Ride",
exerciseRoute = exerciseRoute,
metadata = Metadata.manualEntry(
device = Device(type = Device.TYPE_PHONE)
),
)
val response = healthConnectClient.insertRecords(listOf(exerciseSessionRecord))
}
Sesi olahraga
Sesi olahraga dapat mencakup apa saja, dari berlari hingga bulu tangkis.
Menulis sesi olahraga
Berikut ini cara mem-build permintaan penyisipan yang menyertakan sesi:
suspend fun writeExerciseSession(healthConnectClient: HealthConnectClient) {
healthConnectClient.insertRecords(
listOf(
ExerciseSessionRecord(
startTime = START_TIME,
startZoneOffset = START_ZONE_OFFSET,
endTime = END_TIME,
endZoneOffset = END_ZONE_OFFSET,
exerciseType = ExerciseSessionRecord.ExerciseType.RUNNING,
title = "My Run"
),
// ... other records
)
)
}
Membaca sesi olahraga
Berikut ini contoh cara membaca sesi olahraga:
suspend fun readExerciseSessions(
healthConnectClient: HealthConnectClient,
startTime: Instant,
endTime: Instant
) {
val response =
healthConnectClient.readRecords(
ReadRecordsRequest(
ExerciseSessionRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
for (exerciseRecord in response.records) {
// Process each exercise record
// Optionally pull in with other data sources of the same time range.
val distanceRecord =
healthConnectClient
.readRecords(
ReadRecordsRequest(
DistanceRecord::class,
timeRangeFilter =
TimeRangeFilter.between(
exerciseRecord.startTime,
exerciseRecord.endTime
)
)
)
.records
}
}
Menulis data subjenis
Sesi juga dapat terdiri dari data subjenis opsional yang memperkaya sesi dengan informasi tambahan.
Misalnya, sesi olahraga dapat menyertakan class ExerciseSegment
, ExerciseLap
,
dan ExerciseRoute
:
val segments = listOf(
ExerciseSegment(
startTime = Instant.parse("2022-01-02T10:10:10Z"),
endTime = Instant.parse("2022-01-02T10:10:13Z"),
segmentType = ActivitySegmentType.BENCH_PRESS,
repetitions = 373
)
)
val laps = listOf(
ExerciseLap(
startTime = Instant.parse("2022-01-02T10:10:10Z"),
endTime = Instant.parse("2022-01-02T10:10:13Z"),
length = 0.meters
)
)
ExerciseSessionRecord(
exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_CALISTHENICS,
startTime = Instant.parse("2022-01-02T10:10:10Z"),
endTime = Instant.parse("2022-01-02T10:10:13Z"),
startZoneOffset = ZoneOffset.UTC,
endZoneOffset = ZoneOffset.UTC,
segments = segments,
laps = laps,
route = route
)
Menghapus sesi olahraga
Ada dua cara untuk menghapus sesi olahraga:
- Menurut rentang waktu.
- Menurut UID.
Berikut ini cara menghapus data subjenis berdasarkan rentang waktu:
suspend fun deleteExerciseSessionByTimeRange(
healthConnectClient: HealthConnectClient,
exerciseRecord: ExerciseSessionRecord,
) {
val timeRangeFilter = TimeRangeFilter.between(exerciseRecord.startTime, exerciseRecord.endTime)
healthConnectClient.deleteRecords(ExerciseSessionRecord::class, timeRangeFilter)
// delete the associated distance record
healthConnectClient.deleteRecords(DistanceRecord::class, timeRangeFilter)
}
Anda juga dapat menghapus data subjenis menurut UID. Tindakan ini hanya akan menghapus sesi latihan, bukan data terkait:
suspend fun deleteExerciseSessionByUid(
healthConnectClient: HealthConnectClient,
exerciseRecord: ExerciseSessionRecord,
) {
healthConnectClient.deleteRecords(
ExerciseSessionRecord::class,
recordIdsList = listOf(exerciseRecord.metadata.id),
clientRecordIdsList = emptyList()
)
}