概述

在实际应用开发过程中,经常需要用到移动终端设备的位置信息,比如查看所在城市天气、出行打车、旅行导航以及观察运动轨迹等。关于位置定位,位置服务提供了两种定位方式,分别为GNSS定位和网络定位,如下表所示:

表1 定位方式介绍

定位方式 说明 优点
GNSS定位 基于全球导航卫星系统,包含GPS、GLONASS、北斗、Galileo等,通过导航卫星、设备芯片提供的定位算法,来确定设备准确位置。 定位精准
网络定位 通过网络进行定位,包括WLAN、蓝牙定位、基站定位。 定位速度快

利用系统的位置定位能力,可以在多种开发场景中获得实时准确的位置信息。本文将介绍如下四种常见的定位场景,并给出其具体实现方案,帮助开发者更好地掌握位置定位的基本原理和开发流程。

  • 当前位置定位:获取设备的当前位置信息。开发者可以根据实际需求将其应用于多种业务场景,如外卖定位、打车定位等。
  • 实时位置定位:持续获取设备的实时位置信息。开发者可以将此能力应用于需要实时定位的场景,如步行导航、驾车出行等。
  • 应用后台定位:将应用切换到后台仍然可以持续获取位置信息。该能力可以用于实现后台应用实时记录运动轨迹等业务场景。
  • 历史定位获取:获取系统缓存的最新位置,即最近一次的历史定位信息。该能力可以用于在设备网络信号较弱或对系统功耗比较敏感的场景下获取位置信息。

当前位置定位

开发者可以根据实际业务诉求,设置相应的定位策略获取设备的当前位置信息,不同定位策略对应表1 定位方式介绍中不同的定位方式。

实现原理

位置服务提供getCurrentLocation()接口来获取当前位置信息,该接口需要用户设置关键参数——定位请求信息。定位请求信息包含定位方式优先级、单次定位超时时间等,分为CurrentLocationRequest和SingleLocationRequest两种类型。两种类型对应的定位优先级分别为LocationRequestPriority和LocatingPriority。

开发步骤

  1. 申请定位权限,具体内容可参考申请位置权限开发指导。

  2. 实例化位置信息请求对象,确认当前定位策略。以实例化SingleLocationRequest对象为例,将其定位方式优先级设置为快速获取位置优先,定位超时时间设置为10秒,具体代码如下:

    let request: geoLocationManager.SingleLocationRequest = {
      locatingPriority: 0x502,
      locatingTimeoutMs: 10000
    };
    
  3. 根据定位策略,调用getCurrentLocation()接口获取当前位置信息。

    geoLocationManager.getCurrentLocation(request).then((location: geoLocationManager.Location) => {
      // ...
    }).catch((err: BusinessError) => {
      hilog.error(0x0000, TAG, `getCurrentLocationPosition failed, code: ${err.code}, message: ${err.message}`);
      // ...
    });
    
  4. 调用

    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}`);
        // ...
      }
    });
    
  5. 运行效果如下图所示

    图1 获取当前位置信息效果展示

在这里插入图片描述

实时位置定位

开发者可以根据实际用户活动场景或功耗场景,设置相应的定位策略持续获取设备的位置信息,不同定位策略对应表1 定位方式介绍中不同的定位方式。

实现原理

位置服务通过on(‘locationChange’)接口订阅位置变化情况,实现持续获取设备位置信息的场景诉求。该订阅服务需要申请定位请求信息LocationRequest或者ContinuousLocationRequest,并在请求信息中设置定位场景类型和位置信息上报时间间隔。

开发步骤

  1. 申请定位权限,具体内容可参考申请位置权限开发指导。

  2. 实例化位置信息请求对象,确认持续定位策略。以实例化ContinuousLocationRequest为例,将定位场景类型设置为导航场景,位置信息上报时间间隔设置为1秒,具体代码如下:

    let request: geoLocationManager.ContinuousLocationRequest = {
      interval: 1,
      locationScenario: 0x401
    };
    
  3. 根据定位策略,调用on(‘locationChange’)开启位置变化订阅,并发起定位请求,持续获取当前位置信息。

    geoLocationManager.on('locationChange', request, this.locationChange);
    
  4. 在on(‘locationChange’)的回调函数中,调用

    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}`);
        // ...
      }
    });
    
  5. 在不需要获取位置信息时,及时关闭位置变化订阅,并删除对应的定位请求,减少设备功耗。

    try {
      geoLocationManager.off('locationChange', this.locationChange);
    } catch (err) {
      hilog.error(0x0000, TAG, `offLocationChange failed, code: ${err.code}, message: ${err.message}`);
    }
    
  6. 运行效果如下图所示

    图2 持续获取实时位置信息效果展示
    在这里插入图片描述

    在这里插入图片描述

应用后台定位

当用户将应用切至后台且依然需要获取设备的位置信息时,可以使用该方式进行后台定位。

实现原理

应用后台定位需要申请后台定位权限ohos.permission.LOCATION_IN_BACKGROUND和长时任务权限ohos.permission.KEEP_BACKGROUND_RUNNING。申请了相关权限后,开启任务模式为定位导航的长时任务,并在其回调接口中通过on(‘locationChange’)订阅位置变化情况,在应用后台持续获取当前位置信息。

开发步骤

  1. 申请后台定位权限,具体内容可参考申请位置权限开发指导。

  2. 在模块的module.json5文件中,申请长时任务权限,并将长时任务模式设置为定位导航类型。

    申请长时任务权限

    {
      "name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
      "reason": "$string:running_background",
      "usedScene": {
        "abilities": [
          "EntryAbility"
        ],
        "when": "always"
      }
    },
    

    设置长时任务模式为定位导航类型

    "abilities": [
      {
        // ...
        "backgroundModes": [
          "location"
        ],
        // ...
      }
    ],
    
  3. 开启任务模式为定位导航类型的长时任务,在其回调接口中开启位置变化订阅,并发起定位请求,在应用后台持续获取当前位置信息。

    开启长时任务

    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}`);
        // ...
      }
    }
    
  4. 在位置变化的回调中,调用

    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}`);
        // ...
      }
    });
    
  5. 当不需要在应用后台获取位置信息时,及时关闭长时任务和位置变化订阅,并删除对应的定位请求,减少设备功耗。

    关闭长时任务

    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}`);
      }
    }
    
  6. 运行效果如下图所示

图3 在应用后台持续获取位置信息效果展示
在这里插入图片描述

在这里插入图片描述

历史定位获取

当用户设备网络信号较弱或者对系统功耗比较敏感时,可以先获取系统缓存的最新位置,即最近一次的历史定位信息。

实现原理

位置服务通过getLastLocation()接口来获取系统缓存的最新位置信息。该接口参数列表为空,返回值为Location位置信息。

开发步骤

  1. 申请定位权限,具体内容可参考申请位置权限开发指导。

  2. 调用getLastLocation()接口获取系统缓存的最新位置信息。

    let location = geoLocationManager.getLastLocation();
    
  3. 调用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}`);
        // ...
      }
    });
    
  4. 运行效果如下图所示

    图4 获取缓存位置信息效果展示
    在这里插入图片描述

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐