Android - アプリのインストール、削除、イベントダウンロード(BroadcastReceiverインテントを受け取る)

By JS | Last updated: July 01, 2020

Androidのシステムは、デバイスに他のAppがインストールされたり削除されるブロードキャストイベントを送出します。 アプリがイベントを受け取る関連インテントをBroadcastReceiverに登録をします。

次のような状況には、次のようなActionのインテントがブロードキャストされます。

  • アプリがデバイスに最初にインストールされたとき: android.intent.action.PACKAGE_ADDED
  • アプリが更新される: android.intent.action.PACKAGE_REPLACED
  • アプリ(現在Userのみ)削除される: android.intent.action.PACKAGE_REMOVED
  • アプリがデバイスから完全に削除されたとき: android.intent.action.PACKAGE_FULLY_REMOVED

特に、アプリが更新されると更新されるアプリ、自分には android.intent.action.MY_PACKAGE_REPLACEDが渡されます。 このインテントは、名前のように、他のアプリでは、転送されません。

それぞれのインテントの受信機をどのように登録するかを知ってみましょう。

ACTION_PACKAGE_ADDED:アプリのインストールイベント

Android 8.0のBroadcast Limitations政策的には、暗黙的インテントに渡されるブロードキャストは、AppのAndroidManifest.xmlに登録されたレシーバでは配信されません。これはTarget APIが26以上であるアプリを対象とします。 API 26未満アプリはすべて渡されます。 Target API 26以上のアプリがブロードキャストを受信する Context.registerReceiver() APIを使用して受信機を登録する必要があります。

暗黙的インテントは、次のようにインテントにpackageの情報がないことを意味します。

val intent = Intent(Intent.ACTION_MAIN)

明示的インテントは、次のようにインテントにpackageの情報があることを意味します。

val intent = Intent(Intent.ACTION_MAIN)
intent.`package` = "target.package.name"

ACTION_PACKAGE_ADDEDは、暗黙的インテントに渡されるインテントです。したがってTarget 26以上では、AppのManifestにレシーバを登録すると、インテントが配信されません。 Contextを使用して登録する必要があります。

API 26以上では、レシーバの登録

ACTION_PACKAGE_ADDEDは、API 26以上でContextのみ登録する必要があります。

次のようにレシーバを登録することができます。

val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED)
intentFilter.addDataScheme("package")

val receiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        Log.d("MyReceiver", "onReceive: $intent")
    }
}

context.registerReceiver(receiver, intentFilter)

例では、Receiverは、匿名オブジェクトで生成しました。

そしてIntentFilterを生成する際にschemeを必ず "package"に設定する必要があります。 その理由は、配信されるインテントのdataのschemeが "package"に設定されているからです。そのため、schemeを "package"に設定しない場合は、イベントを受け取ることができません。

次のログは、上記のコードでレシーバを登録してアプリをインストールしたときに出力されるログです。

07-02 21:12:48.021  6331  6331 D MyReceiver: onReceive: Intent { act=android.intent.action.PACKAGE_ADDED dat=package:com.codechacha.myapplication flg=0x4000010 (has extras) }

API 26未満では、レシーバの登録

API 26未満ではContextとManifestを利用して、すべてのレシーバを登録することができます。

次のようにAndroidManifest.xmlにレシーバを登録することができます。

<receiver android:name=".MyReceiver">
    <intent-filter>
        <action android:name="android.intent.action.PACKAGE_ADDED" />
        <data android:scheme="package" />
    </intent-filter>
</receiver>

上記で使用 MyReceiverクラスは、次のように実装しました。

class MyReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        Log.d("MyReceiver", "onReceive: $intent")
    }
}

Contextコードは上で紹介したものと同じです。

ACTION_PACKAGE_REPLACED:アプリの更新イベント

ACTION_PACKAGE_REPLACEDは、アプリが更新されるときに送出さインテントです。このインテントも暗黙的インテントです。

API 26以上では、レシーバの登録

API 26以上では、Contextのみ登録が可能です。

次のように登録することができます。 actionが異なり ACTION_PACKAGE_ADDEDコードと同じです。

val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED)
intentFilter.addDataScheme("package")

val receiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        Log.d("MyReceiver", "onReceive: $intent")
    }
}

API 26未満では、レシーバの登録

次のようにレシーバを登録することができます。

<receiver android:name=".MyReceiver">
    <intent-filter>
        <action android:name="android.intent.action.PACKAGE_REPLACED" />
        <data android:scheme="package" />
    </intent-filter>
</receiver>

アプリのアップデート時に、インテント伝達順

デバイスにアプリが最初にインストールがされると、 ACTION_PACKAGE_ADDEDのみ渡されます。

しかし、アプリが更新されるときは、次のテントが順次配信されます。

1. ACTION_PACKAGE_REMOVED
2. ACTION_PACKAGE_ADDED
3. ACTION_PACKAGE_REPLACED

ACTION_PACKAGE_REMOVEDが配信されている理由は、更新前のバージョンのアプリが削除されたことを意味であり、新しいバージョンがインストールされ、更新された意味でADDEDとREPLACEDインテントが配信されます。

ACTION_PACKAGE_ADDEDインテントにアプリの更新情報の確認

ACTION_PACKAGE_ADDEDインテントは、Intent.EXTRA_REPLACINGという名前のExtraにREPLACEDの情報を持っています。 したがって、 PACKAGE_ADDEDインテントを受けるならPACKAGE_REPLACEDを追加で必要ありません。

次のように ACTION_PACKAGE_ADDEDでReplaced情報を得ることができます。

val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED)
intentFilter.addDataScheme("package")

val receiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val replaced = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
        Log.d("MyReceiver", "onReceive: $intent")
        Log.d("MyReceiver", "Replaced ? $replaced")
    }
}

以下は、最初のインストールされるときのログと更新されるのログです。 更新される Intent.EXTRA_REPLACINGがtrueに渡されます。

// first install
07-02 21:35:20.022  7040  7040 D MyReceiver: onReceive: Intent { act=android.intent.action.PACKAGE_ADDED dat=package:com.codechacha.myapplication flg=0x4000010 (has extras) }
07-02 21:35:20.022  7040  7040 D MyReceiver: Replaced ? false

// upgrade
07-02 21:35:20.667  7040  7040 D MyReceiver: onReceive: Intent { act=android.intent.action.PACKAGE_ADDED dat=package:com.codechacha.myapplication flg=0x4000010 (has extras) }
07-02 21:35:20.667  7040  7040 D MyReceiver: Replaced ? true

ACTION_PACKAGE_REMOVED:アプリの削除イベント

ACTION_PACKAGE_REMOVEDはアプリが削除されるときに送出さインテントであり、暗黙的インテントに渡されます。

AndroidはMulti userをサポートし、それぞれのUserにアプリがインストールされることがあります。 このインテントは、いくつかのUserでアプリが削除されるときに送出されます。このインテントを受けて、デバイスから完全にアプリが削除されたことを意味はしません。

デバイスから(すべてのMulti userで)アプリが完全に削除されたときは ACTION_PACKAGE_FULLY_REMOVEDインテントが配信されます。

API 26以上では、レシーバの登録

API 26以上のアプリは、次のようにレシーバを登録することができます。

val intentFilter = IntentFilter()
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED)
intentFilter.addDataScheme("package")

val receiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Log.d("MyReceiver", "onReceive: $intent")
    }
}

context.registerReceiver(receiver, intentFilter)

API 26未満では、レシーバの登録

API 26未満アプリは、次のようにインテントを渡すことができます。

<receiver android:name=".MyReceiver">
    <intent-filter>
        <action android:name="android.intent.action.PACKAGE_REMOVED" />
        <data android:scheme="package" />
    </intent-filter>
</receiver>

ACTION_PACKAGE_FULLY_REMOVED:デバイス全体でアプリの削除

ACTION_PACKAGE_FULLY_REMOVEDは、デバイス全体でアプリが削除されるときに送出されるイベントです。 暗黙的なイベントであるが、このインテントは、例外的にManifestに登録することができます。

例外的にいくつかの暗黙的インテントは、Manifestにレシーバの登録を許可します。 Implicit Broadcast Exceptionsを見ればどのようなインテントが例外なのか知ることができます。

したがって、Target APIレベルの区別なくManifestとContextに登録可能です。

他のインテントと同様の形式でManifestにレシーバを登録することができます。

<receiver android:name=".MyReceiver">
    <intent-filter>
        <action android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
        <data android:scheme="package" />
    </intent-filter>
</receiver>

Output:

07-02 21:46:31.388  7845  7845 D MyReceiver: onReceive: Intent { act=android.intent.action.PACKAGE_FULLY_REMOVED dat=package:com.codechacha.myapplication flg=0x5000010 cmp=com.codechacha.packageintent/.MyReceiver (has extras) }

Contextに登録することも、他のインテントの例と同様です。

ACTION_MY_PACKAGE_REPLACED:アプリ自分に更新イベント伝達

ACTION_MY_PACKAGE_REPLACEDインテントは、例えばcom.codechacha.myapplicationというアプリを更新するときに com.codechacha.myapplicationアプリに伝達するインテントです。

このインテントは、明示的インテントで、ManifestとContextの両方レシーバー登録が可能です。しかし、更新されアプリ自身は終了するので、Contextにされません。

次のManifestにレシーバを登録することができます。配信されるインテントには、scheme情報がないため、IntentFilterもschemeを設定しないでください。

<receiver android:name=".MyReceiver">
    <intent-filter>
        <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
    </intent-filter>
</receiver>

Related Posts

codechachaCopyright ©2019 codechacha