HarmonyOS运动开发:如何集成百度地图SDK、运动跟随与运动公里数记录
前言
在开发运动类应用时,集成地图功能以及实时记录运动轨迹和公里数是核心需求之一。本文将详细介绍如何在 HarmonyOS 应用中集成百度地图 SDK,实现运动跟随以及运动公里数的记录。
一、集成百度地图 SDK
1.引入依赖
首先,需要在项目的文件中引入百度地图相关的依赖包:
"dependencies": { "@bdmap/base": "1.2.6", "@bdmap/search": "1.2.6", "@bdmap/map": "1.2.6", "@bdmap/locsdk": "1.1.4" }
2.初始化百度地图
为了使用百度地图的功能,我们需要进行初始化操作。这包括设置 API Key 和初始化定位客户端。
MapUtil 类
export class MapUtil{ public static initialize(context:Context){ Initializer.getInstance().initialize("你的key"); // 设置是否同意隐私合规政策接口 // true,表示同意隐私合规政策 // false,表示不同意隐私合规政策 LocationClient.checkAuthKey("你的key", (result: string) => { console.debug("result = " + result); // 可打印出是否鉴权成功的结果 }); LocationClient.setAgreePrivacy(true); LocManager.getInstance().init(context); } }
LocManager 类
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 && listener != null) { this.client.registerLocationListener(listener); isSuccess = true; } return isSuccess; } unRegisterListener(listener: BDLocationListener) { if (this.client != null && 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; } }
3.定位监听器
为了处理定位数据,我们需要实现一个定位监听器:
export class MapLocationListener extends BDLocationListener { private callback: (location: BDLocation) => void; constructor(callback: (location: BDLocation) => void) { super(); this.callback = callback; } onReceiveLocation(bdLocation: BDLocation): void { this.callback(bdLocation); } }
二、页面使用
1.权限申请
在文件中声明所需的权限:
"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" } } ]
2.请求权限
在页面中请求权限:
private async requestPermissions(): Promise<boolean> { const permissions : Permissions[]= [ 'ohos.permission.LOCATION', 'ohos.permission.APPROXIMATELY_LOCATION', 'ohos.permission.APP_TRACKING_CONSENT', ] return LibPermission.requestPermissions(permissions) }
3.页面调用
方向感应
使用鸿蒙系统自带的方向传感器来获取设备的朝向角度:
// 初始化方向传感器 sensor.on(sensor.SensorId.ORIENTATION, (data) => { // 获取设备朝向角度(绕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);
编写定位监听器
private mListener: MapLocationListener = new MapLocationListener((bdLocation: BDLocation) => { 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; } } });
启动和关闭定位
// 启动定位 LocManager.getInstance().registerListener(this.mListener); LocManager.getInstance().start(); // 关闭定位 LocManager.getInstance().unRegisterListener(this.mListener); LocManager.getInstance().stop();
百度地图集成
在页面中集成百度地图:
MapComponent({ onReady: async (err, mapController:MapController) => { if (!err) { // 获取地图的控制器类,用来操作地图 this.mapController= mapController; let result = this.mapController.getLayerByTag(SysEnum.LayerTag.LOCATION); if(result){ this.loc = result as LocationLayer; } if(this.currentLatitude!=0&&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%')
三、公里数计算
在运动应用中,记录用户的运动轨迹并计算运动的总距离是核心功能之一。为了实现这一功能,我们需要设计一个数据模型来记录运动轨迹点,并通过这些点计算总距离。
1.运动轨迹点模型
定义一个RunPoint
类来表示运动轨迹中的一个点,包含纬度、经度和时间戳:
/** * 运动轨迹点数据模型 */ 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 } }
2.运动轨迹管理类
创建一个RunTracker
类来管理运动轨迹点,并计算总距离:
/** * 运动轨迹管理类 */ 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 > 0) { // 计算与上一个点的距离 const lastPoint = this.points[this.points.length - 1]; const distance = this.calculateDistance(lastPoint, point); this.totalDistance += distance; // 更新公里数分组 point.kilometerGroup = Math.floor(this.totalDistance); if (point.kilometerGroup > 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 => point.kilometerGroup === kilometer); } /** * 清空轨迹数据 */ clear(): void { this.points = []; this.totalDistance = 0; this.currentKilometerGroup = 0; } }
3.页面的监听器里记录公里数
在页面中使用RunTracker
类来记录运动轨迹点并计算总距离:
private runTracker: RunTracker = new RunTracker(); 监听器添加代码 const distance = this.runTracker.addPoint(this.currentLatitude, this.currentLongitude); distance就是当前运动的公里数
四、总结
本文详细介绍了如何在 HarmonyOS 应用中集成百度地图 SDK,实现运动跟随以及运动公里数的记录。通过以下步骤,我们可以实现一个功能完整的运动应用:
• 集成百度地图 SDK:
• 引入必要的依赖包。
• 初始化百度地图并设置定位选项。
• 页面使用:
• 请求必要的权限。
• 启动和关闭定位。
• 实时更新地图位置和方向。
• 公里数计算:
• 定义运动轨迹点模型。
• 使用 Haversine 公式计算两点之间的距离。
• 记录运动轨迹点并实时更新总距离。
通过这些步骤,开发者可以轻松实现一个功能强大的运动应用,为用户提供实时的运动数据和地图跟随功能。希望本文的内容能够帮助你在 HarmonyOS 开发中取得更好的成果!