はじめに
Googleから最新のAPIレベルにターゲットしていることが義務付けられました。ついに来ましたね。
詳しくは下記を確認してください。
今後の Google Play でのアプリのセキュリティおよびパフォーマンスの改善について
こちらを抜粋すると下記になります。
1 2 3 |
2018 年 8 月: 新しいアプリはAPIレベル 26(Android 8.0)以降が必須 2018 年 11 月: 既存のアプリのアップデートでもAPIレベル 26が必須 2019 年以降: 毎年、targetSdkVersion の要件が上がる。 |
今回は私が担当している位置情報を利用するアプリで対応した内容について紹介したいと思います。
APIレベル26にした際に発生した対応が必要な症状は下記の3つです。
1 2 3 |
・Serviceを今まで通りの startSarviceで呼び出すとクラッシュする。 ・バックグラウンドで位置情報を取得しようとしてもほぼ出来ない。 ・通知が表示されない。 |
それぞれについて内容と、解決策について書きたいと思います。
Serviceを今まで通りの startServiceで呼び出すとクラッシュする。
アプリが裏に回っている時でも何かの処理を継続させたい時、または何らかのトリガーでアプリを裏で動かしたい時などにServiceを使うと思います。
こちら今までは startService を使えばServiceを動かせたのですが、26からはクラッシュします。
startServiceの代わりに、startForegroundServiceを使って呼び出す必要があり、これでServiceを起動後5秒以内にService側で、startForeground を使用する必要があります。
Service側でstartForegroundを利用する際、Notificationを指定する必要があります。つまりServiceを裏で起動した場合通知を表示して、Serviceと紐付ける必要があります。
このアプリはバックグラウンドで何か処理をしているということをユーザに伝える必要があります。そのためServiceでユーザが知らない間に実行することが困難になったということです。
詳しいことはこちらをご覧下さい。 バックグラウンド実行制限 Android Developers
※こちらのリンクに書いてありますが、もしやりたいことがFCM(プッシュ通知)で出来るならそちらに変えたほうが良いです。
バックグラウンドで位置情報を取得しようとしてもほぼ出来ない。
Android8では、アプリがバックグラウンドの時に LocationManager や Fused Location Providerで位置情報を取得に制限がかかり、1時間に数回しか取得出来なくなります。
今回のアプリでは定期的に位置情報を取って、その場所に合うものを案内するもので、この取得頻度では要件を満たせません。
こちらを解決する場合は、一つ目に書いた方法(startForeground)で、位置情報を取得するServiceに通知を紐付ければ従来通りの頻度で位置情報が取得できました。
これまたGoogleのドキュメントに書いてあるので詳しいことは下記をご確認下さい。
バックグラウンド位置情報の制限 Android Developers
通知が表示されない。
アプリではローカル通知を利用しているのですが、Android8では通知が表示されません。
Android8では通知チャンネルというものが追加されています。通知をまとめるグループのようなものです。
通知チャンネルに通知の設定をしておけばユーザが通知チャンネル毎に通知の許可などを行えます。
具体的な実装方法は下記です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationManager manager = (NotificationManager) getApplicationContext() .getSystemService(Context.NOTIFICATION_SERVICE); NotificationChannel channel = new NotificationChannel( "channel_id_001", // 通知チャンネルID "Sample Notificaiton Channel", // 通知チャンネル名 NotificationManager.IMPORTANCE_HIGH // 優先度 ); channel.setDescription("サンプル通知チャンネル"); // 通知時のライトの色 channel.setLightColor(Color.GREEN); // ロック画面で通知を表示するかどうか channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); manager.createNotificationChannel(channel); } |
そして、実際に通知を作成する際、上記で設定した通知チャンネルIDを指定します。
1 |
Notification.Builder builder = new Notification.Builder(context, "channel_id_001"); |
これで今まで通り通知を表示することが出来ます。※Android8未満に関しては今まで通りに記述する必要があるので処理を分けて下さい。
最後に
Android8に対応する時、Googleのドキュメントがすごい丁寧に書いてあって、ほぼそれで事足りて助かりました。
Android6( APIレベル23 )以降にするとパーミッション周りでユーザに許諾を取らないといけなかったり、8にするとServiceの処理は通知表示しないといけなかったりで、ビルドターゲットを意図的に上げないアプリも多いのではと個人的には思ってます。ただ手間は手間ですがエンジニアとしてはこうした流れは素直に受け入れて、どんどん良いアプリを作っていきたい所と思います。
読んでいただきありがとうございました。