Androidの開発に携わって、ぶつかった問題。
Androidアプリは自分で自分がアンインストールされることを検知できません。
パッケージが削除されるときに通知されるPACKAGE_REMOVEDというイベントがありますが、これを受信できるのは他のアプリです。
Javaで作るのでデストラクタがある訳でもなく、アンインストール時に解放したい値、初期化したい値があっても何もできないのです。
ただし、プリインストールアプリのアップデートの削除(アンインストール)を行う場合は、プリインストールアプリ側(古い方)でMY_PACKAGE_REPLACEDを受信できることがありました。仕事でこの挙動を何度も実機検証した結果、体感では9割くらいの確率でした。
方法はマニフェストファイルにMY_PACKAGE_REPLACEDを登録して、BroadcastReceiverを継承したクラスで受信するだけです。
これは、Android DevelopersのAPIリファレンスでは「既存のアプリケーションの上に新しいバージョンがインストールされた」と説明されているため、当時はアップデートを削除した時にも受信する理由が分かりませんでした。
2026年追記: なぜアップデート削除でもMY_PACKAGE_REPLACEDが来るのか
改めてAndroid Open Source Project(AOSP)のPackageManagerの実装を確認すると、これは偶然の挙動ではありませんでした。
アップデート済みのシステムアプリ(プリインストールアプリ)の更新版を削除すると、システム領域に残っている旧バージョンが再び有効になります。AOSPのPackageManagerServiceでは、この場合にPACKAGE_ADDED、PACKAGE_REPLACEDに続いてMY_PACKAGE_REPLACEDを対象アプリへ送る処理が明示的に入っています。つまりAndroid内部では、更新版の削除によって旧システムアプリへ戻る処理も「パッケージの置き換え」として扱われています。
・Android Developers: ACTION_MY_PACKAGE_REPLACED
・AOSP: PackageManagerService
一方、仕事で何度も実機検証した結果としての「体感9割くらい」という再現率のばらつきまでは、この実装だけでは説明し切れません。Androidのバージョン、端末メーカー側の実装、プロセスやパッケージの状態など、コードから一意に特定できない条件が関係していた可能性があります。少なくとも、MY_PACKAGE_REPLACEDが送信されること自体には実装上の根拠がありますが、端末上の実際の受信まで100%保証できる挙動として扱うべきではありません。だからこそ「必ずこれを受信して後処理できる」という前提で仕様を組むのは避けた方がよい、という当時の結論は変わりません。
アプリのアンインストール時に何かしようというのは基本的に諦めましょう。
代替方法としては、
・アンインストール時は諦めて、プリインストールアプリの場合はアプリ更新時に通知されるMY_PACKAGE_REPLACEDを受け取るか、普通のアプリの場合はPACKAGE_ADDEDを受け取る。
・アンインストール時は諦めて、プリインストールアプリの場合はアンインストール後に再起動する手順を含めることとして、起動時に通知されるBOOT_COMPLETEDを受信する。
・どうしてもアンインストール時に行いたいのであれば、他のアプリを用意してアンインストール時に通知されるPACKAGE_REMOVEDを受信する。
くれぐれもAndroidアプリでアンインストール時に何かしようなんて仕様を書かないように!!(ダジャレじゃない!!)
コメント