הוספת מסלולי אימון

מסלולי אימון מאפשרים למשתמשים לעקוב אחר מסלול GPS אחר פעילות גופנית מאורגנת פעילויות ולשתף מפות של אימוני הכושר שלהם עם אפליקציות אחרות.

במדריך הזה מוסבר איך אפליקציות מקבלות הרשאה לכתוב נתוני מסלולים שיעור פעילות.

לפניכם סיכום קצר של פונקציונליות הקריאה והכתיבה במסלולי אימון:

  1. אפליקציות יוצרות הרשאת כתיבה חדשה למסלולי אימון.
  2. ההכנסה מתבצעת על ידי כתיבת תרגול שכולל מסלול כשדה.
  3. קריאה:
    1. עבור בעלי הסשן, מתבצעת גישה לנתונים באמצעות קריאת סשן.
    2. באפליקציית צד שלישי, דרך תיבת דו-שיח שמאפשרת למשתמש להעניק קריאה חד-פעמית של מסלול.

הרשאות

למסלולי אימון יש הרשאת כתיבה משלהם בזמן ריצה (android.permission.health.WRITE_EXERCISE_ROUTE).

כדי להוסיף לאפליקציה יכולת של מסלול אימון כושר, צריך קודם לבקש כתיבה לפי סוג נתונים מסוים.

בקשת הרשאה ל-Android 14

בקשת הרשאה ל-Android 14

בקשת הרשאה ל-Android 13

בקשת הרשאה ל-Android 13

צריך גם להצהיר על אישור מימוש, כי כל מסלול משויך עם אימון כושר (סשן אחד = אימון אחד).

זו ההרשאה שצריך להצהיר עליה כדי לכתוב מסלולי אימון:

<application>
  <uses-permission
android:name="android.permission.health.WRITE_EXERCISE_ROUTE" />
  <uses-permission
android:name="android.permission.health.WRITE_EXERCISE" />
...
</application>

כדי לקרוא מסלולי אימון, צריך לבקש את ההרשאות הבאות:

<application>
  <uses-permission
android:name="android.permission.health.READ_EXERCISE_ROUTES" />
  <uses-permission
android:name="android.permission.health.READ_EXERCISE" />
...
</application>

כדי לבקש הרשאות, משתמשים שיטה PermissionController.createRequestPermissionResultContract() כאשר קודם צריך לקשר את האפליקציה ל-Health Connect. מספר הרשאות שאפשר להפעיל רוצים לבקש הם:

  • קריאה של נתוני הבריאות, כולל נתוני המסלול: HealthPermission.getReadPermission(ExerciseSessionRecord::class)
  • כתיבת נתוני בריאות, כולל נתוני מסלולים: HealthPermission.getWritePermission(ExerciseSessionRecord::class)
  • כתיבת נתונים של מסלולי אימון: HealthPermission.PERMISSION_WRITE_EXERCISE_ROUTE

קריאה וכתיבה של נתוני המסלול

אפליקציות מוסיפות מסלול על ידי כתיבת סשן עם מסלול כשדה.

אם למשתמש אין הרשאות כתיבה והמסלול לא מוגדר, לא מתעדכן.

אם לאפליקציה יש הרשאת כתיבה של מסלול והיא מנסה לעדכן סשן על ידי כשמעבירים באובייקט סשן ללא מסלול, המסלול הקיים נמחק.

בכל פעם שהאפליקציה שלך צריכה לקרוא נתוני מסלולים שסופקו על ידי אפליקציית צד שלישי, מופיעה תיבת דו-שיח שמבקשת מהמשתמש לאפשר את פעולת הקריאה.

איך מבקשים מסלול מסשן

כך קוראים סשן ב-Health Connect ומבקשים ממנו מסלול סשן:

suspend fun readExerciseSessionAndRoute() {
    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()

    // 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.
    }
  }

כתיבת מסלול מסשן

הקוד הבא מדגים איך להקליט סשן שכולל מסלול האימון:

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.parse("2023-01-01T10:00:00.00Z")
    val sessionDuration = Duration.ofMinutes(20)

    val exerciseRoute =
      if (getPermissions.contains(PERMISSION_EXERCISE_ROUTE_WRITE) {
        ExerciseRoute(
          listOf(
            ExerciseRoute.Location(
              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(
              time = sessionStartTime.plus(sessionDuration)
              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 = /* starting time in milliseconds */,
            startZoneOffset = ZoneOffset.UTC,
            endTime = sessionStartTime.plus(sessionDuration),
            endZoneOffset = ZoneOffset.UTC,
            exerciseType = ExerciseSessionRecord.EXERCISE_TYPE_BIKING,
            title = "Morning Bike Ride",
            exerciseRoute = exerciseRoute
        )

    healthConnectClient.insertRecords(listOf(exerciseSessionRecord))
}