緯度,経度,高度,移動速度,移動方向を取得するAndroidアプリを作る ~Delphiソースコード集
1.Delphiを起動
Delphiを起動して新規FMXプロジェクトを作成し、ターゲットプラットフォームをAndroidに設定して、 フォームにTMemoを1つ配置します。プロジェクトとユニットを保存します。

2.権限設定
おおよその位置情報へのアクセス、詳細な位置情報へのアクセスが必要です。
3.ソースコードの記述
unit Unit1; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.ScrollBox, FMX.Memo,FMX.StdCtrls, System.DateUtils, Androidapi.JNI.Location, Androidapi.JNIBridge, Androidapi.JNI.JavaTypes, Androidapi.JNI.Os, Androidapi.Helpers, Androidapi.JNI.GraphicsContentViewText, Androidapi.Jni.Support, FMX.DialogService, //Android8(ApiLevel26)以降で権限許可の為に必要なユニット System.Permissions ; type TForm1 = class(TForm) Memo1: TMemo; procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); private { private 宣言 } LocationManager : JLocationManager; LocationListener : JLocationListener; procedure onLocationChanged(location: JLocation); //Android8(ApiLevel26)以降対応関数 procedure PermissionRequestResult(Sender:TObject; const APermissions:TArray<string>; const AGrantResults: TArray<TPermissionStatus>); //Android8(ApiLevel26)以降対応関数 procedure RequestPermissions(); public { public 宣言 } end; TOnLocationChanged=procedure(location:JLocation) of object; TMyLocationListener = class(TJavaLocal, JLocationListener) private Folc:TOnLocationChanged; public constructor Create(olc:TOnLocationChanged); procedure onLocationChanged(location: JLocation); cdecl; procedure onProviderDisabled(provider: JString); cdecl; procedure onProviderEnabled(provider: JString); cdecl; procedure onStatusChanged(provider: JString; status: Integer; extras: JBundle); cdecl; end; var Form1: TForm1; implementation {$R *.fmx} { TMyLocationListener } constructor TMyLocationListener.Create(olc: TOnLocationChanged); begin inherited Create(); Folc:=olc; end; procedure TMyLocationListener.onLocationChanged(location: JLocation); begin if Assigned(Folc) then Folc(location); end; procedure TMyLocationListener.onProviderDisabled(provider: JString); begin end; procedure TMyLocationListener.onProviderEnabled(provider: JString); begin end; procedure TMyLocationListener.onStatusChanged(provider: JString; status: Integer; extras: JBundle); begin end; { TForm1 } procedure TForm1.FormCreate(Sender: TObject); var LocationService: JObject; location : JLocation; begin //Android8(ApiLevel26)以降はアプリから権限要求が必要 RequestPermissions; LocationService := TAndroidHelper.Context.getSystemService( TJContext.JavaClass.LOCATION_SERVICE ); LocationManager := TJLocationManager.Wrap( (LocationService as ILocalObject).GetObjectID ); LocationListener:= TMyLocationListener.Create(self.onLocationChanged); //位置情報が変化したら通知をもらう LocationManager.requestLocationUpdates( TJLocationManager.JavaClass.GPS_PROVIDER, 5000,//最小間隔5秒で 10, //距離10m以上移動したら通知 locationListener, TJLooper.JavaClass.getMainLooper ); //過去に取得した位置情報で最後の情報を取得する location:=LocationManager.getLastKnownLocation( TJLocationManager.JavaClass.GPS_PROVIDER ); //とりあえず、それを出力 if assigned(location) then self.onLocationChanged(location); end; procedure TForm1.FormDestroy(Sender: TObject); begin //位置情報通知の解除 LocationManager.removeUpdates(LocationListener); end; procedure TForm1.onLocationChanged(location: JLocation); var dt:TDateTime; begin dt:=UnixToDateTime(location.getTime div 1000,false); Memo1.Lines.Add('日時:'+FormatDateTime('yyyy/mm/dd hh:nn:ss',dt)); Memo1.Lines.Add('緯度:'+location.getLatitude.ToString+'度'); Memo1.Lines.Add('経度:'+location.getLongitude.ToString+'度'); Memo1.Lines.Add('誤差半径:'+location.getAccuracy.ToString+'m'); //WGS84準拠高度から「ジオイド高」を引くと標高が求められる //ジオイド高は国土地理院サイトで緯度・経度から求めることが出来る Memo1.Lines.Add('WGS84準拠高度:'+location.getAltitude.ToString+'m'); Memo1.Lines.Add('高度誤差:±'+location.getVerticalAccuracyMeters.ToString); Memo1.Lines.Add('移動速度:'+location.getSpeed.ToString+'m/s'); Memo1.Lines.Add('移動方向:'+location.getBearing.ToString+'度(北が0で時計回)'); Memo1.Lines.Add(''); Memo1.GoToTextEnd; end; procedure TForm1.PermissionRequestResult(Sender:TObject; const APermissions:TArray<string>; const AGrantResults: TArray<TPermissionStatus>); begin //FineLocationの権限があるか if (AGrantResults[0]<>TPermissionStatus.Granted) then begin //権限がない場合 //「□今後は表示しない」チェックボックスにチェックが入っているか if (TJActivityCompat.JavaClass.shouldShowRequestPermissionRationale( TAndroidHelper.Activity, TJManifest_permission.JavaClass.WRITE_EXTERNAL_STORAGE)) then begin //「□今後は表示しない」チェックボックスにチェックが入っていない場合 // 非同期でダイアログを表示して説明と許可を要求 TDialogService.MessageDialog( '許可しないとアプリが動作しません。',TMsgDlgType.mtInformation, [TMsgDlgBtn.mbOK],TMsgDlgBtn.mbOk,0, procedure (const AResult: TModalResult) begin //2回目以降は「□今後は表示しない」チェックボックスが表示される RequestPermissions(); end); end else begin //「□今後は表示しない」チェックボックスにチェックが入っている TDialogService.MessageDialog( '権限が無いため終了します。「設定⇒アプリと通知」から権限設定してください。', TMsgDlgType.mtError,[TMsgDlgBtn.mbOK],TMsgDlgBtn.mbOK,0, procedure(const AResult:TModalResult) begin Application.Terminate; end ); end; end; end; procedure TForm1.RequestPermissions; begin //位置情報サービスの権限要求を行う PermissionsService.RequestPermissions( [JStringToString(TJManifest_permission.JavaClass.ACCESS_FINE_LOCATION)], PermissionRequestResult ); end; end.
4.実行する
507SH(Android One) Android8.1に、32Bitコンパイルしてインストールして実行

Pixel 3a XL Android11に、64Bitコンパイルしてインストールして実行


5.注意点
移動方位はスマホの向きではなく、移動した方位を示します。表示される高度は、WGS84準拠の高度で標高ではありません。
標高に変換するには[ジオイド高]を引く必要があるそうです。
[標高] ≒ [WGS84準拠の高度]-[ジオイド高]
ジオイド高は国土地理院サイト(https://fgd.gsi.go.jp/download/geoid.php)から、登録してログインするとダウンロードできます。
国土地理院のジオイド計算サイト(https://vldb.gsi.go.jp/sokuchi/surveycalc/geoid/calcgh/calc_f.html)で緯度経度を入力しても計算できます。