何が起きたか
ADB経由でテストデバイスに新しいビルドをプッシュしようとしたら、こんなエラーにぶつかった:
adb install app-debug.apk
Failed
INSTALL_FAILED_UPDATE_INCOMPATIBLE: Package signatures do not match previously installed version; ignoring!
アプリはすでに端末に入っていた — Play Storeからインストールされたか、別のキーストアで署名されたものだ。新しいAPKの署名が既存のものと一致しないため、Androidは上書きを拒否する。これはバグではなくセキュリティチェックだ。Androidは正しく動作している。
なぜこうなるのか
このエラーを引き起こすシナリオは4つあり、そのうちのひとつがあなたの状況に当てはまるはずだ:
- 端末にはリリースキーストアで署名されたプロダクションビルドが入っていて、デバッグビルドをプッシュしようとしている。
- 古いキーストアを紛失したため新しいキーストアを生成した — パッケージ名は同じだが、署名はまったく別物になっている。
- チームメンバーが自分のローカルの
debug.keystoreで署名した。あなたのものとは異なる。開発マシンごとに独自のキーストアが生成される。 - インストール済みのバージョンはPlay Store経由のもの。Google Play App SigningはGoogleのキーでAPKを再署名する。ローカルのキーストアはそれと一致しない。
初回インストール時に、Androidは署名証明書のフィンガープリントを記録する。すべてのアップデートはそれと完全に一致しなければならない — 例外なし。
デバッグ — 署名の不一致を確認する
何かを削除する前に、60秒かけて本当に署名の不一致が原因かどうかを確認しよう。ダウンロードの破損や誤ったデバイスでも似たエラーが出ることがある。
インストール済みアプリの署名を確認する
# パッケージ名がわからない場合はまず調べる
adb shell pm list packages | grep yourappname
# インストール済みパッケージの署名情報を表示する
adb shell dumpsys package com.example.yourapp | grep -A5 "signatures"
インストールしようとしているAPKを確認する
# apksignerを使う(Android SDK build-toolsに付属)
apksigner verify --print-certs app-debug.apk
# またはkeytoolを使う
keytool -printcert -jarfile app-debug.apk
SHA-256フィンガープリントを比較する。AB:CD:12:34:...のような形式 — 16進数2桁のペアが32組並ぶ。値が違えば不一致が確定だ。以下から解決策を選ぼう。
解決策1 — アンインストールしてから再インストール(最も一般的な方法)
古いバージョンを削除して、新しくインストールする。それだけだ。
# データを保持したままアンインストール(まずこれを試す)
adb uninstall -k com.example.yourapp
# それが失敗したら、完全アンインストール(アプリデータもすべて削除される)
adb uninstall com.example.yourapp
# 新しいAPKをインストールする
adb install app-debug.apk
署名変更をまたいでアプリデータを保持したい?Androidは意図的にそれをブロックしている。データディレクトリを手動でコピーするにはroot権限が必要だ — ほとんどのデバッグシナリオでは割に合わない。
replaceフラグを使ってインストールする(署名が一致する場合のみ有効)
# -r は既存アプリを置き換える — 署名の一致が依然として必要
adb install -r app-debug.apk
# 古いAndroidバージョンでは、バージョンダウングレードを許可するために -d を追加する
adb install -r -d app-debug.apk
解決策2 — デバイスから直接アンインストールする
ADB接続がない?手動でやろう:
- 設定 → アプリ → 対象アプリを見つける → アンインストール
- またはアプリアイコンを長押し → アプリ情報 → アンインストール
その後、ADBまたはファイルマネージャーでAPKをサイドロードする。
解決策3 — チーム全体でひとつのデバッグキーストアを共有する
チームプロジェクトの根本原因を解決する方法だ。Androidはマシンごとに固有のdebug.keystoreを自動生成する。マシンが異なれば署名も異なり、共有テストデバイスで必ず競合が発生する。
解決策は:キーストアをひとつ選んで全員に共有する。
# デフォルトのデバッグキーストアの場所
# macOS/Linux
~/.android/debug.keystore
# Windows
%USERPROFILE%\.android\debug.keystore
リポジトリにコミットしても構わない — デバッグビルドにしか使わないため、セキュリティリスクにはならない — またはシークレットマネージャーで配布する。各開発者はローカルのdebug.keystoreを共有のものに置き換える。これで全マシンのフィンガープリントが一致する。
任意のキーストアのフィンガープリントを確認するには:
keytool -list -v -keystore debug.keystore -alias androiddebugkey -storepass android -keypass android
解決策4 — Play Store / App Signing登録済みアプリ
Google Play App SigningはGoogleのキーでAPKを再署名してから配布する。ローカルのキーストアはそのキーとは永遠に一致しない。それが現実だ。
3つの回避策がある:
- Play Storeバージョンをアンインストールし、ローカルで署名したビルドをインストールする。
- デバッグビルドにパッケージ名のサフィックスを追加する(例:
com.example.yourapp.debug)。同じデバイスに両バージョンが共存でき、競合はゼロになる。 - Play ConsoleのInternalテストトラックを使って、実際のPlay署名済みAPKをテスターに配布する。
build.gradleでデバッグ用アプリケーションIDサフィックスを設定する
android {
buildTypes {
debug {
applicationIdSuffix ".debug"
versionNameSuffix "-debug"
}
}
}
これでデバッグとリリースは完全に別々のアプリとして扱われる。共有状態も署名の競合も、一切発生しない。
確認
# 新しいアプリが正しくインストールされたか確認する
adb shell pm list packages | grep yourappname
# インストールされているバージョンを確認する
adb shell dumpsys package com.example.yourapp | grep versionName
# 起動する
adb shell monkey -p com.example.yourapp -c android.intent.category.LAUNCHER 1
アプリがクラッシュせずに起動したら完了だ。
得られた教訓
- Play Storeへのリリースが予定されているプロジェクトでは、最初から
applicationIdSuffix ".debug"を設定しておこう。5分の設定で、後々の署名競合による何時間もの無駄を省ける。 - 共有の
debug.keystoreをリポジトリにコミットしよう。マシンごとのキーストアは、チームのテストワークフローを静かに壊す元凶だ。 - リリースキーストアは少なくとも2か所にバックアップしておこう。紛失すると、既存のPlay Storeリスティングにアップデートを公開できなくなる — 評価もレビューもゼロの全く新しいアプリを公開し直すことになる。
- 共有テストデバイスでは、最初にアンインストールすることを習慣にしよう。問題が起きてからではなく、インストール作業のたびに毎回実行すること。

