本篇 Codelab 使用 ArkTS 语言实现计步器应用,应用主要包括计步传感器、定位服务和后台任务功能:
1. 通过订阅计步器传感器获取计步器数据,处理后显示。
2. 通过订阅位置服务获取位置数据,处理后显示。
3. 通过服务开发实现后台任务功能。
计步传感器 :订阅计步器传感器数据,系统返回相关数据。
后台任务管理 :应用中存在用户能够直观感受到的且需要一直在后台运行的业务时(如,后台播放音乐),可以使用长时任务机制。
位置服务 :位置服务提供 GNSS 定位、网络定位、地理编码、逆地理编码、国家码和地理围栏等基本功能。
本篇 Codelab 用到了计步传感器、后台任务及位置服务功能,需要在配置文件 module.json5 里添加权限:
● ohos.permission.ACTIVITY_MOTION
● ohos.permission.KEEP_BACKGROUND_RUNNING
● ohos.permission.APPROXIMATELY_LOCATION
● ohos.permission.LOCATION
● ohos.permission.LOCATION_IN_BACKGROUND
源码下载

环境搭建
我们首先需要完成 HarmonyOS 开发环境搭建,可参照如下步骤进行。
DevEco Studio 版本:DevEco Studio 3.1 Release。
HarmonyOS SDK 版本:API version 9。
设备类型:华为手机或运行在 DevEco Studio 上的华为手机设备模拟器。
HarmonyOS 系统:3.1.0 Developer Release。
安装 DevEco Studio,详情请参考 下载和安装软件 。
设置 DevEco Studio 开发环境,DevEco Studio 开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:如果可以直接访问 Internet,只需进行 下载HarmonyOS SDK 操作。
如果网络不能直接访问 Internet,需要通过代理服务器才可以访问,请参考 配置开发环境 。
开发者可以参考以下链接,完成设备调试的相关配置:
使用真机进行调试

本篇 Codelab 只对核心代码进行讲解,对于完整代码,我们会在源码下载或 gitee 中提供。
├──entry/src/main/ets
// 代码区
│ ├──common
│ │ ├──constants
│ │ │ └──
CommonConstants.
ets
// 公共常量
│ │ └──utils
// 日志类
│ │ ├──
BackgroundUtil.
ets
// 后台任务工具类
│ │ ├──
GlobalContext.
ets
// 首|选项工具类
│ │ ├──
LocationUtil.
ets
// 位置服务工具类
│ │ ├──
Logger.
ets
// 日志工具类
│ │ ├──
NumberUtil.
ets
// 数字处理工具类
│ │ └──
StepsUtil.
ets
// 计步器工具类
│ ├──entryability
│ │ └──
EntryAbility.
ets
// 程序入口类
│ ├──pages
│ │ └──
HomePage.
ets
// 应用首页
│ └──view
│ ├──
CompletionStatus.
ets
// 目标设置页
│ ├──
CurrentSituation.
ets
// 计步信息页
│ └──
InputDialog.
ets
// 自定义弹窗
└──entry/src/main/resources
// 资源文件夹
计步器页面主要由 Stack 堆叠容器组件、Component 自定义组件和 CustomDialog 自定义弹窗组件完成页面布局,效果如图所示:

// HomePage.etsbuild() {Stack({ alignContent: Alignment.TopStart }) {CompletionStatus({progressValue: $progressValue})CurrentSituation({currentSteps: this.currentSteps,startPosition: this.startPosition,currentLocation: this.currentLocation})Row() {Button(this.isStart ? $r('app.string.stop') : $r('app.string.start'))...}...}...}
应用启动后申请计步传感器权限,获取权限后订阅计步器传感器。通过订阅获取到计步传感器数据,解析处理后在页面显示。效果如图所示:

// HomePage.etsrequestPermissions(): void {let atManager = abilityAccessCtrl.createAtManager();try {atManager.requestPermissionsFromUser(this.context, CommonConstants.REQUEST_PERMISSIONS).then((data) => {if (data.authResults[0] !== 0 || data.authResults[1] !== 0) {return;}const that = this;try {sensor.on(sensor.SensorId.PEDOMETER, (data) => {try {if (that.isStart) {if (StepsUtil.checkStrIsEmpty(that.oldSteps)) {that.oldSteps = data.steps.toString();StepsUtil.putStorageValue(CommonConstants.OLD_STEPS, that.oldSteps);} else {that.currentSteps = (data.steps - NumberUtil._parseInt(that.oldSteps, 10)).toString();}} else {that.currentSteps = data.steps.toString();}if (StepsUtil.checkStrIsEmpty(that.stepGoal) || !that.isStart) {return;}StepsUtil.putStorageValue(CommonConstants.CURRENT_STEPS, that.currentSteps);that.progressValue = StepsUtil.getProgressValue(NumberUtil._parseInt(that.stepGoal, 10),NumberUtil._parseInt(that.currentSteps, 10));StepsUtil.putStorageValue(CommonConstants.PROGRESS_VALUE_TAG, String(that.progressValue));} catch (err) {Logger.error(TAG, 'Sensor on err' + JSON.stringify(err));}}, { interval: CommonConstants.SENSOR_INTERVAL });...}
应用启动后申请位置服务权限,获取权限后启动服务,启动服务后订阅位置服务。通过订阅获取到位置服务数据,解析处理后在页面显示。效果如图所示:

// HomePage.etsrequestPermissions(): void {...LocationUtil.geolocationOn((location: geoLocationManager.Location) => {if (this.latitude === location.latitude && this.longitude === location.longitude) {return;}this.latitude = location.latitude;this.longitude = location.longitude;let reverseGeocodeRequest: geoLocationManager.ReverseGeoCodeRequest = {'latitude': this.latitude,'longitude': this.longitude};geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest).then(data => {if (data[0].placeName) {this.currentLocation = data[0].placeName;}}).catch((err: Error) => {Logger.error(TAG, 'GetAddressesFromLocation err ' + JSON.stringify(err));});});...}
将位置服务相关的函数封装到工具类中。
// LocationUtil.ets
class
LocationUtil {
geolocationOn(
locationChange:
(
location: geoLocationManager.Location) =>
void):
void {
let
requestInfo: geoLocationManager.
LocationRequest = {
'priority':
0x203,
'scenario':
0x300,
'timeInterval':
0,
'distanceInterval':
0,
'maxAccuracy':
0
}
try {
geoLocationManager.
on(
'locationChange', requestInfo, locationChange);
}
catch (err) {
console.
error(
"locationChange error:" +
JSON.
stringify(err));
}
}
geolocationOff():
void {
geoLocationManager.
off(
'locationChange');
}
}
点击开始按钮开启后台任务,通过后台任务管理方法配置申请的后台模式等参数启动后台任务。
// HomePage.etsbuild() {Stack({ alignContent: Alignment.TopStart }) {...Row() {Button(this.isStart ? $r('app.string.stop') : $r('app.string.start'))....onClick(() => {if (this.isStart) {...BackgroundUtil.stopContinuousTask(this.context);} else {if (this.stepGoal === '' || this.currentLocation === '') {promptAction.showToast({ message: CommonConstants.WAIT });} else {...BackgroundUtil.startContinuousTask(this.context);}}StepsUtil.putStorageValue(CommonConstants.IS_START, String(this.isStart));})}...}// BackgroundUtil.etsexport class BackgroundUtil {public static startContinuousTask(context: common.UIAbilityContext): void {let wantAgentInfo: wantAgent.WantAgentInfo = {wants: [{bundleName: context.abilityInfo.bundleName,abilityName: context.abilityInfo.name}],operationType: wantAgent.OperationType.START_ABILITY,requestCode: 0,wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]};wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => {try {backgroundTaskManager.startBackgroundRunning(context,backgroundTaskManager.BackgroundMode.LOCATION, wantAgentObj).then(() => {Logger.info(TAG, 'startBackgroundRunning succeeded');}).catch((err: Error) => {Logger.error(TAG, `startBackgroundRunning failed Cause: ${JSON.stringify(err)}`);});} catch (error) {Logger.error(TAG, `stopBackgroundRunning failed. error: ${JSON.stringify(error)} `);}});}public static stopContinuousTask(context: common.UIAbilityContext): void {try {backgroundTaskManager.stopBackgroundRunning(context).then(() => {Logger.info(TAG, 'stopBackgroundRunning succeeded');}).catch((err: Error) => {Logger.error(TAG, `stopBackgroundRunning failed Cause: ${JSON.stringify(err)}`);});} catch (error) {Logger.error(TAG, `stopBackgroundRunning failed. error: ${JSON.stringify(error)} `);}}}
您已经完成了本次 Codelab 的学习,并了解到以下知识点:
1. 计步器传感器的功能实现。
2. 位置服务的功能实现。
3. 后台任务的功能实现。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70047792/viewspace-2995652/ ,如需转载,请注明出处,否则将追究法律责任。