在实际应用开发过程中,经常需要用到移动终端设备的位置信息,比如查看所在城市天气、出行打车、旅行导航以及观察运动轨迹等。关于位置定位,位置服务提供了两种定位方式,分别为GNSS定位和网络定位,如下表所示:
定位方式 | 说明 | 优点 |
|---|---|---|
GNSS定位 | 基于全球导航卫星系统,包含GPS、GLONASS、北斗、Galileo等,通过导航卫星、设备芯片提供的定位算法,来确定设备准确位置。 | 定位精准 |
网络定位 | 通过网络进行定位,包括WLAN、蓝牙定位、基站定位。 | 定位速度快 |
利用系统的位置定位能力,可以在多种开发场景中获得实时准确的位置信息。本文将介绍如下四种常见的定位场景,并给出其具体实现方案,帮助开发者更好地掌握位置定位的基本原理和开发流程。
开发者可以根据实际业务诉求,设置相应的定位策略获取设备的当前位置信息,不同定位策略对应表1 定位方式介绍中不同的定位方式。
实现原理
位置服务提供getCurrentLocation()接口来获取当前位置信息,该接口需要用户设置关键参数——定位请求信息。定位请求信息包含定位方式优先级、单次定位超时时间等,分为CurrentLocationRequest和SingleLocationRequest两种类型。两种类型对应的定位优先级分别为LocationRequestPriority和LocatingPriority。
开发步骤
let request: geoLocationManager.SingleLocationRequest = {
locatingPriority: 0x502,
locatingTimeoutMs: 10000
};geoLocationManager.getCurrentLocation(request).then((location: geoLocationManager.Location) => {
// ...
}).catch((err: BusinessError) => {
hilog.error(0x0000, TAG, `getCurrentLocationPosition failed, code: ${err.code}, message: ${err.message}`);
// ...
});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}`);
// ...
}
});
开发者可以根据实际用户活动场景或功耗场景,设置相应的定位策略持续获取设备的位置信息,不同定位策略对应表1 定位方式介绍中不同的定位方式。
实现原理
位置服务通过on('locationChange')接口订阅位置变化情况,实现持续获取设备位置信息的场景诉求。该订阅服务需要申请定位请求信息LocationRequest或者ContinuousLocationRequest,并在请求信息中设置定位场景类型和位置信息上报时间间隔。
开发步骤
let request: geoLocationManager.ContinuousLocationRequest = {
interval: 1,
locationScenario: 0x401
};geoLocationManager.on('locationChange', request, this.locationChange);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}`);
// ...
}
});try {
geoLocationManager.off('locationChange', this.locationChange);
} catch (err) {
hilog.error(0x0000, TAG, `offLocationChange failed, code: ${err.code}, message: ${err.message}`);
}

当用户将应用切至后台且依然需要获取设备的位置信息时,可以使用该方式进行后台定位。
实现原理
应用后台定位需要申请后台定位权限ohos.permission.LOCATION_IN_BACKGROUND和长时任务权限ohos.permission.KEEP_BACKGROUND_RUNNING。申请了相关权限后,开启任务模式为定位导航的长时任务,并在其回调接口中通过on('locationChange')订阅位置变化情况,在应用后台持续获取当前位置信息。
开发步骤
申请长时任务权限
{
"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}`);
// ...
}
}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}`);
}
}

当用户设备网络信号较弱或者对系统功耗比较敏感时,可以先获取系统缓存的最新位置,即最近一次的历史定位信息。
实现原理
位置服务通过getLastLocation()接口来获取系统缓存的最新位置信息。该接口参数列表为空,返回值为Location位置信息。
开发步骤
let location = geoLocationManager.getLastLocation();
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}`);
// ...
}
});
问题现象
在定位过程中,获取的定位结果不准确,或者将定位结果标记在地图上时出现偏差。
可能原因
解决措施
问题现象
无法使用定位功能获取位置信息。
可能原因
解决措施
问题现象
使用getCurrentLocation()接口获取当前定位信息后,再使用getLastLocation()接口获取缓存定位信息,两次获取的定位信息不一致。
可能原因
所有应用公用系统中的同一份缓存定位信息,有可能在两次接口调用之间有其他应用发起定位,刷新了系统中的缓存定位信息。
解决措施
对比获取定位信息的时间,根据时间判断缓存定位信息是否更新。