找回密码
 立即注册
首页 业界区 业界 HarmonyOS运动开发:如何集成百度地图SDK、运动跟随与运 ...

HarmonyOS运动开发:如何集成百度地图SDK、运动跟随与运动公里数记录

腥狩频 2025-6-5 10:09:17
前言
在开发运动类应用时,集成地图功能以及实时记录运动轨迹和公里数是核心需求之一。本文将详细介绍如何在 HarmonyOS 应用中集成百度地图 SDK,实现运动跟随以及运动公里数的记录。
一、集成百度地图 SDK
1.引入依赖
首先,需要在项目的文件中引入百度地图相关的依赖包:
  1. "dependencies": {
  2.   "@bdmap/base": "1.2.6",
  3.   "@bdmap/search": "1.2.6",
  4.   "@bdmap/map": "1.2.6",
  5.   "@bdmap/locsdk": "1.1.4"
  6. }
复制代码
2.初始化百度地图
为了使用百度地图的功能,我们需要进行初始化操作。这包括设置 API Key 和初始化定位客户端。
MapUtil 类
  1. export class MapUtil{
  2.   public static initialize(context:Context){
  3.     Initializer.getInstance().initialize("你的key");
  4.     // 设置是否同意隐私合规政策接口
  5.     // true,表示同意隐私合规政策
  6.     // false,表示不同意隐私合规政策
  7.     LocationClient.checkAuthKey("你的key", (result: string) => {
  8.       console.debug("result = " + result); // 可打印出是否鉴权成功的结果
  9.     });
  10.     LocationClient.setAgreePrivacy(true);
  11.     LocManager.getInstance().init(context);
  12.   }
  13. }
复制代码
LocManager 类
  1. export class LocManager {
  2.   private client: LocationClient | null = null;
  3.   private static instance: LocManager;
  4.   public static getInstance(): LocManager {
  5.     if (!LocManager.instance) {
  6.       LocManager.instance = new LocManager();
  7.     }
  8.     return LocManager.instance;
  9.   }
  10.   constructor() {
  11.   }
  12.   init(context: Context) {
  13.     if (this.client == null) {
  14.       try {
  15.         this.client = new LocationClient(context);
  16.       } catch (error) {
  17.         console.error("harmony_baidu_location error: " + error.message);
  18.       }
  19.     }
  20.     if (this.client != null) {
  21.       this.client.setLocOption(this.getDefaultLocationOption());
  22.     }
  23.   }
  24.   start() {
  25.     if (this.client != null) {
  26.       this.client.start();
  27.     }
  28.   }
  29.   stop() {
  30.     if (this.client != null) {
  31.       this.client.stop();
  32.     }
  33.   }
  34.   requestSingleLocation() {
  35.     if (this.client != null) {
  36.       this.client.requestSingleLocation();
  37.     }
  38.   }
  39.   registerListener(listener: BDLocationListener): boolean {
  40.     let isSuccess: boolean = false;
  41.     if (this.client != null && listener != null) {
  42.       this.client.registerLocationListener(listener);
  43.       isSuccess = true;
  44.     }
  45.     return isSuccess;
  46.   }
  47.   unRegisterListener(listener: BDLocationListener) {
  48.     if (this.client != null && listener != null) {
  49.       this.client.unRegisterLocationListener(listener);
  50.     }
  51.   }
  52.   getSDKVersion(): string {
  53.     let version: string = "";
  54.     if (this.client != null) {
  55.       version = this.client.getVersion();
  56.     }
  57.     return version;
  58.   }
  59.   enableLocInBackground(wantAgent: WantAgent) {
  60.     if (this.client != null) {
  61.       this.client.enableLocInBackground(wantAgent);
  62.     }
  63.   }
  64.   disableLocInBackground() {
  65.     if (this.client != null) {
  66.       this.client.disableLocInBackground();
  67.     }
  68.   }
  69.   getDefaultLocationOption() {
  70.     let option = new LocationClientOption();
  71.     option.setCoorType("bd09ll"); // 可选,默认为gcj02,设置返回的定位结果坐标系
  72.     option.setTimeInterval(3); // 可选,默认1秒,设置连续定位请求的时间间隔
  73.     option.setDistanceInterval(0); // 可选,默认0米,设置连续定位的距离间隔
  74.     option.setIsNeedAddress(true); // 可选,设置是否需要地址信息,默认不需要
  75.     option.setIsNeedLocationDescribe(true); // 可选,默认为false,设置是否需要地址描述
  76.     option.setIsNeedLocationPoiList(true); // 可选,默认能为false,设置是否需要POI结果
  77.     option.setLocationMode(LocationMode.High_Accuracy); // 可选,默认高精度,设置定位模式,高精度、低功耗、仅设备
  78.     option.setSingleLocatingTimeout(3000); // 可选,仅针对单次定位生效,设置单次定位的超时时间
  79.     return option;
  80.   }
  81. }
复制代码
3.定位监听器
为了处理定位数据,我们需要实现一个定位监听器:
  1. export class MapLocationListener extends BDLocationListener {
  2.   private callback: (location: BDLocation) => void;
  3.   constructor(callback: (location: BDLocation) => void) {
  4.     super();
  5.     this.callback = callback;
  6.   }
  7.   onReceiveLocation(bdLocation: BDLocation): void {
  8.     this.callback(bdLocation);
  9.   }
  10. }
复制代码
二、页面使用
1.权限申请
在文件中声明所需的权限:
  1. "requestPermissions": [
  2.       {
  3.         "name": "ohos.permission.LOCATION",
  4.         "reason": "$string:location_permission",
  5.         "usedScene": {
  6.           "abilities": [
  7.             "EntryAbility"
  8.           ],
  9.           "when": "inuse"
  10.         }
  11.       },
  12.       {
  13.         "name": "ohos.permission.LOCATION_IN_BACKGROUND",
  14.         "reason": "$string:background_location_permission",
  15.         "usedScene": {
  16.           "abilities": [
  17.             "EntryAbility"
  18.           ],
  19.           "when": "inuse"
  20.         }
  21.       },
  22.       {
  23.         "name": "ohos.permission.APPROXIMATELY_LOCATION",
  24.         "reason": "$string:fuzzy_location_permission",
  25.         "usedScene": {
  26.           "abilities": [
  27.             "EntryAbility"
  28.           ],
  29.           "when": "inuse"
  30.         }
  31.       },
  32.       {
  33.         "name": "ohos.permission.APP_TRACKING_CONSENT",
  34.         "reason": "$string:get_oaid_permission",
  35.         "usedScene": {
  36.           "abilities": [
  37.             "EntryAbility"
  38.           ],
  39.           "when": "inuse"
  40.         }
  41.       },
  42.       {
  43.         "name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
  44.         "reason": "$string:keep_background_running_permission",
  45.         "usedScene": {
  46.           "abilities": [
  47.             "EntryAbility1"
  48.           ],
  49.           "when": "inuse"
  50.         }
  51.       }
  52.     ]
复制代码
2.请求权限
在页面中请求权限:
  1. private async requestPermissions(): Promise<boolean> {
  2.     const permissions : Permissions[]= [
  3.       'ohos.permission.LOCATION',
  4.       'ohos.permission.APPROXIMATELY_LOCATION',
  5.       'ohos.permission.APP_TRACKING_CONSENT',
  6.     ]
  7.     return LibPermission.requestPermissions(permissions)
  8.   }
复制代码
3.页面调用
方向感应
使用鸿蒙系统自带的方向传感器来获取设备的朝向角度:
  1. // 初始化方向传感器
  2.       sensor.on(sensor.SensorId.ORIENTATION, (data) => {
  3.         // 获取设备朝向角度(绕Z轴旋转角度)
  4.         this.currentRotation = data.alpha;
  5.         if(this.loc){
  6.           this.loc.location = new LatLng(this.currentLatitude, this.currentLongitude);
  7.           this.loc.direction = this.currentRotation;
  8.           this.loc.radius = 0;
  9.         }
  10.       });
  11. // 用完记得取消监听
  12. sensor.off(sensor.SensorId.ORIENTATION);
复制代码
编写定位监听器
  1. private mListener: MapLocationListener = new MapLocationListener((bdLocation: BDLocation) => {
  2.     this.currentLatitude = bdLocation.getLatitude();
  3.     this.currentLongitude = bdLocation.getLongitude();
  4.     this.currentRadius = bdLocation.getRadius();
  5.     // 更新地图位置和位置标记
  6.     if (this.mapController) {
  7.       // 更新地图中心点
  8.       this.mapController.setMapCenter({
  9.         lat: this.currentLatitude,
  10.         lng: this.currentLongitude
  11.       },15);
  12.       if(this.loc){
  13.         // 设置定位图标位置、指向以及范围
  14.         this.loc.location = new LatLng(this.currentLatitude, this.currentLongitude);
  15.         this.loc.direction = this.currentRotation;
  16.         // 单位米
  17.         this.loc.radius = 0;
  18.       }
  19.     }
  20.   });
复制代码
启动和关闭定位
  1. // 启动定位
  2. LocManager.getInstance().registerListener(this.mListener);
  3. LocManager.getInstance().start();
  4. // 关闭定位
  5. LocManager.getInstance().unRegisterListener(this.mListener);
  6. LocManager.getInstance().stop();
复制代码
百度地图集成
在页面中集成百度地图:
  1. MapComponent({ onReady: async (err, mapController:MapController) => {
  2.           if (!err) {
  3.             // 获取地图的控制器类,用来操作地图
  4.             this.mapController= mapController;
  5.             let result = this.mapController.getLayerByTag(SysEnum.LayerTag.LOCATION);
  6.             if(result){
  7.               this.loc = result as LocationLayer;
  8.             }
  9.             if(this.currentLatitude!=0&&this.currentLongitude!=0){
  10.               if(this.loc){
  11.                 // 设置定位图标位置、指向以及范围
  12.                 this.loc.location = new LatLng(this.currentLatitude, this.currentLongitude);
  13.                 this.loc.direction = this.currentRotation;
  14.                 // 单位米
  15.                 this.loc.radius = 0;
  16.               }
  17.               this.mapController.setMapCenter({
  18.                 lat: this.currentLatitude,
  19.                 lng: this.currentLongitude
  20.               },15);
  21.             }
  22.           }
  23.         }, mapOptions: this.mapOpt }).width('100%').height('100%')
复制代码
三、公里数计算
在运动应用中,记录用户的运动轨迹并计算运动的总距离是核心功能之一。为了实现这一功能,我们需要设计一个数据模型来记录运动轨迹点,并通过这些点计算总距离。
1.运动轨迹点模型
定义一个RunPoint类来表示运动轨迹中的一个点,包含纬度、经度和时间戳:
  1. /**
  2. * 运动轨迹点数据模型
  3. */
  4. export class RunPoint {
  5.   // 纬度
  6.   latitude: number;
  7.   // 经度
  8.   longitude: number;
  9.   // 时间戳
  10.   timestamp: number;
  11.   // 所属公里数分组(第几公里)
  12.   kilometerGroup: number;
  13.   constructor(latitude: number, longitude: number) {
  14.     this.latitude = latitude;
  15.     this.longitude = longitude;
  16.     this.timestamp = Date.now();
  17.     this.kilometerGroup = 0; // 默认分组为0
  18.   }
  19. }
复制代码
2.运动轨迹管理类
创建一个RunTracker类来管理运动轨迹点,并计算总距离:
  1. /**
  2. * 运动轨迹管理类
  3. */
  4. export class RunTracker {
  5.   // 所有轨迹点
  6.   private points: RunPoint[] = [];
  7.   // 当前总距离(公里)
  8.   private totalDistance: number = 0;
  9.   // 当前公里数分组
  10.   private currentKilometerGroup: number = 0;
  11.   /**
  12.    * 添加新的轨迹点
  13.    * @param latitude 纬度
  14.    * @param longitude 经度
  15.    * @returns 当前总距离(公里)
  16.    */
  17.   addPoint(latitude: number, longitude: number): number {
  18.     const point = new RunPoint(latitude, longitude);
  19.     if (this.points.length > 0) {
  20.       // 计算与上一个点的距离
  21.       const lastPoint = this.points[this.points.length - 1];
  22.       const distance = this.calculateDistance(lastPoint, point);
  23.       this.totalDistance += distance;
  24.       // 更新公里数分组
  25.       point.kilometerGroup = Math.floor(this.totalDistance);
  26.       if (point.kilometerGroup > this.currentKilometerGroup) {
  27.         this.currentKilometerGroup = point.kilometerGroup;
  28.       }
  29.     }
  30.     this.points.push(point);
  31.     return this.totalDistance;
  32.   }
  33.   /**
  34.    * 计算两点之间的距离(公里)
  35.    * 使用Haversine公式计算球面距离
  36.    */
  37.   private calculateDistance(point1: RunPoint, point2: RunPoint): number {
  38.     const R = 6371; // 地球半径(公里)
  39.     const lat1 = this.toRadians(point1.latitude);
  40.     const lat2 = this.toRadians(point2.latitude);
  41.     const deltaLat = this.toRadians(point2.latitude - point1.latitude);
  42.     const deltaLon = this.toRadians(point2.longitude - point1.longitude);
  43.     const a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
  44.               Math.cos(lat1) * Math.cos(lat2) *
  45.               Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
  46.     const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  47.     return R * c;
  48.   }
  49.   /**
  50.    * 将角度转换为弧度
  51.    */
  52.   private toRadians(degrees: number): number {
  53.     return degrees * (Math.PI / 180);
  54.   }
  55.   /**
  56.    * 获取当前总距离
  57.    */
  58.   getTotalDistance(): number {
  59.     return this.totalDistance;
  60.   }
  61.   /**
  62.    * 获取指定公里数分组的轨迹点
  63.    */
  64.   getPointsByKilometer(kilometer: number): RunPoint[] {
  65.     return this.points.filter(point => point.kilometerGroup === kilometer);
  66.   }
  67.   /**
  68.    * 清空轨迹数据
  69.    */
  70.   clear(): void {
  71.     this.points = [];
  72.     this.totalDistance = 0;
  73.     this.currentKilometerGroup = 0;
  74.   }
  75. }
复制代码
3.页面的监听器里记录公里数
在页面中使用RunTracker类来记录运动轨迹点并计算总距离:
  1.   private runTracker: RunTracker = new RunTracker();
  2. 监听器添加代码
  3.       const distance = this.runTracker.addPoint(this.currentLatitude, this.currentLongitude);
  4. distance就是当前运动的公里数
复制代码
四、总结
本文详细介绍了如何在 HarmonyOS 应用中集成百度地图 SDK,实现运动跟随以及运动公里数的记录。通过以下步骤,我们可以实现一个功能完整的运动应用:
• 集成百度地图 SDK:
• 引入必要的依赖包。
• 初始化百度地图并设置定位选项。
• 页面使用:
• 请求必要的权限。
• 启动和关闭定位。
• 实时更新地图位置和方向。
• 公里数计算:
• 定义运动轨迹点模型。
• 使用 Haversine 公式计算两点之间的距离。
• 记录运动轨迹点并实时更新总距离。
通过这些步骤,开发者可以轻松实现一个功能强大的运动应用,为用户提供实时的运动数据和地图跟随功能。希望本文的内容能够帮助你在 HarmonyOS 开发中取得更好的成果!

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册