Xamarin.Formsでバックグラウンド(非アクティブ時でも)で位置情報を取得し続ける(Android編)
Android8以上でも非アクティブな状態で処理を継続する手段としてForeground Serviceがある
これを使ってカウントアップを行う簡単なサンプルアプリを作った.
さて,バックグラウンドで数を1ずつ増やすタスクを実行しているわけですが,このタスクをGPSを取得するものに置き換えればよいということ.
引き続き,前回と同じリポジトリにブランチを足して変更を加える.
GetLocation
というブランチにした.
位置情報の取得
Xamarin.Essentialsには位置情報を取得するAPIが用意されている.
それを使ってTaskCounterクラス内のRunCounterメソッドを書き換える.
public async Task RunCounter(CancellationToken token) { //GPSの精度をHighに ←これと var request = new GeolocationRequest(GeolocationAccuracy.High); await Task.Run(async () => { for (long i = 0; i < long.MaxValue; i++) { token.ThrowIfCancellationRequested(); await Task.Delay(1000); //ここから //位置情報取得 var location = await Geolocation.GetLocationAsync(request); var message = new TickedMessage { Message = $"Count : {i.ToString()}, Lat = {location.Latitude}, Lon = {location.Longitude}" }; //ここまで MainThread.BeginInvokeOnMainThread(() => { MessagingCenter.Send<TickedMessage>(message, nameof(TickedMessage)); }); } }, token); }
こんな感じで1秒毎に位置情報を取得するタスクが完成.
位置情報を拾う部分はXamarin.EssentialsのAPIを使って以下のように書く.
var request = new GeolocationRequest(GeolocationAccuracy.High);
var location = await Geolocation.GetLocationAsync(request);
位置情報取得の許可
位置情報の取得にはPermission(許可)が必要なので,これをユーザーに確認する処理も書く.
これもXamarin.Essentials(1.5以上)のPermissionsというAPIを使う.
バックグラウンドタスクが実行される前に,許可を得たいので,タスク開始ボタンが押されたときに許可を得る.
開始ボタンを押したときのイベントハンドラは以下のようになる.
private async void Button_LongRunningTaskStart_Clicked(object sender, EventArgs e) { //位置情報取得の許可状態を確認 var status = await Permissions.CheckStatusAsync<Permissions.LocationAlways>(); if (status != PermissionStatus.Granted) { //許可されていなかった場合はユーザーに確認する status = await Permissions.RequestAsync<Permissions.LocationAlways>(); //ユーザーが拒否した場合は(´・ω・`) if (status != PermissionStatus.Granted) return; } var message = new StartLongRunningTaskMessage(); MessagingCenter.Send(message, nameof(StartLongRunningTaskMessage)); }
AndroidManifestにも以下の2つのPermissionにチェックをつけておく.
もしくはAndroidManifest.xmlに追加する.
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.xfforegroundservicepractice" android:installLocation="auto"> <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" /> <application android:label="XFForegroundServicePractice.Android"></application> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> </manifest>
実行結果
開始ボタンを押すと,位置情報の取得に関する許可を求めるダイアログが表示されるので,「Allow all the time」を選択.
このように一定間隔で現在地の経緯度が更新されることが確認できる.
ちなみに,Xamarin.Essentialsで位置情報を取得するたびに,Androidの位置情報マークが点滅するので少し鬱陶しいかもしない.
他のアプリを利用中でも動き続けるので,ランニングや散歩などを記録するアプリなどに使える.
ソースコード
GetLocation
ブランチが今回のコード
注意
頻繁な位置情報の取得はバッテリーの消費が激しいので,取得間隔を適宜変更する必要がある.