前言
在開發運動類應用時,集成地圖功能以及實時記錄運動軌跡和公里數是核心需求之一。本文將詳細介紹如何在 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 開發中取得更好的成果!