鸿蒙定位开发服务

发布于:2025-04-04 ⋅ 阅读:(17) ⋅ 点赞:(0)

引言

        鸿蒙操作系统(HarmonyOS)作为面向万物互联时代的分布式操作系统,其定位服务(Location Kit)为开发者提供了多场景、高精度的位置能力支持。本文将从技术原理、开发流程到实战案例,全面解析鸿蒙定位服务的开发要点,助力开发者快速上手。

关于定位方式;

关于位置定位,位置服务官方提供了两种

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

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

开发前的配置:

1.申请证书服务

在AGC平台申请到真机签名证书,先创建项目

在证书,APP ID和Profile中下载到后缀名.csr的证书

在Profile中拿到后缀名.p7b的证书

在项目的API管理中要开启三个服务

在Deveco Stuido里申请私钥和证书请求

拿到四个证书,配置到项目中

当前位置定位:

  1. 使用getCurrentLocation()获得当前位置信息

           a.需要设置关键参数(定位请求信息:定位方式优先级,单次定位超时时间)

步骤;

  1. 申请权限
  2. 实例化位置信息请求对象,确认当前定位策略
  3. 调用getCurrentLocation()接口获取当前位置信息。
  4. 调用getAddressesFromLocation()接口进行逆地理编码转化,将位置坐标信息转换为对应的地理位置
1.基础信息配置,申请权限
"requestPermissions": [
      //允许应用获取设备位置信息
      {
        "name": "ohos.permission.LOCATION",
        "reason": "$string:location_permission",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "inuse"
        }
      }
    ]

创建一个常量工具类

export class CommonConstants {
  /**
   * 定位超时时间(毫秒)
   */
  static LOCATING_TIMEOUT_MS: number = 10000;

  /**
   * 定位优先级
   */
  static PRIORITY_LOCATING_SPEED: number = 0x502;

  /**
   * 定位场景
   */
  static NAVIGATION: number = 0x401;

  /**
   * 定位开关关闭
   */
  static LOCATION_SWITCH_OFF: number = 3301100;

  /**
   * 定位失败
   */
  static LOCATION_FAILED: number = 3301200;

  /**
   * 反向地理编码失败
   */
  static REVERSE_GEOCODING_FAILED: number = 3301300;

  /**
   * Wi-Fi 和蓝牙关闭
   */
  static WIFI_BLUETOOTH_OFF: number = 3301800;

  /**
   * 信息窗口标题
   */
  static MARKER_TITLE: string = getContext(this).resourceManager.getStringSync($r('app.string.geocoded_location'));
}

配置地图数据类型

// 地图数据类型
export interface LocationInter {
  latitude: number,  // 纬度,表示地理位置的南北方向
  longitude: number  // 经度,表示地理位置的东西方向
}
2.实例化位置信息
getLocationPosition(): void {
    // 定义单次定位请求的配置
    let request: geoLocationManager.SingleLocationRequest = {
      // 定位优先级
      locatingPriority: CommonConstants.PRIORITY_LOCATING_SPEED,
      // 单次定位超时时间
      locatingTimeoutMs: CommonConstants.LOCATING_TIMEOUT_MS
    };
    
  }
3.调用getCurrentLocation()接口获取当前位置信息。
getLocationPosition(): void {
    // 定义单次定位请求的配置
    let request: geoLocationManager.SingleLocationRequest = {
      // 定位优先级
      locatingPriority: CommonConstants.PRIORITY_LOCATING_SPEED,
      // 单次定位超时时间
      locatingTimeoutMs: CommonConstants.LOCATING_TIMEOUT_MS
    };
    // 调用地理位置管理器的getCurrentLocation方法获取当前位置信息
    geoLocationManager.getCurrentLocation(request).then((location: geoLocationManager.Location) => {
      // 若获取成功,调用getAddress方法进行地址解析
      this.getAddress({
        latitude: location.latitude,
        longitude: location.longitude
      })
    }).catch((err: BusinessError) => {
      // 若获取失败,记录错误日志并显示定位失败提示
      hilog.error(0x0000, TAG, `getCurrentLocationPosition failed, code: ${err.code}, message: ${err.message}`);
      this.locationFailedAlert(err.code);
    });
  }
4.调用getAddressesFromLocation()接口进行逆地理编码转化
geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest, async (err, data) => {
        if (data) {
          // 若获取地址信息成功,更新地址信息和标记的信息窗口
          this.address = data[0]?.placeName || '';
          this.marker?.setInfoWindowVisible(true);
          this.marker?.setSnippet(this.address);
          // 记录地址信息日志
          hilog.info(0x0000, TAG, `The address is: ${this.address}`);
          if (this.isBackgroundRunning || this.isOnLocationChange) {
            // 若后台定位任务正在运行或正在监听位置变化,标记不使用缓存位置信息
            this.isCacheLocation = false;
          }
        } else {
          // 若获取地址信息失败,记录错误日志并根据情况显示定位失败提示
          hilog.error(0x0000, TAG, `getAddressesFromLocation failed, code: ${err.code}, message: ${err.message}`);
          if (!this.isOnLocationChange && !this.isBackgroundRunning) {
            this.locationFailedAlert(err.code);
          }
        }
      });

效果:

实时位置定位:

实时获取位置服务,需要使用到geoLocationManager.on('locationChange');来监听位置变化情况,实现持续获取位置的需求。on('locationChange')有三个参数需要满足

步骤:

  1. 申请定位权限
  2. 实例化位置信息请求对象
  3. 根据定位策略,调用on('locationChange');开启位置变化监听
  4. 在on('locationChange');的回调中调用逆地理编码转化,将坐标信息转换为对应地理位置
1.申请权限(同上)
2.实例化位置信息请求对象
onLocationChange(): void {
    // 定义持续定位请求的配置
    let request: geoLocationManager.ContinuousLocationRequest = {
      interval: 1,
      locationScenario: CommonConstants.NAVIGATION
    };
  }
3.根据定位策略,调用on('locationChange');开启位置变化监听
onLocationChange(): void {
    // 定义持续定位请求的配置
    let request: geoLocationManager.ContinuousLocationRequest = {
      interval: 1,
      locationScenario: CommonConstants.NAVIGATION
    };
    try {
      // 调用地理位置管理器的on方法开始监听位置变化
      geoLocationManager.on('locationChange', request, this.locationChange);
      // 检查是否有网络连接
      if (!this.judgeHasNet()) {
        // 若没有网络连接,显示提示信息
        promptAction.showToast({
          message: $r('app.string.internet_switch'),
          duration: 2000
        });
        // 隐藏标记的信息窗口
        this.marker?.setInfoWindowVisible(false);
        // 清空地址信息
        this.address = '';
      }
    } catch (err) {
      // 若出现错误,记录错误日志并显示定位失败提示
      hilog.error(0x0000, TAG, `onLocationChange failed, code: ${err.code}, message: ${err.message}`);
      this.locationFailedAlert(err.code);
    }
  }
4.on('locationChange')第三个参数设置
locationChange = (location: geoLocationManager.Location): void => {
    // 调用getAddress方法进行地址解析
    this.getAddress({
      latitude: location.latitude,
      longitude: location.longitude
    });
  }
5.在不需要获取位置信息时,及时关闭位置变化订阅,并删除对应的定位请求,减少设备功耗。
offLocationChange(): void {
    try {
      // 调用地理位置管理器的off方法停止监听位置变化
      geoLocationManager.off('locationChange', this.locationChange);
    } catch (err) {
      // 若出现错误,记录错误日志
      hilog.error(0x0000, TAG, `offLocationChange failed, code: ${err.code}, message: ${err.message}`);
    }
  }

应用后台定位:

应用后台定位是需要申请后台权限和长时任务权限,开启了任务模式为定位导航在on('locationChange')监听位置变化,便可在后台获取当前位置信息

步骤:

  1. 申请权限
  2. 设置长时任务模式为定位导航类型
  3. 在on('locationChange')监听位置变化
  4. 调用逆地理编码转化
1.申请权限
{
        "name": "ohos.permission.LOCATION_IN_BACKGROUND",
        "reason": "$string:location_background",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "always"
        }
      },
2.设置长时任务模式为定位导航类型

3.在在on('locationChange')监听位置变化,完成逆地理解析
startContinuousTask(): void {
    // 获取当前组件的上下文
    let context = getContext(this) 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) => {
      // 调用后台任务管理器的startBackgroundRunning方法启动后台定位任务
      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)}`);
      });
    });
  }
4.在不需要获取位置信息时,及时关闭位置变化订阅,并删除对应的定位请求,减少设备功耗。
stopContinuousTask(): void {
    // 获取当前组件的上下文
    let context = getContext(this) as common.UIAbilityContext;
    if (!context) {
      return;
    }
    // 调用后台任务管理器的stopBackgroundRunning方法停止后台定位任务
    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)}`);
    });
  }

效果:

历史定位获取:

通过getLastLocation()接口来获取系统缓存的最新位置信息。

步骤:

  1. 申请权限
  2. 通过getLastLocation()接口来获取系统缓存的最新位置信息。
  3. 调用getAddressesFromLocation()接口进行逆地理编码转化
1.申请权限(完整权限)
"requestPermissions": [
      //允许应用获取设备位置信息
      {
        "name": "ohos.permission.LOCATION",
        "reason": "$string:location_permission",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "inuse"
        }
      },
      //允许应用获取设备模糊位置信息
      {
        "name": "ohos.permission.APPROXIMATELY_LOCATION",
        "reason": "$string:fuzzy_location_permission",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "inuse"
        }
      },
      //允许应用在后台获取设备位置信息。
      {
        "name": "ohos.permission.LOCATION_IN_BACKGROUND",
        "reason": "$string:location_background",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "always"
        }
      },
      //允许应用开启长时任务
      {
        "name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
        "reason": "$string:running_background",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "always"
        }
      },
      //允许应用获取设备网络连接信息
      {
        "name": "ohos.permission.GET_NETWORK_INFO",
        "reason": "$string:get_network_info",
        "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "always"
        }
      }
    ]

2.通过getLastLocation()接口来获取系统缓存的最新位置信息

judgeHasNet(): boolean {
    try {
      // 获取默认网络句柄
      let netHandle = connection.getDefaultNetSync();
      if (!netHandle || netHandle.netId === 0) {
        return false;
      }
      // 获取网络能力信息
      let netCapability = connection.getNetCapabilitiesSync(netHandle);
      let cap = netCapability.networkCap || [];
      if (cap.includes(connection.NetCap.NET_CAPABILITY_VALIDATED)) {
        // 若网络能力包含有效验证,说明有网络连接
        return true;
      } else {
        return false;
      }
    } catch (err) {
      // 若出现错误,记录错误日志
      hilog.error(0x0000, TAG, `JudgeHasNet failed, code: ${err.code}, message: ${err.message}`);
    }
    return false;
  }

3.调用getAddressesFromLocation()接口进行逆地理编码(同上)

效果:

适用HarmonyOS NEXT / API12或以上版本 -----------------


网站公告

今日签到

点亮在社区的每一天
去签到