当前位置:网站首页>运动App如何实现端侧后台保活,让运动记录更完整?
运动App如何实现端侧后台保活,让运动记录更完整?
2022-06-28 15:48:00 【51CTO】
你在锻炼健身时,有没有遇到这样的情况?辛辛苦苦锻炼了几小时,却发现App停止了运行,本次运动并没有被记录到App上,从而失去了一个查看完整运动数据的机会?
运动类App是通过手机或者穿戴设备的传感器,来识别运动状态并反馈给用户的,App能否在手机后台时刻保持运行是影响运动数据完整性的关键因素。为了满足用户查看完整运动数据的需求,运动类App都希望在设备后台保活,并通过传感器实时记录用户的运动数据。但大部分手机厂商为了节省电量,一旦应用处于后台就会被系统限制甚至强制关闭,导致最终呈现给用户的运动记录不完整。 运动类App要想实现端侧后台保活,目前通常有两种解决办法:
- 引导用户在手机上手动设置保活,如关闭电池优化,允许App后台运行。这种方法缺点在于操作步骤较复杂,用户学习成本较高。
- 可以通过集成华为运动健康服务来解决此问题,运动健康服务提供支持后台保活的运动记录API,集成该能力后应用能够在用户的锻炼过程中在华为手机后台保持运行,从而实现用户锻炼过程中的运动记录不间断。
那如何实现后台保活功能呢?以下是详细的集成步骤。
集成步骤
- 请参考开发准备完成申请Health Kit服务,勾选产品必需申请的数据权限并集成SDK。
- 调用后台保活功能需申请运动记录读取权限,再获取用户授权完成权限申请。
- 为保证您的应用不被系统冻结,需要开启一个前台服务Foreground services,在前台服务中调用ActivityRecordsController方法创建允许后台运行的运动记录;
- 调用ActivityRecordsController的beginActivityRecord接口开始允许后台运行的运动记录,默认会申请允许应用后台运行时长10分钟;
// 请注意此处的this为Activity对象
ActivityRecordsController activityRecordsController = HuaweiHiHealth.getActivityRecordsController(this);
// 1.构造新运动记录开始时间
long startTime = Calendar.getInstance().getTimeInMillis();
// 2.构造ActivityRecord对象,设置运动记录开始时间
ActivityRecord activityRecord = new ActivityRecord.Builder()
.setId("MyBeginActivityRecordId")
.setName("BeginActivityRecord")
.setDesc("This is ActivityRecord begin test!")
.setActivityTypeId(HiHealthActivities.RUNNING)
.setStartTime(startTime, TimeUnit.MILLISECONDS)
.build();
// 3.构建应用运动记录运行中展示的页面, MyActivity需替换成自身的Activity类
ComponentName componentName = new ComponentName(this, MyActivity.class);
// 4.构建运动记录后台运行状态变化监听器
OnActivityRecordListener activityRecordListener = new OnActivityRecordListener() {
@Override
public void onStatusChange(int statusCode) {
Log.i("ActivityRecords", "onStatusChange statusCode:" + statusCode);
}
};
// 5.调用启动新运动记录API接口beginActivityRecord
Task<Void> task1 = activityRecordsController.beginActivityRecord(activityRecord, componentName, activityRecordListener);
// 6.添加启动ActivityRecord成功
task1.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.i("ActivityRecords", "MyActivityRecord begin success");
}
// 7.添加启动ActivityRecord失败
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
String errorCode = e.getMessage();
String errorMsg = HiHealthStatusCodes.getStatusCodeMessage(Integer.parseInt(errorCode));
Log.i("ActivityRecords", errorCode + ": " + errorMsg);
}
});
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 若用户运动时间较长,每临近10分钟(小于10分钟)需调用ActivityRecordsController的continueActivityRecord接口续申请后台保活10分钟;
// 请注意此处的this为Activity对象
ActivityRecordsController activityRecordsController = HuaweiHiHealth.getActivityRecordsController(this);
// 调用continueActivityRecord方法为指定运动记录续申请允许后台运行,入参为ActivityRecord的ID字符串
Task<Void> endTask = activityRecordsController.continueActivityRecord("MyBeginActivityRecordId");
endTask.addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Log.i("ActivityRecords", "continue backgroundActivityRecord was successful!");
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
Log.i("ActivityRecords", "continue backgroundActivityRecord error");
}
});
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 当用户运动结束时,调用ActivityRecordsController的endActivityRecord接口停止该运动记录,同时取消应用后台保活;
// 请注意此处的this为Activity对象
final ActivityRecordsController activityRecordsController = HuaweiHiHealth.getActivityRecordsController(this);
// 调用endActivityRecord接口停止运动记录,入参为ActivityRecord的ID字符串或者null
// 入参为ID字符串时,停止当前应用指定ID的运动记录
// 入参为null时,停止该应用当前所有的未停止运动记录
Task<List<ActivityRecord>> endTask = activityRecordsController.endActivityRecord("MyBeginActivityRecordId");
endTask.addOnSuccessListener(new OnSuccessListener<List<ActivityRecord>>() {
@Override
public void onSuccess(List<ActivityRecord> activityRecords) {
Log.i("ActivityRecords","MyActivityRecord End success");
// 返回停止成功的运动记录列表
if (activityRecords.size() > 0) {
for (ActivityRecord activityRecord : activityRecords) {
DateFormat dateFormat = DateFormat.getDateInstance();
DateFormat timeFormat = DateFormat.getTimeInstance();
Log.i("ActivityRecords", "Returned for ActivityRecord: " + activityRecord.getName() + "\n\tActivityRecord Identifier is "
+ activityRecord.getId() + "\n\tActivityRecord created by app is " + activityRecord.getPackageName()
+ "\n\tDescription: " + activityRecord.getDesc() + "\n\tStart: "
+ dateFormat.format(activityRecord.getStartTime(TimeUnit.MILLISECONDS)) + " "
+ timeFormat.format(activityRecord.getStartTime(TimeUnit.MILLISECONDS)) + "\n\tEnd: "
+ dateFormat.format(activityRecord.getEndTime(TimeUnit.MILLISECONDS)) + " "
+ timeFormat.format(activityRecord.getEndTime(TimeUnit.MILLISECONDS)) + "\n\tActivity:"
+ activityRecord.getActivityType());
}
} else {
// 没有停止成功返回null
Log.i("ActivityRecords","MyActivityRecord End response is null");
}
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(Exception e) {
String errorCode = e.getMessage();
String errorMsg = HiHealthStatusCodes.getStatusCodeMessage(Integer.parseInt(errorCode));
Log.i("ActivityRecords",errorCode + ": " + errorMsg);
}
});
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
需要注意的是,由于端侧后台保活API属于敏感权限,运动类应用接入时需进行人工审核,确保数据安全、流程合规才能上架。
了解更多详情>>
获取 开发指导文档
华为移动服务开源仓库地址: GitHub
关注我们,第一时间了解 HMS Core 最新技术资讯~
边栏推荐
- Navicat 15 for MySQL
- Visual Studio 2010 configuring and using qt5.6.3
- 国债与定期存款哪个更安全 两者之间有何区别
- R language uses the multinom function of NNET package to build an unordered multi classification logistic regression model, and uses regression coefficients and their standard errors to calculate the
- Notes to distributed theory
- Innovation and upgrading of supply chain system driven management mode in petrochemical industry and strengthening internal management of enterprises
- Classic model transformer
- Web worker poll request
- FFmpeg之禁止输出banner log(三十)
- 关注35岁的坎:畏惧是因为你没有匹配这个年纪该有的能力
猜你喜欢

一种跳板机的实现思路

A new 25K byte from the Department showed me what the ceiling is

看界面控件DevExpress WinForms如何创建一个虚拟键盘

SaaS application management platform solution in the education industry: help enterprises realize the integration of operation and management

【MySQL】表连接为什么比子查询快

Xinchuang operating system -- kylin kylin desktop operating system (project 10 security center)

openGauss内核:SQL解析过程分析

【高并发基础】MySQL 不同事务隔离级别下的并发隐患及解决方案

3. Caller 服务调用 - dapr

Analysis of PostgreSQL storage structure
随机推荐
Talking about open source - Linus and Jim talk about open source in China
关注35岁的坎:畏惧是因为你没有匹配这个年纪该有的能力
一个bug肝一周...忍不住提了issue
Visual Studio 2010 configuring and using qt5.6.3
A bug liver a week I can't help mentioning issue
Big God explains open source buff gain strategy live lecture
薅羊毛的机会了,点个“赚”即有机会赚取高额佣金
信创操作系统--麒麟Kylin桌面操作系统 (项目十 安全中心)
数组中的第K大元素[堆排 + 建堆的实际时间复杂度]
Fleet | "backstage exploration" issue 3: status management
Focus on the 35 year old Kan: fear is because you don't have the ability to match your age
among us私服搭建
今天睡眠质量记录80分
开源大咖说 - Linus 与 Jim 对话中国开源
NFT质押LP流动性挖矿系统开发详情
[recommendation system] esmm model of multi task learning (updating)
【LeetCode】13、罗马数字转整数
5 minutes to make a bouncing ball game
openGauss内核:SQL解析过程分析
Visual Studio 2010 编绎Qt5.6.3