定位开发:单次_持续定位、省电策略、隐私合规写法
定位开发:单次/持续定位、省电策略、隐私合规写法
在鸿蒙应用里,定位是高频基础能力:外卖配送、出行打车、天气服务、内容本地化,都离不开位置信息。但很多开发者上手时只关心"怎么拿到经纬度",忽略了权限申请、功耗控制和隐私合规这三件事,最后上架审核被打回,或者用户反馈手机掉电快。本文基于最新鸿蒙 API,把单次定位、持续定位、省电策略和隐私合规的完整落地流程讲清楚,代码可以直接复制到项目里跑。
01 权限前置与隐私合规
定位属于敏感权限,必须先在 module.json5 里声明,再在代码中动态申请。很多人只加了一个 ACCESS_LOCATION,结果持续定位时后台直接被杀,或者上架时权限说明不清晰被驳回。定位相关的权限主要有三个,按业务需要选:
-
ohos.permission.APPROXIMATELY_LOCATION:模糊定位,精度约几公里,适合天气、城市级内容推荐
-
ohos.permission.LOCATION:精确定位,GPS 级精度,适合导航、配送类业务
-
ohos.permission.LOCATION_IN_BACKGROUND:后台定位,应用退到后台后还能持续获取位置
module.json5 里这样配置:
"requestPermissions": [
{
"name": "ohos.permission.LOCATION",
"reason": "$string:location_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.APPROXIMATELY_LOCATION",
"reason": "$string:approx_location_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
},
{
"name": "ohos.permission.LOCATION_IN_BACKGROUND",
"reason": "$string:bg_location_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
reason 字段必须写清楚为什么要这个权限,系统弹窗和应用市场审核都会展示。模糊定位和精确定位是两个独立权限,用户可以只授权模糊定位,代码里要做兼容处理。
代码里动态申请权限:
import { abilityAccessCtrl, common } from '@kit.AbilityKit';
import { bundleManager } from '@kit.BundleKit';
async function requestLocationPermissions(context: common.Context): Promise<boolean> {
const atManager = abilityAccessCtrl.createAtManager();
const bundleInfo = await bundleManager.getBundleInfo(context.applicationInfo.name,
bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION);
const tokenId = bundleInfo.appInfo.tokenId;
const status = await atManager.checkAccessToken(tokenId, 'ohos.permission.LOCATION');
if (status === abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) {
return true;
}
const permissions: string[] = ['ohos.permission.LOCATION', 'ohos.permission.APPROXIMATELY_LOCATION'];
const request = await atManager.requestPermissionsFromUser(context, permissions);
return request.authResults[0] === 0;
}
这里要注意,requestPermissionsFromUser 是异步弹窗,用户点完才返回结果。不要在页面初始化时直接调用定位接口,权限没拿到会直接抛异常。
02 单次定位:快速获取当前位置
单次定位适合"打开页面拿一次位置"的场景:首页加载附近门店、用户手动刷新位置、提交表单时附带当前坐标。不需要持续监听,拿到结果就可以结束。
鸿蒙定位能力由 @kit.LocationKit 提供,核心接口是 getCurrentLocation。
import { geoLocationManager } from '@kit.LocationKit';
async function getCurrentOnce(): Promise<geoLocationManager.Location> {
// 先判断系统定位开关是否打开
const isEnabled = await geoLocationManager.isLocationEnabled();
if (!isEnabled) {
throw new Error('系统定位开关未打开');
}
const request: geoLocationManager.CurrentLocationRequest = {
priority: geoLocationManager.LocationRequestPriority.PRIORITY_FAST,
scenario: geoLocationManager.LocationRequestScenario.UNSET,
maxAccuracy: 100,
timeoutMs: 10000
};
const location = await geoLocationManager.getCurrentLocation(request);
console.info('纬度', location.latitude, '经度', location.longitude);
console.info('定位精度', location.accuracy);
return location;
}
几个关键参数:
-
priority:PRIORITY_FAST 优先快速返回,PRIORITY_ACCURACY 优先高精度。普通业务用 FAST 就够了,导航类才需要 ACCURACY
-
maxAccuracy:期望精度,单位米。设置 100 表示允许百米级误差,系统会更快返回结果
-
timeoutMs:超时时间。设太短会拿不到结果,设太长用户等得久,一般 10 秒比较合理
单次定位不需要手动停止,系统拿到结果自动释放定位硬件。这也是它省电的原因——用完即走,不会持续占用 GPS。
03 持续定位:实时位置追踪
持续定位适合导航、运动轨迹、实时配送这类场景,需要连续不断地更新位置。实现方式是创建定位订阅,注册回调,不需要的时候主动取消订阅。
import { geoLocationManager } from '@kit.LocationKit';
let subscriber: geoLocationManager.GeofenceSubscribe | null = null;
async function startContinuousLocation() {
const request: geoLocationManager.LocationRequest = {
priority: geoLocationManager.LocationRequestPriority.PRIORITY_ACCURACY,
interval: 5000,
withdrawCacheAccuracy: 50,
minDistance: 10
};
// 订阅位置变化
subscriber = await geoLocationManager.createGeofenceSubscribe();
const callback: geoLocationManager.LocationChangeCallback = (location: geoLocationManager.Location) => {
console.info('实时位置', location.latitude, location.longitude);
// 在这里更新 UI、上报服务器
};
await subscriber.on('locationChange', request, callback);
}
// 页面离开、任务结束时必须取消订阅
function stopContinuousLocation() {
if (subscriber) {
subscriber.off('locationChange');
subscriber = null;
}
}
持续定位最容易踩的坑就是忘了取消订阅。页面都退出了,GPS 还在持续定位,电池掉得飞快,用户第二天就卸载了。
正确的做法是把 start 和 stop 绑定到页面生命周期:onPageShow 开始定位,onPageHide 停止定位。如果是后台持续定位(比如外卖配送),要配合后台任务和 LOCATION_IN_BACKGROUND 权限一起用。
04 省电策略:降低定位功耗
定位是耗电大户,尤其是持续开启 GPS 高精度定位。很多开发者为了"定位准",把精度拉满、间隔设成 1 秒,结果手机半小时掉电 20%。实际上,大部分业务不需要这么高精度和高频率。合理的省电策略可以从几个维度入手:
**第一,按场景选定位优先级。**普通列表附近推荐,用 PRIORITY_LOW_POWER,基于网络基站和 WiFi 定位,功耗低,精度几百米就够了。只有导航、打卡这类对精度有硬要求的场景,才切到 PRIORITY_ACCURACY。
**第二,调整定位间隔和最小距离。**interval 设为 5000 毫秒(5 秒),minDistance 设为 10 米——也就是位置变化超过 10 米才触发回调。用户站着不动的时候,不会频繁触发 GPS 唤醒,能省不少电。导航场景可以把间隔缩到 1-2 秒,但非必要不要低于 1 秒。
const lowPowerRequest: geoLocationManager.LocationRequest = {
priority: geoLocationManager.LocationRequestPriority.PRIORITY_LOW_POWER,
interval: 30000,
minDistance: 100
};
**第三,前后台分离策略。**应用在前台时,精度高一点、间隔短一点;退到后台,立刻降低频率和精度。用户切回前台时再恢复。不要不管前后台都用同一套参数。
**第四,页面不可见时暂停定位。**用户切到别的页面、按了 Home 键,当前页面的定位就该停掉。不要因为"万一还要用"就一直挂着,系统定位硬件被持续占用,功耗是线性增长的。
05 落地注意事项
**系统定位开关要判断。**很多用户会手动关掉系统定位开关,这时候无论怎么申请权限都拿不到位置。调用定位接口前,先调 isLocationEnabled 判断一下,如果没开,引导用户去系统设置打开,而不是直接报错。
**模糊定位要兼容。**用户可能只授权了模糊定位,这时候拿到的精度会比较低。业务代码里不要假设精度一定是 GPS 级,要根据 accuracy 字段判断当前定位质量,太低时给用户提示。
**定位回调里不要做重操作。**locationChange 回调频率很高,不要在里面直接做复杂的网络请求、数据库写入。先把位置数据存下来,用节流的方式批量上报,避免频繁 IO 拖慢主线程。
**隐私弹窗要提前说明用途。**权限申请弹窗弹出前,最好有一段引导文案告诉用户"我们为什么需要定位"。直接弹系统权限窗,用户很容易点拒绝,提前解释清楚授权率会高很多。
小结
定位开发的核心不是调 API 拿坐标,而是把权限、功耗、合规三件事配合好。单次定位用完即走,持续定位记得取消订阅;精度和频率按业务场景调,不要上来就拉满;权限申请提前说明用途,模糊定位做兼容。把这套逻辑封装成统一的定位工具类,项目里直接复用,能避免大部分定位相关的功耗投诉和审核驳回。
更多推荐




所有评论(0)