Chuyện gì xảy ra
Thử đẩy bản build mới lên thiết bị test qua ADB và gặp ngay lỗi này:
adb install app-debug.apk
Failed
INSTALL_FAILED_UPDATE_INCOMPATIBLE: Package signatures do not match previously installed version; ignoring!
App đã có sẵn trên điện thoại — được cài từ Play Store hoặc ký bằng keystore khác. Android từ chối ghi đè vì chữ ký trên APK mới không khớp với bản đang cài. Đây là kiểm tra bảo mật, không phải lỗi. Android đang hoạt động đúng như thiết kế.
Tại sao lỗi này xảy ra
Có bốn tình huống dẫn đến lỗi này, và gần như chắc chắn một trong số đó đúng với trường hợp của bạn:
- Thiết bị đang có bản production (ký bằng release keystore) trong khi bạn đang đẩy bản debug.
- Bạn tạo keystore mới sau khi mất keystore cũ — cùng package name nhưng chữ ký hoàn toàn khác.
- Đồng nghiệp ký bằng
debug.keystoretrên máy họ. Máy bạn dùng keystore khác. Mỗi máy dev tự tạo keystore riêng. - Bản đang cài đến từ Play Store. Google Play App Signing ký lại APK bằng khóa của Google. Keystore local của bạn sẽ không bao giờ khớp với khóa đó.
Khi cài lần đầu, Android lưu lại fingerprint của chứng chỉ ký. Mọi bản cập nhật sau đó đều phải khớp chính xác với fingerprint đó — không có ngoại lệ.
Chẩn đoán — xác nhận chữ ký không khớp
Trước khi xóa bất cứ thứ gì, hãy dành 60 giây xác nhận bạn thực sự đang gặp vấn đề chữ ký không khớp. File tải về bị hỏng hoặc sai thiết bị cũng có thể hiển thị lỗi tương tự.
Kiểm tra chữ ký của app đang cài
# Lấy package name nếu chưa biết
adb shell pm list packages | grep yourappname
# Xem thông tin chữ ký của package đang cài
adb shell dumpsys package com.example.yourapp | grep -A5 "signatures"
Kiểm tra APK bạn đang muốn cài
# Dùng apksigner (có sẵn trong Android SDK build-tools)
apksigner verify --print-certs app-debug.apk
# Hoặc dùng keytool
keytool -printcert -jarfile app-debug.apk
So sánh fingerprint SHA-256. Chúng trông giống như AB:CD:12:34:... — 32 cặp ký tự hex. Giá trị khác nhau nghĩa là đã xác nhận không khớp chữ ký. Chọn cách xử lý bên dưới.
Cách xử lý 1 — Gỡ cài đặt rồi cài lại (phổ biến nhất)
Xóa bản cũ đi. Cài mới lại. Vậy thôi.
# Gỡ cài đặt nhưng giữ lại dữ liệu (thử cách này trước)
adb uninstall -k com.example.yourapp
# Nếu không được, gỡ hoàn toàn (xóa luôn toàn bộ dữ liệu app)
adb uninstall com.example.yourapp
# Giờ cài APK mới vào
adb install app-debug.apk
Muốn giữ lại dữ liệu app khi đổi chữ ký? Android chủ động chặn điều đó. Bạn sẽ cần quyền root để sao chép thủ công thư mục dữ liệu — không đáng công trong hầu hết các tình huống debug.
Cài với cờ replace (chỉ hoạt động khi chữ ký khớp)
# -r thay thế app đang có — vẫn yêu cầu chữ ký phải khớp
adb install -r app-debug.apk
# Trên các phiên bản Android cũ, thêm -d để cho phép hạ phiên bản
adb install -r -d app-debug.apk
Cách xử lý 2 — Gỡ cài đặt trực tiếp trên thiết bị
Không kết nối ADB được? Làm thủ công:
- Cài đặt → Ứng dụng → tìm app của bạn → Gỡ cài đặt
- Hoặc nhấn giữ icon app → Thông tin ứng dụng → Gỡ cài đặt
Sau đó sideload APK lại qua ADB hoặc trình quản lý file.
Cách xử lý 3 — Dùng chung một debug keystore cho cả nhóm
Cách này giải quyết tận gốc vấn đề với dự án nhóm. Android tự tạo debug.keystore riêng biệt trên mỗi máy. Máy khác nhau, chữ ký khác nhau, xung đột là điều không tránh khỏi trên thiết bị test dùng chung.
Giải pháp: chọn một keystore dùng chung cho tất cả mọi người.
# Vị trí mặc định của debug keystore
# macOS/Linux
~/.android/debug.keystore
# Windows
%USERPROFILE%\.android\debug.keystore
Commit nó vào repo — chỉ dùng cho debug build, không có rủi ro bảo mật — hoặc phân phối qua secrets manager. Mỗi dev thay thế debug.keystore local của họ bằng file dùng chung. Fingerprint giờ sẽ khớp trên tất cả các máy.
Để kiểm tra fingerprint của bất kỳ keystore nào:
keytool -list -v -keystore debug.keystore -alias androiddebugkey -storepass android -keypass android
Cách xử lý 4 — App đã đăng ký Play Store / App Signing
Google Play App Signing ký lại APK của bạn bằng khóa của Google trước khi phân phối. Keystore local sẽ không bao giờ khớp với khóa đó. Không có ngoại lệ.
Ba hướng giải quyết:
- Gỡ bản Play Store, sau đó cài bản build ký local của bạn.
- Thêm hậu tố package name cho debug build (ví dụ:
com.example.yourapp.debug). Cả hai phiên bản cùng tồn tại trên một thiết bị — không bao giờ xung đột. - Dùng internal test track trên Play Console để phân phối APK đã ký bởi Play đến tester.
Thiết lập debug application ID suffix trong build.gradle
android {
buildTypes {
debug {
applicationIdSuffix ".debug"
versionNameSuffix "-debug"
}
}
}
Giờ đây debug và release được coi là hai app hoàn toàn tách biệt. Không chia sẻ trạng thái, không xung đột chữ ký, mãi mãi.
Kiểm tra lại
# Xác nhận app mới đã cài thành công
adb shell pm list packages | grep yourappname
# Kiểm tra phiên bản đang cài
adb shell dumpsys package com.example.yourapp | grep versionName
# Khởi chạy app
adb shell monkey -p com.example.yourapp -c android.intent.category.LAUNCHER 1
App khởi chạy không bị crash? Vậy là xong.
Bài học rút ra
- Đặt
applicationIdSuffix ".debug"ngay từ đầu với bất kỳ dự án nào sẽ lên Play Store. Năm phút thiết lập ban đầu tiết kiệm hàng giờ xử lý xung đột chữ ký về sau. - Commit một
debug.keystoredùng chung vào repo. Keystore riêng từng máy là kẻ thù thầm lặng của quy trình test nhóm. - Sao lưu release keystore ra ít nhất hai nơi. Mất keystore đồng nghĩa với việc bạn không bao giờ đẩy được cập nhật cho listing Play Store hiện tại — buộc phải publish app mới hoàn toàn từ đầu, mất sạch rating và review.
- Trên thiết bị test dùng chung, hãy biến việc gỡ cài đặt trước thành thói quen. Làm trước mỗi phiên cài, không phải chờ đến lúc có lỗi mới làm.

