HarmonyOS鸿蒙Next中开发一款骑行记录 App,如何确保 GPS 在锁屏后仍能以 1Hz 频率持续采集位置?
HarmonyOS鸿蒙Next中开发一款骑行记录 App,如何确保 GPS 在锁屏后仍能以 1Hz 频率持续采集位置? 应用需在用户骑行过程中后台持续记录轨迹点,采样间隔为 1 秒。测试发现,当屏幕关闭或切换至其他 App 后,定位回调频率大幅下降(有时长达 30 秒才触发一次),导致轨迹不连续?
在鸿蒙(HarmonyOS)系统中开发骑行记录类 App,要实现 锁屏或后台状态下以 1Hz(每秒一次)持续采集 GPS 位置,确实面临系统对后台资源的严格管控。这是为了平衡用户体验与设备功耗/安全。但通过合理申请权限、使用前台服务(Foreground Service)和高精度定位策略,可以有效解决该问题。
核心解决方案:前台服务 + 高优先级定位 + 后台运行权限
一、申请必要权限(module.json5)
确保在配置文件中声明以下权限:
二、启动 前台服务(Foreground Service)
鸿蒙要求:需要长时间后台运行的任务必须以“前台服务”形式存在,并显示持续通知(不可清除),否则系统会在几分钟后冻结进程。
1. 定义服务(LocationService.ets)
import { CommonEventSupport } from '@kit.CommonEventManagerKit';
import location from '@kit.LocationKit';
import foregroundServiceManager from '@kit.AbilityKit';
@Entry
export default class LocationService extends ServiceExtensionAbility {
private locationId: number = -1;
onStart(want) {
// 1. 启动前台通知
this.startForeground({
notificationId: 1001,
notification: {
contentTitle: '骑行记录中',
contentText: '正在后台记录轨迹...',
contentType: 0 // NOTIFICATION_CONTENT_BASIC_TEXT
}
});
// 2. 请求高精度定位
this.startLocationUpdates();
}
startLocationUpdates() {
let request = {
scenario: location.Scenario.SPORTS, // 运动场景,高频率
timeInterval: 1000, // 1秒
distanceInterval: 0, // 不依赖距离
priority: 100 // 高优先级(可选)
};
try {
this.locationId = location.on('locationChange', request, (location) => {
// 回调:每秒触发一次(理想情况)
console.info(`[Location] Lat: ${location.latitude}, Lng: ${location.longitude}`);
// 将位置存入数据库或发送到主 UI 页面
CommonEventSupport.publishCommonEvent({
eventId: 'location.update',
parameters: { lat: location.latitude, lng: location.longitude, time: location.time }
});
});
} catch (error) {
console.error('[Location] Start failed:', error);
}
}
onStop() {
if (this.locationId !== -1) {
location.off('locationChange', this.locationId);
}
this.stopForeground(true); // 移除通知
}
}
2. 在 module.json5 中注册服务
{
"extensionAbilities": [
{
"name": "LocationService",
"srcEntry": "./ets/location/LocationService.ets",
"type": "service",
"exported": false,
"metadata": [
{
"name": "ohos.extension.service.foreground",
"resource": "$profile:foreground_service_config"
}
]
}
]
}
并在 resources/base/profile/ 下创建 foreground_service_config.json:
{
"foregroundServiceType": "location"
}
三、申请 后台运行白名单(用户手动授权)
即使代码正确,HarmonyOS 默认会限制后台活动。你需要引导用户手动开启:
-
弹窗提示用户:
// 在开始记录前检查 import backgroundTaskManager from '@kit.BackgroundTaskKit'; backgroundTaskManager.canUseBackgroundResources().then(canUse => { if (!canUse) { AlertDialog.show({ title: '需要后台权限', message: '请允许本应用在后台运行,否则锁屏后将无法记录轨迹。', confirmLabel: '去设置', onConfirm: () => { backgroundTaskManager.requestBackgroundPermission(); } }); } }); -
用户需在 设置 > 应用 > 你的App > 电池 > 允许后台活动 中开启。
更多关于HarmonyOS鸿蒙Next中开发一款骑行记录 App,如何确保 GPS 在锁屏后仍能以 1Hz 频率持续采集位置?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
开发者您好,需要您开启长时任务,具体步骤如下:
应用后台定位
当用户将应用切至后台且依然需要获取设备的位置信息时,可以使用该方式进行后台定位。
实现原理
应用后台定位需要申请后台定位权限ohos.permission.LOCATION_IN_BACKGROUND和长时任务权限ohos.permission.KEEP_BACKGROUND_RUNNING。申请了相关权限后,开启任务模式为定位导航的长时任务,并在其回调接口中通过on(‘locationChange’)订阅位置变化情况,在应用后台持续获取当前位置信息。
开发步骤
-
申请后台定位权限,具体内容可参考申请位置权限开发指导。
-
在模块的module.json5文件中,申请长时任务权限,并将长时任务模式设置为定位导航类型。 申请长时任务权限
{ "name": "ohos.permission.KEEP_BACKGROUND_RUNNING", "reason": "$string:running_background", "usedScene": { "abilities": [ "EntryAbility" ], "when": "always" } },设置长时任务模式为定位导航类型
"abilities": [ { // ... "backgroundModes": [ "location" ], // ... } ], -
详细参考开启任务模式为定位导航类型的长时任务,在其回调接口中开启位置变化订阅,并发起定位请求,在应用后台持续获取当前位置信息。
开启长时任务
startContinuousTask(): void { let context = this.getUIContext().getHostContext() as common.UIAbilityContext; if (!context) { return; } let wantAgentInfo: wantAgent.WantAgentInfo = { wants: [ { bundleName: context.abilityInfo.bundleName, abilityName: context.abilityInfo.name } ], operationType: wantAgent.OperationType.START_ABILITY, requestCode: 1, wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG] }; wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => { backgroundTaskManager.startBackgroundRunning(context, backgroundTaskManager.BackgroundMode.LOCATION, wantAgentObj).then(() => { this.onLocationChange(); hilog.info(0x0000, TAG, 'startBackgroundRunning succeeded'); }).catch((err: BusinessError) => { hilog.error(0x0000, TAG, `startBackgroundRunning failed, cause: ${JSON.stringify(err)}`); }); }).catch((err: BusinessError) => { hilog.error(0x0000, TAG, `getWantAgent failed, cause: ${JSON.stringify(err)}`); }); }订阅位置变化情况
onLocationChange(): void { let request: geoLocationManager.ContinuousLocationRequest = { interval: 1, locationScenario: 0x401 }; try { geoLocationManager.on('locationChange', request, this.locationChange); // ... } catch (err) { hilog.error(0x0000, TAG, `onLocationChange failed, code: ${err.code}, message: ${err.message}`); // ... } } -
在位置变化的回调中,调用getAddressesFromLocation()接口进行逆地理编码转化,将坐标信息转换为对应的地理位置描述。
geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest, async (err, data) => { if (data) { this.address = data[0]?.placeName || ''; // ... } else { hilog.error(0x0000, TAG, `getAddressesFromLocation failed, code: ${err.code}, message: ${err.message}`); // ... } }); -
当不需要在应用后台获取位置信息时,及时关闭长时任务和位置变化订阅,并删除对应的定位请求,减少设备功耗。
关闭长时任务
stopContinuousTask(): void { let context = this.getUIContext().getHostContext() as common.UIAbilityContext; if (!context) { return; } backgroundTaskManager.stopBackgroundRunning(context).then(() => { if (!this.isOnLocationChange) { this.offLocationChange(); } hilog.info(0x0000, TAG, 'stopBackgroundRunning succeeded'); }).catch((err: BusinessError) => { hilog.error(0x0000, TAG, `stopBackgroundRunning failed, cause: ${JSON.stringify(err)}`); }); }关闭位置变化订阅
offLocationChange(): void { try { geoLocationManager.off('locationChange', this.locationChange); } catch (err) { hilog.error(0x0000, TAG, `offLocationChange failed, code: ${err.code}, message: ${err.message}`); } }
详细demo请参考:基于位置服务获取设备定位信息
持续定位。多用于导航、运动轨迹、出行等场景。
首先要实例化ContinuousLocationRequest对象,用于告知系统该向应用提供何种类型的位置服务,以及位置结果上报的频率。
- 设置locationScenario: 建议locationScenario参数优先根据应用的使用场景进行设置,该参数枚举值定义参见UserActivityScenario,例如地图在导航时使用NAVIGATION参数,可以持续在室内和室外场景获取位置用于导航。
- 设置interval: **表示上报位置信息的时间间隔,单位是秒,默认值为1秒。**如果对位置上报时间间隔无特殊要求,可以不填写该字段。
以地图导航场景为例,调用方式如下:
import { geoLocationManager } from '@kit.LocationKit';
let request: geoLocationManager.ContinuousLocationRequest= {
'interval': 1,
'locationScenario': geoLocationManager.UserActivityScenario.NAVIGATION
}
let locationCallback = (location:geoLocationManager.Location):void => {
console.log('locationCallback: data: ' + JSON.stringify(location));
};
try {
geoLocationManager.on('locationChange', request, locationCallback);
} catch (err) {
console.error("errCode:" + JSON.stringify(err));
}
更多详细信息详见开发文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/location-guidelines
申请定位权限,然后持续上报试试
我来学习的
找HarmonyOS工作还需要会Flutter的哦,有需要Flutter教程的可以学学大地老师的教程,很不错,B站免费学的哦:https://www.bilibili.com/video/BV1S4411E7LY/?p=17
申请后台定位权限
在HarmonyOS Next中,使用持续任务(Continuous Task)机制。通过申请位置权限和后台持续运行权限,在ServiceAbility中创建位置服务实例并调用enableLocationChange方法,设置interval参数为1000毫秒。同时,在config.json文件中正确配置backgroundModes为location。系统将允许应用在锁屏后维持GPS采集。
在HarmonyOS Next中,要实现锁屏后持续高频(如1Hz)GPS采集,关键在于正确使用后台任务管理和持续定位能力。核心步骤如下:
-
申请必要权限:在
module.json5中声明ohos.permission.LOCATION和ohos.permission.LOCATION_IN_BACKGROUND(后台定位权限),并确保应用获得用户授权。 -
使用持续定位接口:通过
geoLocationManager请求位置更新时,需明确设置定位场景为NAVIGATION(导航场景),该场景下系统会优先保证定位频率和精度。关键配置示例:let requestInfo: location.LocationRequest = { scenario: location.LocationScenario.NAVIGATION, timeInterval: 1, // 时间间隔(秒) distanceInterval: 0, // 距离间隔(米),设为0表示按时间间隔优先 maxAccuracy: 10 // 精度要求(米) }; -
创建并持有后台任务:使用
backgroundTaskManager申请一个持续任务(如location类型),防止应用进程被挂起。需在module.json5中声明ohos.permission.KEEP_BACKGROUND_RUNNING权限。 -
使用Service Ability进行后台数据收集:将定位回调逻辑放在Service Ability中运行,而非UIAbility。Service Ability在后台具有更稳定的生命周期,适合执行持续采集任务。注意在
module.json5中正确配置backgroundModes为location。 -
优化功耗与系统策略应对:高频定位会显著增加功耗。建议:
- 仅在用户开始骑行时启动上述后台采集流程,结束时及时释放。
- 合理设置
maxAccuracy,过高的精度要求会增加系统调度难度和耗电。 - 考虑使用
requestSuspendDelay申请延迟挂起,并在收到挂起通知时尝试保存必要状态。
-
注意系统省电策略:即使采用上述方法,在系统电量极低或特定省电模式下,系统仍可能限制后台活动。应向用户说明该情况属于正常系统行为。
通过组合使用后台任务、Service Ability以及正确的定位场景配置,可以最大程度满足锁屏后1Hz采集的需求。实际效果仍会受到具体设备硬件和系统实时资源调度的影响。

