We use essential cookies for the website to function, as well as analytics cookies for analyzing and creating statistics of the website performance. To agree to the use of analytics cookies, click "Accept All". You can manage your preferences at any time by clicking "Cookie Settings" on the footer. More Information.

Only Essential Cookies
Accept All

Managing Exercise Records

You can manage users' exercise records by calling APIs in HMSHealthKit after integrating Health Service Kit. First, check whether your app has been granted the following scopes to operate on the exercise record data:

  • Read: HMSHealthKitScope.HEALTHKIT_ACTIVITY_RECORD_READ
  • Write: HMSHealthKitScope.HEALTHKIT_ACTIVITY_RECORD_WRITE

APIs you can call are as follows:

Writing Exercise Records to Health Service Kit

NOTE

The start time and end time passed for writing exercise records must be later than the UNIX timestamp corresponding to January 1, 2014.

  1. Create an ActivityRecord object with the specified workout type, start time, end time, workout statistics, time zone, and other necessary information.
  2. Create an ActivityRecordInsertOptions object using ActivityRecord and available sampling datasets or polymerized sampling points.
  3. Insert ActivityRecordInsertOptions to Health Service Kit using addActivityRecord.

    Sample code for writing exercise records to Health Service Kit:
    Collapse
    Word wrap
    Dark theme
    Copy code
    1. import {HMSHealthKit, HMSHealthKitDataType, HMSHealthKitDeviceType, HMSHealthKitActivityType, DeviceInfo, DataCollector, Value, SamplePoint, SampleSet, PaceSummary, ActivityFeature, ActivitySummary, ActivityRecord, ActivityRecordInsertOptions} from '@hw-hmscore/hms-js-health'
    2. // Step 1: Create an ActivityRecord object with the specified workout type, start time, end time, workout statistics, time zone, and other necessary information.
    3. // Build device information based on the device manufacturer, device model, device UUID, and device type.
    4. let deviceInfo = new DeviceInfo("manufacturer", "modelName", "uuid", HMSHealthKitDeviceType.TYPE_PHONE);
    5. // Build a data collector based on the device information, app package name, and data type.
    6. let dataCollector = new DataCollector(deviceInfo, "com.health.demo", HMSHealthKitDataType.DT_ACTIVITY_FEATURE_JUMPING_ROPE);
    7. // Build the field value of the workout feature statistical data type based on the mappings between data types and data fields.
    8. const valuesActivityFeature = []
    9. let valueSkipNum = new Value("skip_num", "150");
    10. let valueStumbingNum = new Value("stumbling_rope", "0");
    11. let valueMaxSkipping = new Value("max_skipping_times", "1");
    12. let valueDoubleShake = new Value("double_shake", "0");
    13. let valueTripleShake = new Value("triple_shake", "0");
    14. valuesActivityFeature.push(valueSkipNum);
    15. valuesActivityFeature.push(valueStumbingNum);
    16. valuesActivityFeature.push(valueMaxSkipping);
    17. valuesActivityFeature.push(valueDoubleShake);
    18. valuesActivityFeature.push(valueTripleShake);
    19. // Create a samplePoint object based on the field value array, start time, end time, and metadata.
    20. let samplePoint = new SamplePoint(valuesActivityFeature, "1624774020000", "1624774320000", "here is customized text");
    21. // Create an ActivityFeature object based on the data source and samplePoint.
    22. let activityFeature = new ActivityFeature(dataCollector, samplePoint);
    23. // Create a piece of rope jumping speed statistics data.
    24. let dataCollectorJumpRope = new DataCollector(deviceInfo, "com.health.demo", HMSHealthKitDataType.DT_CONTINUOUS_SKIP_SPEED_STATISTICS);
    25. let valueAvg = new Value("avg", "40");
    26. let valueMax = new Value("max", "60");
    27. let valueMin = new Value("min", "20");
    28. const valueJumpRopeSummary = [];
    29. valueJumpRopeSummary.push(valueAvg);
    30. valueJumpRopeSummary.push(valueMax);
    31. valueJumpRopeSummary.push(valueMin);
    32. let samplePointSkipSummary = new SamplePoint(valueJumpRopeSummary, "1624774020000", "1624774320000", "here is customized text");
    33. const samplePoints = [];
    34. samplePoints.push(samplePointSkipSummary);
    35. let sampleSetJumpRope = new SampleSet(dataCollectorJumpRope, samplePoints);
    36. // Create a piece of calorie statistics data.
    37. let dataCollectorCaloresTotal = new DataCollector(deviceInfo, "com.health.demo", HMSHealthKitDataType.DT_CONTINUOUS_CALORIES_BURNT_TOTAL);
    38. let valueCaloresTotal = new Value("calories_total", "180");
    39. const valueCalories = [];
    40. valueCalories.push(valueCaloresTotal);
    41. let samplePointCaloresTotal = new SamplePoint(valueCalories, "1624774020000", "1624774320000", "here is customized text");
    42. const samplePointsCaloresTotal = [];
    43. samplePointsCaloresTotal.push(samplePointCaloresTotal);
    44. let sampleSetCalories = new SampleSet(dataCollectorCaloresTotal, samplePointsCaloresTotal);
    45. let sampleSets = [];
    46. sampleSets.push(sampleSetJumpRope);
    47. sampleSets.push(sampleSetCalories);
    48. // Build an activitySummary object based on the workout characteristics, sampling dataset, and paceSummary.
    49. let activitySummary = new ActivitySummary(activityFeature, sampleSets, null);
    50. // Create a data source for workout heart rate details.
    51. let dataCollectorHeartRate = new DataCollector(deviceInfo, "com.health.demo", HMSHealthKitDataType.DT_INSTANTANEOUS_EXERCISE_HEART_RATE);
    52. const valuesHeartRates = []
    53. let valueHeartRate = new Value("bpm", "120");
    54. valuesHeartRates.push(valueHeartRate)
    55. let samplePointHeartRate = new SamplePoint(valuesHeartRates, "1624774020000", "1624774320000", "here is customized text");
    56. const samplePointsHeartRate = []
    57. samplePointsHeartRate.push(samplePointHeartRate);
    58. // Sampling dataset of the details associated with the exercise record.
    59. let sampleSet = new SampleSet(dataCollectorHeartRate, samplePointsHeartRate);
    60. const sampleSetLists = []
    61. sampleSetLists.push(sampleSet);
    62. let activityRecord = new ActivityRecord("mysession1", "1624774020000", "1624774320000", HMSHealthKitActivityType.JUMPING_ROPE, "here", activitySummary, "+0800", "here is customized text", deviceInfo);
    63. // Step 2: Create an ActivityRecordInsertOptions object based on ActivityRecord and available sampling datasets or polymerized sampling point data.
    64. let activityRecordInsertOptions = new ActivityRecordInsertOptions(activityRecord, sampleSetLists);
    65. // Step 3: Insert ActivityRecordInsertOptions to Health Service Kit using addActivityRecord.
    66. HMSHealthKit.addActivityRecord(activityRecordInsertOptions).then((result) => {
    67. // Calling succeeded.
    68. console.info("addActivityRecord success: " + JSON.stringify(result))
    69. }).catch((error) => {
    70. // Calling failed.
    71. console.error("addActivityRecord error: " + JSON.stringify(error));
    72. })

Deleting Exercise Records from Health Service Kit

NOTE
  1. The start time and end time passed for deleting exercise records must be later than the UNIX timestamp corresponding to January 1, 2014.
  2. If activityRecordIds is not empty, it will be used to delete exercise record data. Otherwise, exercise record data will be deleted based on the start time and end time.
  1. Create an ActivityRecordDeleteOptions object based on activityRecordIds or the workout start and end times.
  2. Delete exercise records that match ActivityRecordDeleteOptions from Health Service Kit using deleteActivityRecord.

    Sample code for deleting exercise records from Health Service Kit:

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. import {HMSHealthKit, HMSHealthKitDataType, ActivityRecordDeleteOptions} from '@hw-hmscore/hms-js-health'
    2. // Step 1: Create an ActivityRecordDeleteOptions object based on activityRecordIds or the start and end times.
    3. const subDataTypes = []
    4. // Build an array of the sub-data type to be deleted.
    5. subDataTypes.push(HMSHealthKitDataType.DT_INSTANTANEOUS_HEART_RATE)
    6. const activityRecordIds = []
    7. // If you do not set acitivityRecordId, comment out the next line.
    8. activityRecordIds.push("mysession1")
    9. // Build deleteOptions based on conditions like the time.
    10. let deleteOption = new ActivityRecordDeleteOptions("1624774020000", "1624774320000", subDataTypes, activityRecordIds, "true")
    11. // Step 2: Delete exercise records that match ActivityRecordDeleteOptions from Health Service Kit using deleteActivityRecord.
    12. HMSHealthKit.deleteActivityRecord(deleteOption).then((result) => {
    13. // Calling succeeded.
    14. console.info("deleteActivityRecord success: " + JSON.stringify(result))
    15. }).catch((error) => {
    16. // Calling failed.
    17. console.error("addActivityRecord error: " + JSON.stringify(error))
    18. })

Reading Exercise Records from Health Service Kit

NOTE
  1. The start time and end time passed for querying exercise records must be later than the UNIX timestamp corresponding to January 1, 2014.
  2. The start time and end time for querying cannot span over 10 days.
  3. When building ActivityRecordReadOptions, you can set data types through setDataTypeNameList by referring to Open Exercise Record Data Types. If you do not set data types, your app may not be able to read detailed data of exercise records from Huawei Health.
  1. To obtain a list of exercise records that meet specific conditions, create an ActivityRecordReadOptions instance first.
  2. Call getActivityRecord to obtain exercise record data.

    Sample code for querying exercise records from Health Service Kit:

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. import {HMSHealthKit, HMSHealthKitDataType, ActivityRecordReadOptions} from '@hw-hmscore/hms-js-health'
    2. // Step 1: Create an ActivityRecordReadOptions instance.
    3. const dataTypeNameList = []
    4. // Create the detailed data associated with the target exercise record.
    5. dataTypeNameList.push(HMSHealthKitDataType.DT_INSTANTANEOUS_EXERCISE_HEART_RATE)
    6. // Create parameters for reading exercise records based on the start time, end time, and detailed dataset.
    7. let readOption = new ActivityRecordReadOptions("1624774020000", "1624774320000", dataTypeNameList)
    8. // Step 2: Call getActivityRecord to obtain exercise record data.
    9. HMSHealthKit.getActivityRecord(readOption).then((result) => {
    10. // Calling succeeded.
    11. console.info("getActivityRecord success: " + JSON.stringify(result))
    12. }).catch((error) => {
    13. // Calling failed.
    14. console.error("getActivityRecord error: " + JSON.stringify(error));
    15. })

Creating Exercise Records That Stay Alive in the Background

Create exercise records that stay alive in the background, so that your app can keep track of users' workout data in the background.

NOTE
  • To prevent your app from being frozen by the system, start a foreground service after calling beginActivityRecord to create an exercise record that stays alive in the background.
  • Currently, this is supported on WATCH 3/4 series smart watches running HarmonyOS 3.0.0 or later.
  • When the user starts a workout, call beginActivityRecord to start the exercise record, and apply for it to stay alive in the background for 10 minutes. Then, start the foreground service.
  • Each time the 10-minute period is about to end but the workout continues, call continueActivityRecord for the exercise record to stay alive in the background.
  • When the workout ends, call endActivityRecord to stop the exercise record and the foreground service.

FA JavaScript Side

  1. Start an exercise record that stays alive in the background.

    Call beginActivityRecord to start an exercise record and apply for it to run in the background for 10 minutes. Then call PA to start the foreground service.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. import {HMSHealthKit, DeviceInfo, ActivityRecord, ComponentInfo, HMSHealthKitActivityType, HMSHealthKitDeviceType} from '@hw-hmscore/hms-js-health'
    2. // Set the type of the PA to be called to 0 (Ability) or 1 (Internal Ability).
    3. const ABILITY_TYPE_EXTERNAL = 0;
    4. // Message code for starting the foreground service
    5. const MESSAGE_CODE_START = 1001;
    6. // Message code for stopping the foreground service
    7. const MESSAGE_CODE_STOP = 1002;
    8. export default {
    9. async beginActivityRecord() {
    10. // Device information
    11. let deviceInfo = new DeviceInfo("manufacturer", "modelName", "uuid", HMSHealthKitDeviceType.TYPE_SMART_WATCH);
    12. // Create an ActivityRecord object with the specified activity ID, start time, time zone, and other necessary information.
    13. let activityRecord = new ActivityRecord("mysession1", "1624774020000", "0", HMSHealthKitActivityType.YOGA, "desc", null, "+0800", "here is customized text", deviceInfo);
    14. // Build the screen to be displayed when the exercise record is running in the background. Note that you need to replace the app package name and screen in the sample code.
    15. var componentInfo = new ComponentInfo("com.huawei.ohos.healthkit.demo", "pages", "Harmony")
    16. // Call HMSHealthKit.beginActivityRecord to start the exercise record that stays alive in the background.
    17. HMSHealthKit.beginActivityRecord(activityRecord, componentInfo, (result) => {
    18. console.info("beginActivityRecord callback:" + new Date() + " " + JSON.stringify(result))
    19. // If the operation to keep the exercise record alive is canceled due to timeout or is preempted by another app, the callback needs to stop the foreground service.
    20. if (result.data != "0") {
    21. this.stopKeepBackground();
    22. }
    23. }, this.$app.$def.hmsData.eventCallbackMap).then((result) => {
    24. console.info("beginActivityRecord -> success :" + JSON.stringify(result))
    25. // If the calling is successful, call the foreground service of the Java PA.
    26. this.startKeepBackground();
    27. }).catch((error) => {
    28. // If the calling fails, process the failure in the callback.
    29. console.error("beginActivityRecord -> Error : " + JSON.stringify(error));
    30. });
    31. },
    32. // Call the PA to start the foreground service.
    33. startKeepBackground() {
    34. console.info("workout startKeepBackground begin")
    35. // Set the Java PA action information. Note that you need to replace your app information in the sample code.
    36. var action = {};
    37. action.bundleName = 'com.huawei.ohos.healthkit.demo';
    38. action.abilityName = 'com.huawei.ohos.healthkit.demo.KeepBackgroundAbility';
    39. action.messageCode = MESSAGE_CODE_START;
    40. action.abilityType = ABILITY_TYPE_EXTERNAL;
    41. action.syncOption = 0;
    42. FeatureAbility.callAbility(action);
    43. console.info("workout startOngoing done")
    44. },
    45. // Call the Java PA to stop the foreground service.
    46. stopKeepBackground() {
    47. console.info("workout stopKeepBackground begin")
    48. // Set the Java PA action information. Note that you need to replace your app information in the sample code.
    49. var action = {};
    50. action.bundleName = 'com.huawei.ohos.healthkit.demo';
    51. action.abilityName = 'com.huawei.ohos.healthkit.demo.KeepBackgroundAbility';
    52. action.messageCode = MESSAGE_CODE_STOP;
    53. action.abilityType = ABILITY_TYPE_EXTERNAL;
    54. // Call the PA ability of the corresponding action.
    55. FeatureAbility.callAbility(action);
    56. console.info("workout stopKeepBackground done")
    57. },
    58. }
    NOTE

    In the preceding code snippet, this.$app.$def.hmsData.eventCallbackMap indicates a collection of callbacks for global events. You can define it by referring to Initializing Modules.

  2. Apply for the exercise record to continue running in the background each time the 10-minute period is about to end.

    Call continueActivityRecord for the exercise record to stay alive in the background for 10 minutes.

    NOTE

    Call continueActivityRecord for the exercise record to continue running in the background each time the 10-minute period is about to end during the workout. Otherwise, your app will be terminated.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. import {HMSHealthKit, DeviceInfo, ActivityRecord, ComponentInfo, HMSHealthKitActivityType, HMSHealthKitDeviceType} from '@hw-hmscore/hms-js-health'
    2. export default {
    3. async continueActivityRecord () {
    4. // Call HMSHealthKit.continueActivityRecord and pass the exercise record ID for the record to continue running in the background.
    5. HMSHealthKit.continueActivityRecord("mysession1").then((result) => {
    6. // If the calling is successful, process the result.
    7. console.info("continueActivityRecord -> success :" + JSON.stringify(result))
    8. }).catch((error) => {
    9. // If the calling fails, process the failure in the callback.
    10. console.error("continueActivityRecord -> Error : " + JSON.stringify(error));
    11. });
    12. },
    13. }

  3. Stop ActivityRecord.

    Call endActivityRecord to stop the exercise record and the foreground service.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. import {HMSHealthKit, DeviceInfo, ActivityRecord, ComponentInfo, HMSHealthKitActivityType, HMSHealthKitDeviceType} from '@hw-hmscore/hms-js-health'
    2. // Message code for stopping the foreground service
    3. const MESSAGE_CODE_STOP = 1002;
    4. export default {
    5. async endActivityRecord () {
    6. // Call the HMSHealthKit.endActivityRecord method and pass the exercise record ID to stop the exercise record.
    7. HMSHealthKit.endActivityRecord("mysession1").then((result) => {
    8. console.info("endActivityRecord -> success :" + JSON.stringify(result))
    9. // If the calling is successful, call the Java PA to stop the foreground service.
    10. this.stopKeepBackground();
    11. }).catch((error) => {
    12. // If the calling fails, process the failure in the callback.
    13. console.error("endActivityRecord -> Error : " + JSON.stringify(error));
    14. });
    15. },
    16. // Call the Java PA to stop the foreground service.
    17. stopKeepBackground() {
    18. console.info("workout stopKeepBackground begin")
    19. // Set the Java PA action information. Note that you need to replace your app information in the sample code.
    20. var action = {};
    21. action.bundleName = 'com.huawei.ohos.healthkit.demo';
    22. action.abilityName = 'com.huawei.ohos.healthkit.demo.KeepBackgroundAbility';
    23. action.messageCode = MESSAGE_CODE_STOP;
    24. action.abilityType = ABILITY_TYPE_EXTERNAL;
    25. // Call the PA ability of the corresponding action.
    26. FeatureAbility.callAbility(action);
    27. console.info("workout stopKeepBackground done")
    28. },
    29. }

PA Side (Ability Calling Mode)

  1. Create a service ability file named KeepBackgroundAbility.java in the java directory.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. package com.huawei.ohos.healthkit.demo;
    2. // OHOS-related packages
    3. import ohos.aafwk.ability.Ability;
    4. import ohos.aafwk.content.Intent;
    5. import ohos.event.notification.NotificationRequest;
    6. import ohos.rpc.IRemoteObject;
    7. import ohos.hiviewdfx.HiLog;
    8. import ohos.hiviewdfx.HiLogLabel;
    9. import ohos.rpc.IRemoteBroker;
    10. import ohos.rpc.RemoteObject;
    11. import ohos.rpc.MessageParcel;
    12. import ohos.rpc.MessageOption;
    13. public class KeepBackgroundAbility extends Ability {
    14. // Define the log label.
    15. private static final HiLogLabel LABEL_LOG = new HiLogLabel(3, 0xD001100, "KeepBackgroundAbility");
    16. // Define notificationId for binding the foreground service to the notification.
    17. public static final int NOTIFICATION_ID = 1005;
    18. // Define the RemoteObject object for FA to send messages to PA.
    19. private MyRemote remote = new MyRemote();
    20. // When requesting the PA service, FA calls Ability.connectAbility to connect to PA. After the connection is successful, a remote object is returned in onConnect.
    21. @Override
    22. protected IRemoteObject onConnect(Intent intent) {
    23. super.onConnect(intent);
    24. return remote.asObject();
    25. }
    26. class MyRemote extends RemoteObject implements IRemoteBroker {
    27. // Message code for starting the foreground service
    28. private static final int START = 1001;
    29. // Message code for stopping the foreground service
    30. private static final int STOP = 1002;
    31. MyRemote() {
    32. super("MyService_MyRemote");
    33. }
    34. @Override
    35. public boolean onRemoteRequest(int code, MessageParcel data, MessageParcel reply, MessageOption option) {
    36. switch (code) {
    37. case START: {
    38. // Create a notification of the foreground service.
    39. sendNotification();
    40. HiLog.info(LABEL_LOG, "onRemoteRequest START");
    41. break;
    42. }
    43. case STOP: {
    44. // Cancel the notification of the foreground service.
    45. cancelNotification();
    46. HiLog.info(LABEL_LOG, "onRemoteRequest EXIT");
    47. break;
    48. }
    49. default: {
    50. return false;
    51. }
    52. }
    53. return true;
    54. }
    55. @Override
    56. public IRemoteObject asObject() {
    57. return this;
    58. }
    59. }
    60. @Override
    61. public void onStop() {
    62. super.onStop();
    63. cancelNotification();
    64. }
    65. @Override
    66. public void onCommand(Intent intent, boolean restart, int startId) {
    67. super.onCommand(intent, restart, startId);
    68. }
    69. @Override
    70. public void onDisconnect(Intent intent) {
    71. super.onDisconnect(intent);
    72. }
    73. // Create a notification and call keepBackgroundRunning() to bind the foreground service to the notification.
    74. private void sendNotification() {
    75. // Create a notification. The NOTIFICATION_ID constant is passed as notificationId.
    76. NotificationRequest request = new NotificationRequest(NOTIFICATION_ID);
    77. NotificationRequest.NotificationNormalContent content = new NotificationRequest.NotificationNormalContent();
    78. content.setTitle("Demo").setText("doing workout");
    79. NotificationRequest.NotificationContent notificationContent = new NotificationRequest.NotificationContent(content);
    80. request.setContent(notificationContent);
    81. // Bind the foreground service to the notification. The NOTIFICATION_ID constant is passed as notificationId.
    82. keepBackgroundRunning(NOTIFICATION_ID, request);
    83. }
    84. // Cancel the notification.
    85. private void cancelNotification() {
    86. cancelBackgroundRunning();
    87. }
    88. }

  2. In the configuration file, add configurations of the foreground service in module > abilities, set backgroundModes to dataTransfer, and declare the ohos.permission.KEEP_BACKGROUND_RUNNING permission.

    Collapse
    Word wrap
    Dark theme
    Copy code
    1. {
    2. "backgroundModes": [
    3. "dataTransfer"
    4. ],
    5. "name": "com.huawei.ohos.healthkit.demo.KeepBackgroundAbility",
    6. "type": "service",
    7. "visible": true
    8. }

Search in Guides
Enter a keyword.