Android 8.0 暗黙的ブロードキャストを受信できなくなったときの対処方法
Android 8.0 から、一部のブロードキャストを除きマニフェストでブロードキャストレシーバーを登録し、暗黙的ブロードキャストを受信できなくなりました。
Android 8.0に対応する必要がある場合、なんらかの変更を行う必要があります。
その変更方法について詳しく見ていきます。
スポンサーリンク
もくじ
なぜマニフェストの暗黙的ブロードキャストのレシーバーが制限されるようになったか
暗黙的ブロードキャストは、そのブロードキャストに対するブロードキャストレシーバーが登録されているアプリすべてが受信します。
複数のアプリがたくさんのブロードキャストレシーバーを登録していると、ブロードキャストの送信のたびにレシーバーを作動させる必要があり、システムのリソースを消費します。マニフェストに登録したブロードキャストレシーバーはアプリが起動していても、起動していなくてもブロードキャストを受信するためです。
電池の持ちを良くしたり、パフォーマンスを良くするためには不要なブロードキャストレシーバーによる受信を減らす必要があるため、マニフェストに記載したブロードキャストレシーバーは制限されるようになりました。
ブロードキャストには、次のような区別ができます。
- 「暗黙的」または「明示的」なブロードキャスト
- 「署名パーミッションが必要」または「不要」なブロードキャスト
これらの組み合わせでブロードキャストレシーバーで受信できるかを次の表で表します。
マニフェストの ブロードキャストレシーバー登録 |
署名パーミッション (ブロードキャスト) |
暗黙的 / 明示的 (ブロードキャスト) |
有効 | 必要 | 暗黙的 |
有効 | 必要 | 明示的 |
無効(一部例外あり) | 不要 | 暗黙的 |
有効 | 不要 | 明示的 |
明示的ブロードキャストと署名パーミッションが必要なブロードキャストは、端末上のすべてのアプリではなく、特定のアプリに対してのみブロードキャストを送信します。このため、マニフェストのブロードキャストレシーバーの登録が制限されません。
ブロードキャストの送信先が明示的に決まるためシステムリソースの消費の問題は起きにくいということです。
詳細は、公式:ブロードキャストの制限事項を参照してください。
暗黙的ブロードキャストとは
ブロードキャストは、送信と受信の2つが重要な要素です。それぞれについて説明します。
暗黙的ブロードキャストを送信する
Context#sendBroadcast()を使用して、暗黙的インテントを送信します。
インテントに送信先を明示的に指定しないと暗黙的インテントとなり、それをブロードキャストで送信すると暗黙的なブロードキャストになります。
1 2 3 4 |
Intent intent = new Intent(); // 明示的なアクティビティやサービスなどを指定しません。 intent.setAction("pkg.example.broadcast.MY_BROADCAST"); intent.putExtra("exampleData", "Example content."); sendBroadcast(intent); // 暗黙的インテントをブロードキャストで送信します。 |
なお、同一アプリ内のローカルブロードキャストを送信する場合はLocalBroadcastManager#sendBroadcast()を使用してください。
暗黙的ブロードキャストを受信する(マニフェストに宣言する方法)
AndroidManifest.xmlにブロードキャストレシーバーを宣言します。
1 2 3 4 5 6 7 8 9 10 |
<manifest ...> ... <application ...> ... <receiver android:name=".MyReceiver"> <intent-filter> <action android:name="pkg.example.broadcast.MY_BROADCAST"/> </intent-filter> </receiver> ... |
BroadcastReceiverのサブクラスのMyReceiverクラスを作成します。
1 2 3 4 5 6 7 8 9 10 11 |
public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { case "pkg.example.broadcast.MY_BROADCAST": // ここで受信したブロードキャストに対する処理を実行 break; } } } |
一部ブロードキャストはマニフェストに宣言する方法では受信できません。プログラムで登録する方法で受信する必要があります。
暗黙的ブロードキャストを受信する(プログラムで登録する方法)
BroadcastReceiverのインスタンスとIntentFilterを生成し、Context#registerReceiver()で登録します。
1 2 3 |
BroadcastReceiver receiver = new MyReceiver(); IntentFilter filter = new IntentFilter("pkg.example.broadcast.MY_BROADCAST"); context.registerReceiver(receiver, filter); |
マニフェストで登録する方法をプログラムでそのまま記載していると考えられますね。
ブロードキャストレシーバーのサブクラスは、マニフェストで登録する方法のMyReceiverを使用しています。
なお、同一アプリ内のローカルブロードキャストを受信する場合はLocalBroadcastManager#registerReceiver()を使用してください。
明示的ブロードキャストとは
暗黙的なブロードキャストと同様に明示的なブロードキャストを説明します。
明示的ブロードキャストを送信する
Context#sendBroadcast()を使用して、明示的インテントを送信します。
インテントに送信先を明示的に指定すると明示的インテントとなり、それをブロードキャストで送信すると明示的なブロードキャストになります。
1 2 3 4 |
Intent intent = new Intent(context, MyReceiver.class); // ここで、明示的に特定のアクティビティやサービスなどを指定します。通知先のブロードキャストレシーバーを指定してください。 intent.setAction("pkg.example.broadcast.MY_BROADCAST"); intent.putExtra("exampleData", "Example content."); sendBroadcast(intent); // 明示的インテントをブロードキャストで送信します。 |
なお、同一アプリ内のローカルブロードキャストを送信する場合はLocalBroadcastManager#sendBroadcast()を使用してください。
明示的ブロードキャストを受信する(マニフェストに宣言する方法)
AndroidManifest.xmlにブロードキャストレシーバーを宣言します。
1 2 3 4 5 6 |
<manifest ...> ... <application ...> ... <receiver android:name=".MyReceiver" /> ... |
明示的ブロードキャストで「MyReceiver.class」を指定したため、インテントフィルターの設定が不要で、常に送信されます。
その他のブロードキャストの受信方法は、暗黙的なブロードキャストと同様です。
署名パーミッションが必要なブロードキャストとは
ブロードキャストはパーミッションによる制限を行うことができます。
このパーミッションのタイプに「署名」があり、それを使用することで署名パーミッションを必要とするブロードキャストになります。
マニフェストのandroid:protectionLevelの値「signature」が署名パーミッションです。同一の証明書を持つアプリで送信/受信可能なブロードキャストです。
署名パーミッションが必要なブロードキャストを送信する
Context#sendBroadcast()を使用して、暗黙的または明示的インテントを送信する際に、署名パーミッションを指定します。
1 2 3 4 |
Intent intent = new Intent(); intent.setAction("pkg.example.broadcast.MY_BROADCAST"); intent.putExtra("exampleData", "Example content."); sendBroadcast(intent, "pkg.example.broadcast.permission.MY_BROADCAST"); // 署名パーミッションを指定します。 |
署名パーミッションが必要なブロードキャストを受信する(マニフェストに宣言する方法)
署名パーミッションの宣言と、レシーバーにもパーミッションを宣言します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<manifest ...> <permission android:name="pkg.example.broadcast.permission.MY_BROADCAST_SIGNATURE" android:label="my_permission" android:protectionLevel="signature"></permission> ... <uses-permission android:name="pkg.example.broadcast.permission.MY_BROADCAST" android:protectionLevel="signature" /> ... <application ...> ... <receiver android:name=".MyReceiver" android:permission="pkg.example.broadcast.permission.MY_BROADCAST"> <intent-filter> <action android:name="pkg.example.broadcast.MY_BROADCAST"/> </intent-filter> </receiver> ... |
BroadcastReceiverのサブクラスのMyReceiverクラスを作成します。
1 2 3 4 5 6 7 8 9 10 11 |
public class MyReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { case "pkg.example.broadcast.MY_BROADCAST": // ここで受信したブロードキャストに対する処理を実行 break; } } } |
一部ブロードキャストはマニフェストに宣言する方法では受信できません。プログラムで登録する方法で受信する必要があります。
署名パーミッションが必要なブロードキャストを受信する(プログラムで登録する方法)
マニフェストにパーミッションの宣言が必要です。
1 2 3 4 5 6 7 8 |
<manifest ...> <permission android:name="pkg.example.broadcast.permission.MY_BROADCAST_SIGNATURE" android:label="my_permission" android:protectionLevel="signature"></permission> ... <uses-permission android:name="pkg.example.broadcast.permission.MY_BROADCAST" android:protectionLevel="signature" /> ... |
BroadcastReceiverのインスタンスとIntentFilterを生成し、Context#registerReceiver()で登録します。
1 2 3 |
BroadcastReceiver receiver = new MyReceiver(); IntentFilter filter = new IntentFilter("pkg.example.broadcast.MY_BROADCAST"); context.registerReceiver(receiver, filter, "pkg.example.broadcast.permission.MY_BROADCAST", null); // 署名パーミッションを指定します。 |
マニフェストで登録する方法をプログラムでそのまま記載していると考えられますね。
ブロードキャストレシーバーのサブクラスは、マニフェストで登録する方法のMyReceiverを使用しています。
受信可能な暗黙的ブロードキャスト
Android 8.0 からは、暗黙的ブロードキャストはブロードキャストレシーバーで受信することができなくなりました。しかし、一部の暗黙的ブロードキャストは受信することができます。
これを列挙します。
ACTION_LOCKED_BOOT_COMPLETED
,ACTION_BOOT_COMPLETED
ACTION_USER_INITIALIZE
,"android.intent.action.USER_ADDED"
,"android.intent.action.USER_REMOVED"
"android.intent.action.TIME_SET"
,ACTION_TIMEZONE_CHANGED
,ACTION_NEXT_ALARM_CLOCK_CHANGED
ACTION_USB_ACCESSORY_ATTACHED
,ACTION_USB_ACCESSORY_DETACHED
,ACTION_USB_DEVICE_ATTACHED
,ACTION_USB_DEVICE_DETACHED
ACTION_CONNECTION_STATE_CHANGED
,ACTION_CONNECTION_STATE_CHANGED
,ACTION_ACL_CONNECTED
,ACTION_ACL_DISCONNECTED
ACTION_CARRIER_CONFIG_CHANGED
,TelephonyIntents.ACTION_*_SUBSCRIPTION_CHANGED
,"TelephonyIntents.SECRET_CODE_ACTION"
,ACTION_PHONE_STATE_CHANGED
,ACTION_PHONE_ACCOUNT_REGISTERED
,ACTION_PHONE_ACCOUNT_UNREGISTERED
LOGIN_ACCOUNTS_CHANGED_ACTION
ACTION_PACKAGE_DATA_CLEARED
ACTION_PACKAGE_FULLY_REMOVED
ACTION_NEW_OUTGOING_CALL
ACTION_DEVICE_OWNER_CHANGED
ACTION_EVENT_REMINDER
ACTION_MEDIA_MOUNTED
,ACTION_MEDIA_CHECKING
,ACTION_MEDIA_UNMOUNTED
,ACTION_MEDIA_EJECT
,ACTION_MEDIA_UNMOUNTABLE
,ACTION_MEDIA_REMOVED
,ACTION_MEDIA_BAD_REMOVAL
SMS_RECEIVED_ACTION
,WAP_PUSH_RECEIVED_ACTION
詳細は、公式のImplicit Broadcast Exceptionsを参照してください。
暗黙的なブロードキャストの対処方法
暗黙的ブロードキャストであっても受信可能なブロードキャストはそのままとしてください。
これら以外で、受信可能でなくなった暗黙的ブロードキャストに対するマニフェストに記載したブロードキャストレシーバーは次のような対処が必要です。
※Context#registerReceiver()を使用したプログラムで登録する方法は受信可能です。
- マニフェストのブロードキャストレシーバーをContext#registerReceiver()を使用したプログラムに変える
- 暗黙的ブロードキャストを明示的ブロードキャストに変える
- 暗黙的ブロードキャストを署名パーミッションが必要なブロードキャストに変える
- JobScheduler ジョブを使用する
- あきらめる
マニフェストのブロードキャストレシーバーをContext#registerReceiver()を使用したプログラムに変える
マニフェストにブロードキャストレシーバーを記載しなくても、アプリ起動時にContext#registerReceiver()でブロードキャストレシーバーを登録できるかを検討してください。
アプリが動作しているときに暗黙的ブロードキャストを受信する場合は、この方法で対処可能です。
暗黙的ブロードキャストを明示的ブロードキャストに変える
自作アプリでブロードキャストを送信している場合、明示的ブロードキャストに変更できないか検討してください。
明示的に送信先が特定できる場合はこの方法で対処可能です。
暗黙的ブロードキャストを署名パーミッションが必要なブロードキャストに変える
明示的ブロードキャストと同様に、自作アプリでブロードキャストを送信している場合の対処方法です。
明示的ブロードキャストにすれば問題ないので、あえてこちらの方法で対応する必要はないです。
JobScheduler ジョブを使用する
JobSchedulerを使用して、特定の条件になったらジョブを実行します。
このジョブの実行条件に、暗黙的ブロードキャストの条件と同じ条件を設定できる場合は、JobSchedulerで置き換えることができます。
JobSchedulerとは
JobSchedulerは、Android 5.0から利用可能になりました。大きな変更点として、Android 7.0 でContentProviderの変更をトリガーにジョブを実行することが可能になっています。
JobSchedulerを使用するには、ジョブを登録し、ネットワークとタイミングの条件を設定します。すると、システムが適切なタイミングでジョブの実行をスケジュールします。
ジョブの実行条件は、JobInfoで設定します。実行条件の詳細は、JobInfoを生成するJobInfo.Builderのsetterを参照してください。
あきらめる
他の作者のアプリからの暗黙的ブロードキャストやシステムの暗黙的ブロードキャストなどは受信できません。
受信をきっかけに処理していた場合は、連携できないため他の方法で機能を実現するか機能自体を廃止する対応しかない可能性があります。