緯度,経度,高度,移動速度,移動方向を取得する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)で緯度経度を入力しても計算できます。
