新昌一股清泉 發表於 2025-5-7 09:13:00

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

<p>前言</p>
<p>在开发运动类应用时,集成地图功能以及实时记录运动轨迹和公里数是核心需求之一。本文将详细介绍如何在 HarmonyOS 应用中集成百度地图 SDK,实现运动跟随以及运动公里数的记录。</p>
<p>一、集成百度地图 SDK</p>
<p>1.引入依赖</p>
<p>首先,需要在项目的文件中引入百度地图相关的依赖包:</p>
<pre><code class="language-json">"dependencies": {
"@bdmap/base": "1.2.6",
"@bdmap/search": "1.2.6",
"@bdmap/map": "1.2.6",
"@bdmap/locsdk": "1.1.4"
}
</code></pre>
<p>2.初始化百度地图</p>
<p>为了使用百度地图的功能,我们需要进行初始化操作。这包括设置 API Key 和初始化定位客户端。</p>
<p>MapUtil 类</p>
<pre><code>
export class MapUtil{

public static initialize(context:Context){
    Initializer.getInstance().initialize("你的key");
    // 设置是否同意隐私合规政策接口
    // true,表示同意隐私合规政策
    // false,表示不同意隐私合规政策
    LocationClient.checkAuthKey("你的key", (result: string) =&gt; {
      console.debug("result = " + result); // 可打印出是否鉴权成功的结果
    });
    LocationClient.setAgreePrivacy(true);
    LocManager.getInstance().init(context);
}

}
</code></pre>
<p>LocManager 类</p>
<pre><code>
export class LocManager {
private client: LocationClient | null = null;

private static instance: LocManager;

public static getInstance(): LocManager {
    if (!LocManager.instance) {
      LocManager.instance = new LocManager();
    }
    return LocManager.instance;
}

constructor() {

}

init(context: Context) {
    if (this.client == null) {
      try {
      this.client = new LocationClient(context);
      } catch (error) {
      console.error("harmony_baidu_location error: " + error.message);
      }
    }
    if (this.client != null) {
      this.client.setLocOption(this.getDefaultLocationOption());
    }
}

start() {
    if (this.client != null) {
      this.client.start();
    }
}

stop() {
    if (this.client != null) {
      this.client.stop();
    }
}

requestSingleLocation() {
    if (this.client != null) {
      this.client.requestSingleLocation();
    }
}

registerListener(listener: BDLocationListener): boolean {
    let isSuccess: boolean = false;
    if (this.client != null &amp;&amp; listener != null) {
      this.client.registerLocationListener(listener);
      isSuccess = true;
    }
    return isSuccess;
}

unRegisterListener(listener: BDLocationListener) {
    if (this.client != null &amp;&amp; listener != null) {
      this.client.unRegisterLocationListener(listener);
    }
}

getSDKVersion(): string {
    let version: string = "";
    if (this.client != null) {
      version = this.client.getVersion();
    }
    return version;
}

enableLocInBackground(wantAgent: WantAgent) {
    if (this.client != null) {
      this.client.enableLocInBackground(wantAgent);
    }
}

disableLocInBackground() {
    if (this.client != null) {
      this.client.disableLocInBackground();
    }
}

getDefaultLocationOption() {
    let option = new LocationClientOption();
    option.setCoorType("bd09ll"); // 可选,默认为gcj02,设置返回的定位结果坐标系
    option.setTimeInterval(3); // 可选,默认1秒,设置连续定位请求的时间间隔
    option.setDistanceInterval(0); // 可选,默认0米,设置连续定位的距离间隔
    option.setIsNeedAddress(true); // 可选,设置是否需要地址信息,默认不需要
    option.setIsNeedLocationDescribe(true); // 可选,默认为false,设置是否需要地址描述
    option.setIsNeedLocationPoiList(true); // 可选,默认能为false,设置是否需要POI结果
    option.setLocationMode(LocationMode.High_Accuracy); // 可选,默认高精度,设置定位模式,高精度、低功耗、仅设备
    option.setSingleLocatingTimeout(3000); // 可选,仅针对单次定位生效,设置单次定位的超时时间

    return option;
}

}
</code></pre>
<p>3.定位监听器</p>
<p>为了处理定位数据,我们需要实现一个定位监听器:</p>
<pre><code>
export class MapLocationListener extends BDLocationListener {
private callback: (location: BDLocation) =&gt; void;

constructor(callback: (location: BDLocation) =&gt; void) {
    super();
    this.callback = callback;
}

onReceiveLocation(bdLocation: BDLocation): void {
    this.callback(bdLocation);
}
}
</code></pre>
<p>二、页面使用</p>
<p>1.权限申请</p>
<p>在文件中声明所需的权限:</p>
<pre><code>"requestPermissions": [
      {
      "name": "ohos.permission.LOCATION",
      "reason": "$string:location_permission",
      "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "inuse"
      }
      },
      {
      "name": "ohos.permission.LOCATION_IN_BACKGROUND",
      "reason": "$string:background_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.APP_TRACKING_CONSENT",
      "reason": "$string:get_oaid_permission",
      "usedScene": {
          "abilities": [
            "EntryAbility"
          ],
          "when": "inuse"
      }
      },
      {
      "name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
      "reason": "$string:keep_background_running_permission",
      "usedScene": {
          "abilities": [
            "EntryAbility1"
          ],
          "when": "inuse"
      }
      }
    ]
</code></pre>
<p>2.请求权限</p>
<p>在页面中请求权限:</p>
<pre><code>private async requestPermissions(): Promise&lt;boolean&gt; {
    const permissions : Permissions[]= [
      'ohos.permission.LOCATION',
      'ohos.permission.APPROXIMATELY_LOCATION',
      'ohos.permission.APP_TRACKING_CONSENT',
    ]
    return LibPermission.requestPermissions(permissions)
}
</code></pre>
<p>3.页面调用</p>
<p>方向感应</p>
<p>使用鸿蒙系统自带的方向传感器来获取设备的朝向角度:</p>
<pre><code class="language-typescript">// 初始化方向传感器
      sensor.on(sensor.SensorId.ORIENTATION, (data) =&gt; {
      // 获取设备朝向角度(绕Z轴旋转角度)
      this.currentRotation = data.alpha;
      if(this.loc){
          this.loc.location = new LatLng(this.currentLatitude, this.currentLongitude);
          this.loc.direction = this.currentRotation;
          this.loc.radius = 0;
      }
      });

// 用完记得取消监听
sensor.off(sensor.SensorId.ORIENTATION);
</code></pre>
<p>编写定位监听器</p>
<pre><code>private mListener: MapLocationListener = new MapLocationListener((bdLocation: BDLocation) =&gt; {
    this.currentLatitude = bdLocation.getLatitude();
    this.currentLongitude = bdLocation.getLongitude();
    this.currentRadius = bdLocation.getRadius();

    // 更新地图位置和位置标记
    if (this.mapController) {
      // 更新地图中心点
      this.mapController.setMapCenter({
      lat: this.currentLatitude,
      lng: this.currentLongitude
      },15);

      if(this.loc){
      // 设置定位图标位置、指向以及范围
      this.loc.location = new LatLng(this.currentLatitude, this.currentLongitude);
      this.loc.direction = this.currentRotation;
      // 单位米
      this.loc.radius = 0;

      }

    }
});
</code></pre>
<p>启动和关闭定位</p>
<pre><code class="language-typescript">// 启动定位
LocManager.getInstance().registerListener(this.mListener);
LocManager.getInstance().start();

// 关闭定位
LocManager.getInstance().unRegisterListener(this.mListener);
LocManager.getInstance().stop();
</code></pre>
<p>百度地图集成</p>
<p>在页面中集成百度地图:</p>
<pre><code>MapComponent({ onReady: async (err, mapController:MapController) =&gt; {
          if (!err) {
            // 获取地图的控制器类,用来操作地图
            this.mapController= mapController;
            let result = this.mapController.getLayerByTag(SysEnum.LayerTag.LOCATION);
            if(result){
            this.loc = result as LocationLayer;
            }

            if(this.currentLatitude!=0&amp;&amp;this.currentLongitude!=0){
            if(this.loc){
                // 设置定位图标位置、指向以及范围
                this.loc.location = new LatLng(this.currentLatitude, this.currentLongitude);
                this.loc.direction = this.currentRotation;
                // 单位米
                this.loc.radius = 0;
            }

            this.mapController.setMapCenter({
                lat: this.currentLatitude,
                lng: this.currentLongitude
            },15);

            }
          }
      }, mapOptions: this.mapOpt }).width('100%').height('100%')
</code></pre>
<p>三、公里数计算</p>
<p>在运动应用中,记录用户的运动轨迹并计算运动的总距离是核心功能之一。为了实现这一功能,我们需要设计一个数据模型来记录运动轨迹点,并通过这些点计算总距离。</p>
<p>1.运动轨迹点模型</p>
<p>定义一个<code>RunPoint</code>类来表示运动轨迹中的一个点,包含纬度、经度和时间戳:</p>
<pre><code>/**
* 运动轨迹点数据模型
*/
export class RunPoint {
// 纬度
latitude: number;
// 经度
longitude: number;
// 时间戳
timestamp: number;
// 所属公里数分组(第几公里)
kilometerGroup: number;

constructor(latitude: number, longitude: number) {
    this.latitude = latitude;
    this.longitude = longitude;
    this.timestamp = Date.now();
    this.kilometerGroup = 0; // 默认分组为0
}
}
</code></pre>
<p>2.运动轨迹管理类</p>
<p>创建一个<code>RunTracker</code>类来管理运动轨迹点,并计算总距离:</p>
<pre><code>
/**
* 运动轨迹管理类
*/
export class RunTracker {
// 所有轨迹点
private points: RunPoint[] = [];
// 当前总距离(公里)
private totalDistance: number = 0;
// 当前公里数分组
private currentKilometerGroup: number = 0;

/**
   * 添加新的轨迹点
   * @param latitude 纬度
   * @param longitude 经度
   * @returns 当前总距离(公里)
   */
addPoint(latitude: number, longitude: number): number {
    const point = new RunPoint(latitude, longitude);

    if (this.points.length &gt; 0) {
      // 计算与上一个点的距离
      const lastPoint = this.points;
      const distance = this.calculateDistance(lastPoint, point);
      this.totalDistance += distance;

      // 更新公里数分组
      point.kilometerGroup = Math.floor(this.totalDistance);
      if (point.kilometerGroup &gt; this.currentKilometerGroup) {
      this.currentKilometerGroup = point.kilometerGroup;
      }
    }

    this.points.push(point);
    return this.totalDistance;
}

/**
   * 计算两点之间的距离(公里)
   * 使用Haversine公式计算球面距离
   */
private calculateDistance(point1: RunPoint, point2: RunPoint): number {
    const R = 6371; // 地球半径(公里)
    const lat1 = this.toRadians(point1.latitude);
    const lat2 = this.toRadians(point2.latitude);
    const deltaLat = this.toRadians(point2.latitude - point1.latitude);
    const deltaLon = this.toRadians(point2.longitude - point1.longitude);

    const a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2) +
            Math.cos(lat1) * Math.cos(lat2) *
            Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

    return R * c;
}

/**
   * 将角度转换为弧度
   */
private toRadians(degrees: number): number {
    return degrees * (Math.PI / 180);
}

/**
   * 获取当前总距离
   */
getTotalDistance(): number {
    return this.totalDistance;
}

/**
   * 获取指定公里数分组的轨迹点
   */
getPointsByKilometer(kilometer: number): RunPoint[] {
    return this.points.filter(point =&gt; point.kilometerGroup === kilometer);
}

/**
   * 清空轨迹数据
   */
clear(): void {
    this.points = [];
    this.totalDistance = 0;
    this.currentKilometerGroup = 0;
}
}
</code></pre>
<p>3.页面的监听器里记录公里数</p>
<p>在页面中使用<code>RunTracker</code>类来记录运动轨迹点并计算总距离:</p>
<pre><code>private runTracker: RunTracker = new RunTracker();
监听器添加代码
      const distance = this.runTracker.addPoint(this.currentLatitude, this.currentLongitude);

distance就是当前运动的公里数
</code></pre>
<p>四、总结</p>
<p>本文详细介绍了如何在 HarmonyOS 应用中集成百度地图 SDK,实现运动跟随以及运动公里数的记录。通过以下步骤,我们可以实现一个功能完整的运动应用:</p>
<p>• 集成百度地图 SDK:</p>
<p>• 引入必要的依赖包。</p>
<p>• 初始化百度地图并设置定位选项。</p>
<p>• 页面使用:</p>
<p>• 请求必要的权限。</p>
<p>• 启动和关闭定位。</p>
<p>• 实时更新地图位置和方向。</p>
<p>• 公里数计算:</p>
<p>• 定义运动轨迹点模型。</p>
<p>• 使用 Haversine 公式计算两点之间的距离。</p>
<p>• 记录运动轨迹点并实时更新总距离。</p>
<p>通过这些步骤,开发者可以轻松实现一个功能强大的运动应用,为用户提供实时的运动数据和地图跟随功能。希望本文的内容能够帮助你在 HarmonyOS 开发中取得更好的成果!</p><br><br>
来源:https://www.cnblogs.com/wangerdan115/p/18863616
頁: [1]
查看完整版本: HarmonyOS运动开发:如何集成百度地图SDK、运动跟随与运动公里数记录