Scenario-Based Subscription Gives Users Key Insight on Health and Fitness - Huawei Developers

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Many health and fitness apps provide a data subscription feature, which allows users to receive notifications in real time within the app, once their fitness or health records are updated, such as the day's step count, heart rate, or running distance.
However, tracking health and fitness over the long haul is not so easy. Real time notifications are less useful here. This can be a common challenge for fitness and health tracking apps, as meeting specific goals is not conducive for thinking over a long term. I have encountered this issue in my own fitness app. Let us say that a user of my app is trying to make an exercise plan. They set a long-term goal of walking for 10,000 steps for three times a week. When the step goal is achieved for the current day, my app will send a message with the day's step count. However, my app is still unable to notify the user whether the goal has been achieved for the week. That means, the user will have to check manually to see whether they have completed their long-term goals, which can be quite a hassle.
I stumbled across the scenario-based event subscription capability provided by HMS Core Health Kit, and tried integrating it into my app. Instead of subscribing to a single data type, I can now subscribe to specific scenarios, which entail the combination of one or more data types. In the example mentioned above, the scenario will be walking for 10,000 steps for any of the three days of a week. At the end of a week, my app will push a notification to the user, telling them whether they have met their goal.
After integrating the kit's scenario-based event subscription capability, my users have found it more convenient to track their long-term health and fitness goals. As a result, the user experience is considerably improved, and the retention period has been extended. My app is now a truly smart and handy fitness and health assistant. Next I'll show you how I managed to do this.
Integration Method​Registering as a Subscriber​Apply for the Health Kit service on HUAWEI Developers, select a product you have created, and select Registering the Subscription Notification Capability. You can select the HTTP subscription mode, enter the callback notification address, and test the connectivity of the address. Currently, the subscription capability is available to enterprise developers only. If you are an individual developer, you will not be able to use this capability for your app.
You can also select device-side notification and set the app package name and action if your app:
Uses the device-side subscription mode.
Subscribes to scenario-based goal events.
Relies on communications between APKs.
Registering Subscription Records​Send an HTTP request as follows to add or update subscription records:
Code:
POST
https://health-api.cloud.huawei.com/healthkit/v1/subscriptions
Request example
Code:
POST
https://health-api.cloud.huawei.com/healthkit/v1/subscriptions
Request body
Code:
POST
https://health-api.cloud.huawei.com/healthkit/v1/subscriptions
Content-Type: application/json
Authorization: Bearer ***
x-client-id: ***
x-version: ***
x-caller-trace-id: ***
{
"subscriberId": "08666998-78f6-46b9-8620-faa06cdbac2b",
"eventTypes": [
{
"type": "SCENARIO_GOAL_EVENT",
"subType": "ACHIEVE",
"eventType": "SCENARIO_GOAL_EVENT$ACHIEVE",
"goalInfo": {
"createTime": 1654660859105,
"startDay": 20220608, // Set the goal start date, which must be later than the date on which the goal is created.
"recurrence": {
"unit": 1, // Set the period unit to day.
"count": 30, // Set the entire period to 30 days.
"expectedAchievedCount": 28
},
"goals": [
{
"goalType": 1,
"metricGoal": {
"value": 10000, // Set the goal to 10,000 steps.
"fieldName": "steps",
"dataType": "com.huawei.continuous.steps.total"
}
}
]
}
}
]
}
Receiving Notifications of Goal Achievement​Send an HTTP request as follows to receive notifications of whether a goal is achieved:
Code:
POST
https://www.example.com/healthkit/notifications
Request example
Code:
POST
https://www.example.com/healthkit/notifications
Request body
Code:
POST
https://lfhealthdev.hwcloudtest.cn/test/healthkit/notifications
Content-Type: application/json
x-notification-signature: ***
[{
"appId": "101524371",
"subscriptionId": "3a82f885-97bf-47f8-84d1-21e558fe6e99",
"periodIndex": 0,
"periodStartDay": 20220608,
"periodEndDay": 20220608,
"goalAchieve": [{
"goalType": 1,
"metricGoal": {
"value": 10000.0,
"fieldName": "steps",
"dataType": "com.huawei.continuous.steps.total"
},
"achievedFlag": true // Goal achieved.
}
]
}
(Optional) Querying Goal Achievement Results​Send an HTTP request as follows to query results of scenario-based events in a single period:
Code:
GET
https://health-api.cloud.huawei.com/healthkit/v1/subscriptions/3a82f885-97bf-47f8-84d1-21e558fe6e99/achievedRecord
Request example
Code:
GET
https://health-api.cloud.huawei.com/healthkit/v1/subscriptions/3a82f885-97bf-47f8-84d1-21e558fe6e99/achievedRecord
Response body
Code:
HTTP/1.1 200 OK
Content-type: application/json;charset=utf-8
[
{
"openId": "MDFAMTAxNTI0MzcxQGQ0Y2M3N2UxZTVmNjcxNWFkMWQ5Y2JjYjlmZDZiaNTY3QDVhNmNkY2FiaMTFhYzc4NDk4NDI0MzJiaNjg0MzViaYmUyMGEzZjZkNzUzYWVjM2Q5ZTgwYWM5NTgzNmY",
"appId": "101524371",
"subscriptionId": "3a82f885-97bf-47f8-84d1-21e558fe6e99",
"periodIndex": 0,
"periodStartDay": 20220608,
"periodEndDay": 20220608,
"goalAchieve": [{
"goalType": 1,
"metricGoal": {
"value": 10000.0, // Goal value
"fieldName": "steps",
"dataType": "com.huawei.continuous.steps.total"
},
"achievedResult": "20023", // Actual value
"achievedFlag": true // Flag indicating goal achieved
}]
},
{
"openId": "MDFAMTAxNTI0MzcxQGQ0Y2M3N2UxZTVmNjcxNWFkMWQ5Y2JjYjlmZDZiaNTY3QDVhNmNkY2FiaMTFhYzc4NDk4NDI0MzJiaNjg0MzViaYmUyMGEzZjZkNzUzYWVjM2Q5ZTgwYWM5NTgzNmY",
"appId": "101524371",
"subscriptionId": "3a82f885-97bf-47f8-84d1-21e558fe6e99",
"periodIndex": 1,
"periodStartDay": 20220609,
"periodEndDay": 20220609,
"goalAchieve": [{
"goalType": 1,
"metricGoal": {
"value": 10000.0, // Goal value
"fieldName": "steps",
"dataType": "com.huawei.continuous.steps.total"
},
"achievedResult": "9800", // Actual value
"achievedFlag": false // Flag indicating goal not achieved
}]
}
]
Conclusion​It is common to find apps that notify users of real-time fitness and health events, for example, for every kilometer that's run, or when the user's heart rate crosses a certain threshold, or when they have walked certain number of steps that current day.
However, health and fitness goals tend to be long-term, and can be broken down into small, periodic goals. This means that apps that only offer real time notifications are not as appealing as might otherwise be.
Users may set a long-term goal, like losing 10 kg in three months, or going to the gym and exercising three times per week for the upcoming year, and then break down the goal into one month or one week increments. They may expect apps to function as a reminder of their fitness or health goals over the long run.
Health Kit can help us do this easily, without requiring too much development workload.
This kit provides the scenario-based event subscription capability, empowering health and fitness apps to periodically notify users of whether or not they have met their set goals, in a timely manner.
With these notifications, app users will be able to keep better track of their goals, and be better motivated to meet them, or even use the app to share their goals with friends and loved ones.
Reference​HMS Core Health Kit
Data Subscription Capability Development Guide

Related

Implementing Message Push for Your Quick App Rapidly

Now you have a quick app released on HUAWEI AppGallery. Do you want to attract more users and win more traffic for it? HUAWEI Push Kit can help you with that. You can push messages at the right moment to users for them to open your quick app to view more details. This better engages your users and improves activity.
Typical scenarios of push messages are as follows:
l Shopping quick apps can push information about new products and discounts to users to attract more customers for merchants.
l Reading quick apps can push information such as popular books and chapter updates to users, providing up-to-date information that users concern about.
l Food & drink quick apps can push information about food and good restaurants to users, facilitating user's life and bringing more users for the catering industry.
Follow instructions in this document to integrate HUAWEI Push Kit to your quick app to get all these benefits.
Getting Started
The hardware requirements are as follows:
l A computer with Node.js 10 or later and HUAWEI Quick App IDE of the latest version installed
l A Huawei mobile phone running EMUI 8.0 or later (with a USB cable)
Development Guide
Enabling HUAWEI Push Kit
1. Sign in to AppGallery Connect and click My projects.
2. Click the card of the project for which you need to enable the service. Click the Manage APIs tab, and toggle the Push Kit switch.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
3. Click the General information tab. In the App information area, set SHA-256 certificate fingerprint to the SHA-256 fingerprint.
Subscribing to Push Messages
The service process is as follows.
1. Call the push.getProvider API to check whether the current device supports HUAWEI Push Kit. If huawei is returned, the device supports HUAWEI Push Kit. You can call other relevant APIs only when the device supports HUAWEI Push Kit.
2. Call the push.subscribe API to obtain regId (registered ID). The ID is also called a token or push token, which identifies messages sent by HUAWEI Push Kit.
Notice: It is recommended that the preceding APIs be called in app.ux that takes effect globally.
3. Report the obtained regId to the server of your quick app through the Fetch Data API, so the server can push messages to the device based on regId. Generally, the value of regId does not change and does not need to be reported to the server each time after it is obtained.
You are advised to call the Data Storage API to store the regId locally. Each time the regId is obtained, compare the regId with that stored locally. If they are the same, the regId does not need to be reported to the server. Otherwise, report the regId to the server.
The service process is as follows.
The sample code for comparing the obtained regId with that stored locally is as follows:
Code:
checkToken() {
var subscribeToken=this.$app.$def.dataApp.pushtoken;
console.log("checkToken subscribeToken= "+subscribeToken);
var storage = require("@system.storage");
var that=this;
storage.get({
key: 'token',
success: function (data) {
console.log("checkToken handling success data= "+data);
if (subscribeToken != data) {
// Report regId to your service server.
that.uploadToken(subscribeToken);
that.saveToken(subscribeToken);
}
},
fail: function (data, code) {
console.log("handling fail, code = " + code);
}
})
},
The sample code for saving regId locally is as follows:
saveToken(subscribeToken){
console.log("saveToken");
var storage = require("@system.storage");
storage.set({
key: 'token',
value: subscribeToken,
success: function (data) {
console.log("saveToken handling success");
},
fail: function (data, code) {
console.log("saveToken handling fail, code = " + code);
}
})
},
Testing Push Message Sending
You can test the push function by sending a push message to your test device. In this case, regId (push token) uniquely identifies your device. With it, your service server can accurately identify your device and push the message to your quick app on the device. Your device can receive the pushed message in any of the following conditions:
l The quick app has been added to the home screen.
l The quick app has been added to MY QUICK APP.
l The quick app has been used before.
l The quick app is running.
You can use either of the following methods to send a push message to a quick app that has been released on AppGallery or run by Huawei Quick App Loader.
l Select some target users in AppGallery Connect and send the push message.
l Call the specific server API to send the push message to users in batches.
Sending a Push Message Through AppGallery Connect
This method is simple. You only need to configure the recipients in AppGallery Connect. However, the target user scope is smaller than that through the API.
1. Sign in to AppGallery Connect and click My apps.
2. Find your app from the list and click the version that you want to test.
3. Go to Operate > Promotion > Push Kit. Click Add notification and configure the push message to be sent.
Sending a Push Message by Calling the API
1. Call the accessToken API to obtain the access token, which will be used in the push message sending API.
2. Call the push message sending API. The sample code of the push message body is as follows:
Code:
var mData = {
"pushtype": 0, // The value 0 indicates a notification message.
"pushbody": {
"title": "How can young people make a living? ",
"description": "Why did he choose to be a security guard after college graduation? ",
"page": "/", // Path of the quick app page that is displayed when a user taps a notification message. This parameter is valid only when pushtype is set to 0. /" Go to the app home page.
"params": {
"key1": "test1",
"key2": "test2"
},
"ringtone": {
"vibration": "true",
"breathLight": "true"
}
}
};
var formatJsonString = JSON.stringify(mData);
var messbody = {
"validate_only": false,
"message": {
"data": formatJsonString, // The data type is JsonString, not a JSON object.
"android": {
"fast_app_target": 1, // The value 1 indicates that a push message is sent to a quick app running by Huawei Quick App Loader. To send a push message to a quick app from AppGallery, set this parameter to 2.
"collapse_key": -1,
"delivery_priority": "HIGH",
"ttl": "1448s",
"bi_tag": "Trump",
},
"token": ['pushtoken1','pushtoken2'], // Target users of message pushing.
}
};
For details, please refer to Accessing HUAWEI Push Kit.

How to Request Ads Using Location Data

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Have you ever had the following experience: When you are walking on a road and searching for car information in a social networking app, an ad pops up to you suddenly, telling you about discounts at a nearby car dealership. Given the advantages of the short distance, demand matching, and discount, you are more likely to go to the place for some car details, and this ad succeeds to attract you to the activity.
Nowadays, advertising has been one of the most effective ways for app developers to monetize traffic and achieve business success. By adding sponsored links or displaying ads in various formats, such as splash ads and banner ads, in their apps, app developers will be able to attract targeting audiences to view and tap the ads, or even purchase items. So how do apps always push ads for the right users at the right moment? Audience targeting methods may be the right thing they are looking for.
In the car selling situation, you may wonder how the ad can know what you want.
This benefits from the location-based ad requesting technology. Thanks to the increasing sophistication of ad technology, apps are now able to request user location-based ads, when being authorized, and audience targeting also makes it possible.
So the most important thing for an ad is to reach its target customers. Therefore, app marketing personnel should be giving a lot of thought to how to target audience, place ads online to advertise their items, and maximize ad performance.
That's why it is critical for apps to track audience information. Mobile location data can indicate the user's patterns of consumption. Office workers tend to order a lot of takeout on busy weekdays, trendsetters may prefer more stylish and fashion activities, and homeowners in high-end villas are more likely to purchase luxury items, to cite just some examples. All these mean that user attributes can be extracted from location information for ad matching purposes, and ad targeting should be as precise and multi-faceted as possible.
As an app developer, I am always looking for new tools to help me match and request ads with greater precision. Some of these tools have disappointed me greatly. Fortunately, I stumbled upon Ads Kit in HMS Core, which is capable of requesting ads based on geographical locations. With this tool, I've been able to integrate ads in various formats into my app with greater ease, and provide targeted, audience specific marketing content, including native and roll ads for nearby restaurants, stores, courses, and more.
I've been able to achieve monetization success with improvement of user conversions and substantially boost my ad revenue as a result.
To display ads more efficiently and accurately, my app can carry users’ location information through the Ads SDK, when requesting ads, so long as my app has been authorized to obtain the users' location information.
The SDK is surprisingly easy to integrate. Here's how to do it:
Integration Steps​First, request permissions for your app.
1. As the Android OS provides two location permissions: ACCESS_COARSE_LOCATION (approximate location permission) and ACCESS_FINE_LOCATION (precise location permission), configure the permissions in the AndroidManifest.xml file.
Code:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
2. (Optional) If your app needs to continuously locate the device of Android 10 or later when it runs in the background, configure the ACCESS_BACKGROUND_LOCATION permission in the AndroidManifest.xml file.
Code:
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
3. Dynamically apply for related location permissions (according to requirements for dangerous permissions in Android 6.0 or later).
Code:
// Dynamically apply for required permissions if the API level is 28 or lower.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
Log.i(TAG, "android sdk <= 28 Q");
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) !=
PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
String[] strings =
{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION};
ActivityCompat.requestPermissions(this, strings, 1);
}
} else {
// Dynamically apply for required permissions if the API level is greater than 28. The android.permission.ACCESS_BACKGROUND_LOCATION permission is required.
if (ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
&& ActivityCompat.checkSelfPermission(this,
"android.permission.ACCESS_BACKGROUND_LOCATION") != PackageManager.PERMISSION_GRANTED) {
String[] strings = {android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.ACCESS_COARSE_LOCATION,
"android.permission.ACCESS_BACKGROUND_LOCATION"};
ActivityCompat.requestPermissions(this, strings, 2);
}
}
If your app requests and obtains the location permission from a user, the SDK will carry the location information by default. If you do not want to carry the location information in an ad request from the app, you can call the setRequestLocation() API and set requestLocation to false.
Code:
// Here, a banner ad is used as an example. The location information is not carried.
AdParam adParam = new AdParam.Builder()
// Indicates whether location information is carried in a request. The options are true (yes) and false (no). The default value is true.
.setRequestLocation(false)
.build();
bannerView.loadAd(adParam);
Conclusion​All app developers are deeply concerned with how to boost conversions and revenue, by targeting ad audiences. The key is gaining insight into what users care most about. Real time location is a key piece of this puzzle.
If your apps are permitted to do so, you can add personalized ads in apps for these users. Displaying ads through ad networks may be the most popular way to help you monetize traffic and other content. A good advertising mechanism can help you a lot, and in this way, location-based ad requesting is very important in this process. Through users' locations, you will be able to give what they are looking for and show ads perfectly matching user intent. All these implementations may be a complicated process, and I have been also searching for good ways for better results.
As you can see from the coding above, this SDK is easy to implement, with just a few lines of code, and is highly useful for you to request location-based ads. I hope that it serves you as well as it has served me.
References​Ads Kit
Development guide

Allow Users to Track Fitness Status in Your App

During workouts, users expect to be able to track their status and data in real time within the health or fitness app on their phone. Huawei phone users can link a piece of equipment, like a treadmill or spinner bike, via the Huawei Health app, and start and track their workout within the app. As a fitness and health app developer, you can read activity records from the Huawei Health app, and display the records in your app. It is even possible to control the workout status directly within your app, and obtain real-time activity data, without having to redirect users to the Huawei Health app, which helps users conveniently track their workout and greatly enhances the user experience. Here is how.
HMS Core Health Kit provides a wide range of capabilities for fitness and health app developers. Its extended capabilities open up a wealth of real time activity and health data and solutions specific to different scenarios. For example, after integrating the extended capabilities, you can call the APIs for starting, pausing, resuming, and stopping activities, to control activity status directly within your app, without redirecting users to the Huawei Health app. The Huawei Health app runs unobtrusively in the background throughout this entire process.
The extended capabilities also offer APIs for obtaining and halting the collection of real-time workout data. To prevent data loss, your app should call the API for obtaining real-time data before the workout starts, and avoid calling the API for halting the collection of real-time data before the workout ends. If the user links their phone with a Huawei wearable device via the Huawei Health app, the workout status in your app will be synched to the wearable device. This means that the wearable device will automatically display the workout screen when the user starts a workout in your app, and will stop displaying it as soon as the workout is complete. Make sure that you have applied for the right scopes from Huawei and obtained the authorization from users before API calling. Otherwise, API calling will fail. The following workouts are currently supported: outdoor walking, outdoor running, outdoor cycling, indoor running (on a treadmill), elliptical machine, rowing machine, and indoor cycling.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Redirecting to the device pairing screen
Demo​
Preparations​Applying for Health Kit​Before applying for Health Kit, you will need to apply for Account Kit first.
Integrating the HMS Core SDK​Before integrating the Health SDK, integrate the Account SDK first.
Before getting started, you need to integrate the HMS Core SDK into your app using Android Studio. Make sure that you use Android Studio V3.3.2 or later during the integration of Health Kit.
Development Procedure​Starting Obtaining Real-time Activity Data​1. Call the registerSportData method of the HiHealthDataStore object to start obtaining real time activity data.
2. Check the returned result through the request parameter HiSportDataCallback.
The sample code is as follows:
Code:
HiHealthDataStore.registerSportData(context, new HiSportDataCallback() {
@Override
public void onResult(int resultCode) {
// API calling result.
Log.i(TAG, "registerSportData onResult resultCode:" + resultCode);
}
@Override
public void onDataChanged(int state, Bundle bundle) {
// Real-time data change callback.
Log.i(TAG, "registerSportData onChange state: " + state);
StringBuffer stringBuffer = new StringBuffer("");
if (state == HiHealthKitConstant.SPORT_STATUS_RUNNING) {
Log.i(TAG, "heart rate : " + bundle.getInt(HiHealthKitConstant.BUNDLE_KEY_HEARTRATE));
Log.i(TAG, "distance : " + bundle.getInt(HiHealthKitConstant.BUNDLE_KEY_DISTANCE));
Log.i(TAG, "duration : " + bundle.getInt(HiHealthKitConstant.BUNDLE_KEY_DURATION));
Log.i(TAG, "calorie : " + bundle.getInt(HiHealthKitConstant.BUNDLE_KEY_CALORIE));
Log.i(TAG, "totalSteps : " + bundle.getInt(HiHealthKitConstant.BUNDLE_KEY_TOTAL_STEPS));
Log.i(TAG, "totalCreep : " + bundle.getInt(HiHealthKitConstant.BUNDLE_KEY_TOTAL_CREEP));
Log.i(TAG, "totalDescent : " + bundle.getInt(HiHealthKitConstant.BUNDLE_KEY_TOTAL_DESCENT));
}
}
});
Stopping Obtaining Real-time Activity Data​1. Call the unregisterSportData method of the HiHealthDataStore object to stop obtaining the real time activity data.
2. Check the returned result through the request parameter HiSportDataCallback.
The sample code is as follows:
Code:
HiHealthDataStore.unregisterSportData(context, new HiSportDataCallback() {
JSONObject jsonResult
@Override
public void onResult(int resultCode) {
// API calling result.
Log.i(TAG, "unregisterSportData onResult resultCode:" + resultCode);
}
@Override
public void onDataChanged(int state, Bundle bundle) {
// The API is not called at the moment.
}
});
Starting an Activity According to the Activity Type​1. Call the startSport method of the HiHealthDataStore object to start a specific type of activity.
2. Use the ResultCallback object as a request parameter to get the query result.
The sample code is as follows:
Code:
// Outdoor running.
int sportType = HiHealthKitConstant.SPORT_TYPE_RUN;
HiHealthDataStore.startSport(context, sportType, new ResultCallback() {
@Override
public void onResult(int resultCode, Object message) {
if (resultCode == HiHealthError.SUCCESS) {
Log.i(TAG, "start sport success");
}
}
});
3. For activities that depend on equipment like treadmills, rowing machines, elliptical machines, and stationary bikes, you will need to first check whether the relevant equipment has been paired in the Huawei Health app before starting the activity. The following uses a rowing machine as an example.
If there is one rowing machine paired, this machine will be connected by default, and the activity will then start in the background.
If the app is paired with more than one rowing machines, a pop-up window will display prompting the user to select a machine. After the user makes their choice, the window will disappear and the workout will start in the background.
If the app is not paired with any rowing machine, the user will be redirected to the device pairing screen in the Huawei Health app, before being returned to your app. The workout will then start in the background.
Starting an Activity Based on the Device Information​1. Call the startSportEx method of the HiHealthDataStore object, and pass the StartSportParam parameter for starting the activity. You can control whether to start the activity in the foreground or in the background by setting CharacteristicConstant.SportModeType.
2. Use the ResultCallback object as a request parameter to get the activity starting result.
The sample code is as follows:
Code:
// The following takes the rowing machine as an example.
// MAC address, with every two digits separated by a colon (:), for example, 11:22:33:44:55:66.
String macAddress = "11:22:33:44:55:66" ;
// Whether FTMP is supported. 0: no; 1: yes.
int isSupportedFtmp = CharacteristicConstant.FtmpType.FTMP_SUPPORTED.getFtmpTypeValue();
// Device type: rowing machine.
int deviceType = CharacteristicConstant.DeviceType.TYPE_ROWER_INDEX.getDeviceTypeValue();
// Activity type: rowing machine.
int sportType = CharacteristicConstant.EnhanceSportType.SPORT_TYPE_ROW_MACHINE.getEnhanceSportTypeValue();
// Construct startup parameters for device connection and activity control.
StartSportParam param = new StartSportParam(macAddress, isSupportedFtmp, deviceType, sportType);
// Whether to start the activity in the foreground (0) or background (1).
param.putInt(HiHealthDataKey.IS_BACKGROUND,
CharacteristicConstant.SportModeType.BACKGROUND_SPORT_MODE.getType());
HiHealthDataStore.startSportEx(mContext, param, new ResultCallback() {
@Override
public void onResult(int resultCode, Object message) {
if (resultCode == HiHealthError.SUCCESS) {
Log.i(TAG, "start sportEx success");
}
}
});
Stopping an Activity​1. Call the stopSport method of the HiHealthDataStore object to stop a specific type of activity. Note that you cannot use this method to stop activities started in the foreground.
2. Use the ResultCallback object as a request parameter to get the query result.
The sample code is as follows:
Code:
HiHealthDataStore.stopSport(context, new ResultCallback() {
@Override
public void onResult(int resultCode, Object message) {
if (resultCode == HiHealthError.SUCCESS) {
Log.i(TAG, "stop sport success");
}
}
});
Conclusion​Huawei phone users can use the Huawei Health app to bind wearable devices, start a workout and control their workout status, and track their workouts over time. When developing a fitness and health app, you can harness the capabilities in Health Kit and the Huawei Health app to get the best of all worlds: easy workout management free of annoying redirections. By calling the APIs provided by the kit's extended capabilities, you will be able to start, pause, resume, and stop workouts directly in your app, or obtain real time workout data from the Huawei Health app and display it in your app, with Huawei Health running in the background. This will considerably enhance the user experience, and make your fitness and health app much more appealing to a wider audience.
References​HMS Core Health Kit Development Guide
Bundle Keys for Real-time Activity
Applying for the HUAWEI ID Service

Sandbox Testing and Product Redelivery, for In-App Purchases

{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
Hey, guys! I'm still working on my mobile multiplayer survival game. In my article titled Build a Game That Features Local In-App Purchases , I shared my experience of configuring in-app product information in the language and currency of the country or region where the user's account is located, which streamlines the purchase journey for users and boosts monetization.
Some new challenges have arisen, though. When an in-app product is configured, I need to test its purchase process before it can be brought online. Hence, I need a virtual purchase environment that doesn't actually charge me real money. Sandbox testing it is.
Aside from this, network latency or abnormal process termination can sometimes cause data of the app and the in-app purchases server to be out of synchronization. In this case, my app won't deliver the virtual products users have just purchased. This same issue can be pretty tricky for many developers and operations personnel as we don't want to see a dreaded 1 star on the "About this app" screen of our app on app stores or users venting their anger about our apps on tech forums. Of course my app lets users request a refund by filing a ticket to start the process, but guess how they feel about the extra time they have to put into this?
So I wondered how to implement sandbox testing and ensure a successful product delivery for my app. That's where HMS Core In-App Purchases (IAP) comes to the rescue. I integrated its SDK to do the trick. Let's see how it works.
Sandbox Testing​Sandbox testing of IAP supports end-to-end testing without real payments for joint debugging.
Preparing for Sandbox Testing​I added a test account by going to Users and permissions > Sandbox > Test accounts. The test account needs to be a registered HUAWEI ID and will take effect between 30 minutes and an hour after it has been added.
As the app package I want to test hasn't been released in AppGallery Connect, its versionCode should exceed 0. For an app package once released in AppGallery Connect, the versionCode should be greater than that of the released one.
If you fail to access the sandbox when trying out the function, use the IapClient.isSandboxActivated (for Android) or HMSIAP.isSandboxActivated API (for HarmonyOS) in your app for troubleshooting.
Testing Non-Subscription Payments​I signed in with the test account and installed the app to be tested on my phone. When a request was initiated to purchase a one-time product (stealth skill card), IAP detected that I was a test user, so it skipped the payment step and displayed a message indicating that the payment was successful.
It was impressively smooth. The purchase process in the sandbox testing environment accurately reflected what would happen in reality. I noticed that the purchaseType field on the receipt generated in IAP had a value of 0, indicating that the purchase was a sandbox test record.
Let's try out a non-consumable product — the chance to unlock a special game character. In the sandbox testing environment, I purchased it and consumed it, and then I could purchase this character again.
Sandbox testing for a one-time product on a phone
Testing Subscription Renewal​The purchase process of subscriptions is similar to that of one-time products but subscriptions have more details to consider, such as the subscription renewal result (success or failure) and subscription period. Test subscriptions renew much faster than actual subscriptions. For example, the actual subscription period is 1 week, while the test subscription renews every 3 minutes.
Sandbox testing for a subscription on a phone
Sandbox testing helps me test new products before I launch them in my app.
Consumable Product Redelivery​When a user purchased a consumable such as a holiday costume, my app would call an API to consume it. However, if an exception occurred, the app would fail to determine whether the payment was successful, so the purchased product might not be delivered as expected.
Note: A non-consumable or subscription will not experience such a delivery failure because they don't need to be consumed.
I turned to IAP to implement consumable redelivery. The process is as follows.
Consumable Redelivery Process​
Here's my development process.
1. Call obtainOwnedPurchases to obtain the purchase data of the consumable that has been purchased but not delivered. Specify priceType as 0 in OwnedPurchasesReq.
If this API is successfully called, IAP will return an OwnedPurchasesResult object, which contains the purchase data and signature data of all products purchased but not delivered. Use the public key allocated by AppGallery Connect to verify the signature.
The data of each purchase is a character string in JSON format and contains the parameters listed in InAppPurchaseData. Parse the purchaseState field from the InAppPurchaseData character string. If purchaseState of a purchase is 0, the purchase is successful. Deliver the required product for this purchase again.
Code:
// Construct an OwnedPurchasesReq object.
OwnedPurchasesReq ownedPurchasesReq = new OwnedPurchasesReq();
// priceType: 0: consumable; 1: non-consumable; 2: subscription
ownedPurchasesReq.setPriceType(0);
// Obtain the Activity object that calls the API.
final Activity activity = getActivity();
// Call the obtainOwnedPurchases API to obtain the order information about all consumable products that have been purchased but not delivered.
Task<OwnedPurchasesResult> task = Iap.getIapClient(activity).obtainOwnedPurchases(ownedPurchasesReq);
task.addOnSuccessListener(new OnSuccessListener<OwnedPurchasesResult>() {
@Override
public void onSuccess(OwnedPurchasesResult result) {
// Obtain the execution result if the request is successful.
if (result != null && result.getInAppPurchaseDataList() != null) {
for (int i = 0; i < result.getInAppPurchaseDataList().size(); i++) {
String inAppPurchaseData = result.getInAppPurchaseDataList().get(i);
String inAppSignature = result.getInAppSignature().get(i);
// Use the IAP public key to verify the signature of inAppPurchaseData.
// Check the purchase status of each product if the verification is successful. When the payment has been made, deliver the required product. After a successful delivery, consume the product.
try {
InAppPurchaseData inAppPurchaseDataBean = new InAppPurchaseData(inAppPurchaseData);
int purchaseState = inAppPurchaseDataBean.getPurchaseState();
} catch (JSONException e) {
}
}
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
if (e instanceof IapApiException) {
IapApiException apiException = (IapApiException) e;
Status status = apiException.getStatus();
int returnCode = apiException.getStatusCode();
} else {
// Other external errors.
}
2. Call the consumeOwnedPurchase API to consume a delivered product.
Conduct a delivery confirmation for all products queried through the obtainOwnedPurchases API. If a product is already delivered, call the consumeOwnedPurchase API to consume the product and instruct the IAP server to update the delivery status. After the consumption is complete, the server resets the product status to available for purchase. Then the product can be purchased again.
[HEADING=1]Conclusion[/HEADING]
A 1-star app rating is an unwelcome sight for any developer. For game developers in particular, one of the major barriers to their app achieving a 5-star rating is a failed virtual product delivery.
I integrated HMS Core In-App Purchases into my mobile game to implement the consumable redelivery function, so now my users can smoothly make in-app purchases. Furthermore, when I need to launch a new skill card in the game, I can perform tests without having to fork out real money thanks to the kit.
I hope this practice helps you guys tackle similar challenges. If you have any other tips about game development that you'd like to share, please leave a comment.
}
});

Reel in Users with Topic-based Messaging

Smartphones are everywhere these days and play an important role in our daily lives. The popularization of smartphones has led to a wave of mobile apps hitting the market. So, the homogeneous competition between apps is more fierce than ever and developers are trying their best to figure out how best to attract users to their apps. Most developers resort to message pushing, which leads to an exponential growth of pushed messages. As a result, users quickly become flooded with pushed messages and struggle to find the information they need.
The explosion of pushed messages means that crafting eye-catching messages that appeal to users has never been more crucial and challenging. Like many other developers, I also encountered this problem. I have pushed many promotional messages to users of my app, but the outcome is not particularly positive. So I wondered if it is possible to push messages only to a specific user group, for example, sending car-related product promotion messages to users with cars.
It occurred to me that I came across HMS Core Push Kit, which provides a function that allows developers to send topic-based messages. With this function, developers can customize messages by topic to match users' habits or interests and then regularly send these messages to user devices via a push channel. For example, a weather forecast app can send weather forecast messages concerning a city that users have subscribed to, or a movie ticket-booking app can send reminders to users who have followed a particular movie.
Isn't that exactly what I need? So I decided to play about with this function, and it turned out to be very effective. Below is a walkthrough of how I integrated this function into my app to send topic-based messages. I hope this will help you.
Development Procedure​
Generally, three development steps are required for using the topic-based messaging function.
Step 1: Subscribe to a topic within the app.
Step 2: Send a message based on this topic.
Step 3: Verify that the message has been received.
The figure below shows the process of messaging by topic subscription on the app server.
{
"lightbox_close": "Close",
"lightbox_next": "Next",
"lightbox_previous": "Previous",
"lightbox_error": "The requested content cannot be loaded. Please try again later.",
"lightbox_start_slideshow": "Start slideshow",
"lightbox_stop_slideshow": "Stop slideshow",
"lightbox_full_screen": "Full screen",
"lightbox_thumbnails": "Thumbnails",
"lightbox_download": "Download",
"lightbox_share": "Share",
"lightbox_zoom": "Zoom",
"lightbox_new_window": "New window",
"lightbox_toggle_sidebar": "Toggle sidebar"
}
You can manage topic subscriptions in your app or on your app server. I will detail the procedures and codes for both of these methods later.
Key Steps and Coding​
Managing Topic Subscription in Your App​
The following is the sample code for subscribing to a topic:
Code:
public void subtopic(View view) {
String SUBTAG = "subtopic";
String topic = "weather";
try {
// Subscribe to a topic.
HmsMessaging.getInstance(PushClient.this).subscribe(topic).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(Task<Void> task) {
if (task.isSuccessful()) {
Log.i(SUBTAG, "subscribe topic weather successful");
} else {
Log.e(SUBTAG, "subscribe topic failed,return value is" + task.getException().getMessage());
}
}
});
} catch (Exception e) {
Log.e(SUBTAG, "subscribe faied,catch exception:" + e.getMessage());
}
}
The figure below shows that the topic is successfully subscribed to.
The following is the sample code for unsubscribing from a topic:
Code:
public void unsubtopic(View view) {
String SUBTAG = "unsubtopic";
String topic = "weather";
try {
// Subscribe to a topic.
HmsMessaging.getInstance(PushClient.this).unsubscribe(topic).addOnCompleteListener(new OnCompleteListener<Void>() {
@Override
public void onComplete(Task<Void> task) {
if (task.isSuccessful()) {
Log.i(SUBTAG, "unsubscribe topic successful");
} else {
Log.e(SUBTAG, "unsubscribe topic failed,return value is" + task.getException().getMessage());
}
}
});
} catch (Exception e) {
Log.e(SUBTAG, "subscribe faied,catch exception:" + e.getMessage());
}
}
The figure below shows that the topic is successfully unsubscribed from.
Managing Topic Subscription on Your App Server​
Obtaining an Access Token​
You can call the API (https://oauth-login.cloud.huawei.com/oauth2/v3/token) of the HMS Core Account Kit server to obtain an app-level access token for authentication.
Request for obtaining an access token
Code:
POST /oauth2/v3/token HTTP/1.1
Host: oauth-login.cloud.huawei.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&
client_id=<APP ID >&
client_secret=<APP secret >
Demonstration of obtaining an access token
Subscribing to and Unsubscribe from Topics​
Your app server can subscribe to or unsubscribe from a topic for your app by calling the corresponding subscription and unsubscription APIs of the Push Kit server. The URLs of the subscription and unsubscription APIs differ slightly, but the header and body of the subscription request are the same as those of the unsubscription request. The details are as follows:
URL of the subscription API
Code:
https://push-api.cloud.huawei.com/v1/[appid]/topic:subscribe
URL of the unsubscription API
Code:
https://push-api.cloud.huawei.com/v1/[appid]/topic:unsubscribe
Example of the request header, where the token following Bearer is the access token obtained in the previous step
Code:
Authorization: Bearer CV0kkX7yVJZcTi1i+uk...Kp4HGfZXJ5wSH/MwIriqHa9h2q66KSl5
Content-Type: application/json
Example of the request body
Code:
{
"topic": "weather",
"tokenArray": [
"AOffIB70WGIqdFJWJvwG7SOB...xRVgtbqhESkoJLlW-TKeTjQvzeLm8Up1-3K7",
"AKk3BMXyo80KlS9AgnpCkk8l...uEUQmD8s1lHQ0yx8We9C47yD58t2s8QkOgnQ"
]
}
Request demonstration
Sending Messages by Topic​
You can send messages based on a created topic through the HTTPS protocol. The sample code for HTTPS-based messaging is as follows:
Code:
{
"validate_only": false,
"message": {
"notification": {
"title": "message title",
"body": "message body"
},
"android": {
"notification": {
"click_action": {
"type": 1,
"action": "com.huawei.codelabpush.intent.action.test"
}
}
},
"topic": "weather"
}
}
The figure below shows that the message is received and displayed on the user device.
Precautions​
1. Your app can subscribe to any existing topics, or create new topics. When subscribing to a topic that does not exist, your app will request Push Kit to create such a topic. Then, any other app can subscribe to this topic.
2. The Push Kit server provides basic APIs for managing topics. You can subscribe to or unsubscribe from a topic using a maximum of 1000 tokens at a time. Each app can have a maximum of 2000 different topics.
3. The subscription relationship between the topic and token takes effect one minute after the subscription is complete. After the subscription takes effect, you'll be able to specify one topic, or a set of topic matching conditions to send messages in batches.
That's all for integrating the topic-based messaging function. In addition to this function, I also found that Push Kit provides functions such as scenario-based messaging and geofence-based messaging, which I think are very useful because they allow apps to push messages that are suitable for users' scenarios to users.
For example, with the scenario-based messaging function, an app can automatically send messages to users by scenario, such as when headsets are inserted, the Bluetooth car stereo is disconnected, or the motion status changes. With the geofence-based messaging function, an app can send messages to users by location, such as when users enter a shopping mall or airport and stay there for a specified period of time.
These functions, I think, can help apps improve user experience and user engagement. If you want to try out these functions, click here to view the official website.
Conclusion​
The key to a successful app that stands out from the crowd is crafting messages that immediately grasp users' attention. This requires customizing messages by topic to match users' habits or interests, then regularly sending these messages to user devices via a push channel. As I illustrated earlier in this article, my solution for doing so is to integrate the topic-based messaging function in Push Kit, and it turns out to be very effective. If you have similar demands, have a try on this function and you may be surprised.

Categories

Resources