HarmonyOS運動開発:百度マップSDKの統合、運動の追跡と運動距離の記録
前言
運動系アプリを開発する際、マップ機能を統合し、リアルタイムで運動の軌跡と距離を記録することは、核心的なニーズの一つです。この記事では、HarmonyOSアプリに百度マップSDKを統合し、運動の追跡と運動距離の記録を実現する方法を詳しく紹介します。
一、百度マップSDKの統合
- 依存関係の導入
まず、プロジェクトのファイルに百度マップ関連の依存パッケージを導入する必要があります。
"dependencies": {
"@bdmap/base": "1.2.6",
"@bdmap/search": "1.2.6",
"@bdmap/map": "1.2.6",
"@bdmap/locsdk": "1.1.4"
}
- 百度マップの初期化
百度マップの機能を使用するためには、初期化操作を行う必要があります。これは、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;
}
}
- 定位リスナー
定位データを処理するためには、定位リスナーを実装する必要があります。
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);
}
}
二、ページの使用
- 権限の申請
ファイルに必要な権限を宣言します。
"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"
}
}
]
- 権限の要求
ページで権限を要求します。
private async requestPermissions(): Promise<boolean> {
const permissions : Permissions[]= [
'ohos.permission.LOCATION',
'ohos.permission.APPROXIMATELY_LOCATION',
'ohos.permission.APP_TRACKING_CONSENT',
]
return LibPermission.requestPermissions(permissions)
}
- ページの呼び出し
方向センサーの使用
鴻蒙システムの組み込み方向センサーを使用して、デバイスの方向角度を取得します。
// 方向センサーの初期化
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%')
三、距離の計算
運動アプリでは、ユーザーの運動軌跡を記録し、運動の総距離を計算することが核心機能の一つです。この機能を実現するためには、運動軌跡のポイントを記録するデータモデルを設計し、これらのポイントから総距離を計算する必要があります。
- 運動軌跡のポイントモデル
RunPoint
クラスを定義して、運動軌跡の1つのポイントを表します。これは、緯度、経度、タイムスタンプを含みます。
/**
* 運動軌跡のポイントデータモデル
*/
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
}
}
- 運動軌跡の管理クラス
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;
}
/**
* 2つのポイント間の距離(キロメートル)を計算する
* 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;
}
}
- ページのリスナーでキロメートル数を記録する
ページで RunTracker
クラスを使用して、運動軌跡のポイントを記録し、総距離を計算します。
private runTracker: RunTracker = new RunTracker();
リスナーに追加するコード
const distance = this.runTracker.addPoint(this.currentLatitude, this.currentLongitude);
distance は現在の運動キロメートル数です
四、まとめ
この記事では、HarmonyOSアプリに百度マップSDKを統合し、運動の追跡と運動キロメートル数の記録を実現する方法を詳しく紹介しました。以下の手順で、機能が完整的な運動アプリを実現できます。
• 百度マップSDKの統合:
• 必要な依存パッケージを導入する。
• 百度マップを初期化し、定位オプションを設定する。
• ページの使用:
• 必要な権限を要求する。
• 定位を開始し、停止する。
• マップの位置と方向をリアルタイムで更新する。
• キロメートル数の計算:
• 運動軌跡のポイントモデルを定義する。
• Haversine公式を使用して2つのポイント間の距離を計算する。
• 運動軌跡のポイントを記録し、総距離をリアルタイムで更新する。
これらの手順を通じて、開発者は機能が強力な運動アプリを簡単に実現し、ユーザーにリアルタイムの運動データとマップの追跡機能を提供することができます。この記事の内容があなたの HarmonyOS 開発に役立つことを願っています!
Discussion