位置情報を取得する方法
Androidで位置情報を取得する方法は複数用意されていますが,代表的なものはFusedLocationProviderClientを利用した位置取得です.GoogleApiの一貫として提供されていますので,play-services-locationライブラリを有効にする必要があります.
ライブラリの有効化,及び,その基本的な手法はその他のサイトで豊富に説明されていると思いますので割愛します.(FusedLocationProviderClientのrequestLocationUpdatesに必要な引数を渡すだけで位置情報を取得できます.)
ApplicationがForegroundでない場合にも位置情報を取得したい
自分が実装する際に詰まったのがこの部分でした.ApplicationがForegroundの場合には,Activityに処理を書いておけば位置情報を取得してくれますが,ApplicationがBackgroundになった場合にも継続して位置情報を取得するにはどうすればよいのか?
Serviceを利用すれば継続して位置情報を取得してくれるのは想像できますが,何点か注意点がありました.
(Background) Serviceには位置情報取得制限がある
Android8.0(API Level26)からはBackground Serviceによる位置情報取得に制限がかかります.FusedLocationProviderClientの場合,BackGroundServiceでの位置情報取得は一時間に数回に制限されます.以下が公式ドキュメントです.
プライバシーの規約が厳しくなってきた結果だと思いますが,自分の場合,ApplicationがBackgroundでも位置情報を取得したいアプリを開発していたので,これではどうにもなりません.
Foreground Serviceを利用する
結論として,ApplicationがBackgroundな状態でも継続して高頻度で位置情報を取得するためにはForeground Serviceを利用します.
Foreground ServiceはNotificationへの表示が義務付けられますが,仕方ないですね.Foreground Serviceを利用する流れは以下になります.
①Serviceを継承したクラスを作製する
public class ForegroundService extends Service
②Manifest.xmlにForegroundのPermissionとserviceのタイプ指定を追加する
Foregroundのpermissionは Android 9 (API level 28)
service typeの指定は Android 10 (API level 29) 以上で必須です.
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <application> <service android:name=".ForegroundService" android:foregroundServiceType="location"/> </application>
③Notification,NotificationChannelを作製し,NotificationManagerに登録する
oNotificationChannel = new NotificationChannel(SERVICE_NOTIFICATION_CHANNEL_ID, getText(R.string.notificationTitle), NotificationManager.IMPORTANCE_DEFAULT); oNotification = new Notification.Builder(this, SERVICE_NOTIFICATION_CHANNEL_ID) .setContentTitle(getText(R.string.notificationTitle)) .setContentText(getText(R.string.notificationContent)) .setSmallIcon(R.drawable.icon) .build(); NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE); manager.createNotificationChannel(oNotificationChannel);
④Foreground Serviceを明示的に開始する.
@Override public void onCreate() { super.onCreate(); startForeground(1, oNotification); }
startForeground()はこのServiceがstartService()された後に即座(5msec以内)に呼び出さないとErrorが発生しますので,onCreate()内に書くことを推奨します.
追加で
以上でForegroundServiceの作成は完了です.後は通常の位置情報取得コードをこのService内に追加すれば完了です.なお,NotificationはTaskManagerからApplicationを停止された場合には自動的に除去されませんので,onTaskRemoved()をOverrideしてstopForeground()を呼び出す必要があります.
@Override public void onTaskRemoved(Intent rootIntent) { super.onTaskRemoved(rootIntent); stopForeground(true); }
最後に
初めてAndroidアプリの開発をしていますが即座に動作を自分のスマホで確認できるので面白いですね.時代はKotlinらしいですが,普段の業務がJavaなので勉強も兼ねてJavaで実装しています.もし間違い等ありましたらコメントいただけると幸いです.