签名这个东西,我在日常接 SDK、做渠道包、帮人排查问题的时候几乎天天都会碰到。很多同学第一次问出“Android Studio 怎么获取 APP 应用签名”,基本都卡在同一个地方:翻遍了 IDE 菜单找不到一个叫“签名信息”的按钮,或者好不容易找到个keytool命令,又搞不清该用 MD5 还是 SHA1,填给第三方平台还被提示格式不对。
这篇内容我就把 Android Studio 环境下获取应用签名的完整方法讲透,同时把签名机制、debug 签名和 release 签名的区别、v1/v2/v3 的坑一起捋清楚。无论你是刚学 Android 的新手,还是被“签名校验失败”折磨一下午的老开发,先看这篇,基本能少走一大半弯路。
1. 应用签名到底是什么,为什么平台总让我填 MD5
1.1 包名不是唯一标识,签名才是应用的身份凭证
Android 系统判定一个应用的身份,用的是“包名 + 签名”的组合。包名可以理解成门牌号,签名就是身份证号。两个应用可以门牌号一样,但身份证号不能一样,否则系统会认为它们是冲突应用,后装的那个根本无法覆盖安装。
这个机制直接决定了两件常见的事:
- 同一个包名,签名不同,系统不允许覆盖安装,会报
INSTALL_FAILED_UPDATE_INCOMPATIBLE: Signature ... do not match。 - 第三方开放平台给你填的“应用签名 MD5 / SHA1”,本质上是想确认调用方 APK 确实来自某个开发者,防止你的包名被别人冒用去调接口。
所以你会发现,几乎所有需要和支付、地图、分享、推送类 SDK 对接的平台,都绕不开“填签名信息”这一步。这个值不是随便写的,必须从真实的 APK 或 keystore 里查出来。
1.2 从 v1 到 v3,签名方案在变,直接影响你“查得对不对”
搞懂 v1、v2、v3 签名方案,能帮你避免不少“明明查了签名,却还是不对”的尴尬。
- v1(JAR 签名):Android 7.0 之前的传统签名方式。它只校验 APK 中未被修改的条目,签名后 APK 里某些资源仍然可以被人为改动而不被发现,安全性相对较弱。
- v2(APK Signature Scheme v2):从 Android 7.0 开始引入,对整个 APK 文件按块做校验,校验速度更快,安全性更高。它把签名信息放在 APK 的 Signing Block 里,不再依赖
META-INF目录下的文件。 - v3(APK Signature Scheme v3):Android 9 开始支持,在 v2 基础上增加了密钥轮换机制,也就是应用开发者可以在不更换身份的情况下,切换签名证书。
这三个方案对“查签名”这件事的影响在于:不同环境下读到的证书来源可能不一样。有的工具解析的是 v1 签名块,有的工具解析的是 v2/v3 签名块;如果 APK 只勾了 v1 或只勾了 v2,部分读取方式就可能失败或拿不到完整信息。后面我会重点提到这个坑。
1.3 MD5、SHA1、SHA256 到底有什么区别
查签名时,工具会同时输出一串 MD5、SHA1、SHA256 指纹,很多人不知道填哪个。它们本质上是证书内容的哈希摘要,只是算法和长度不同:
| 指纹类型 | 长度 | 常见使用场景 |
|---|---|---|
| MD5 | 32 位十六进制 | 很多支付类平台、统计类平台要求填的“应用签名” |
| SHA1 | 40 位十六进制 | 地图类、定位类 SDK 申请 Key 时常用 |
| SHA256 | 64 位十六进制 | 较新的开放平台、企业证书校验常用 |
获取方法上,用keytool或apksigner通常一次能同时拿到三种指纹。我的习惯是三种都留下来,对接不同平台时再按对方要求选。要注意一点:某些平台要求 MD5 是 32 位小写且不带冒号,有些平台又允许大写带冒号,这个后面单独讲。
2. 动手之前,先确认你这个包到底用的哪个签名
2.1 debug 签名和 release 签名的坑
Android Studio 里直接点 Run 装到手机上的包,默认用的都是 debug 签名。这个签名文件在用户目录下(Windows 一般是C:\Users\你的用户名\.android\debug.keystore,macOS/Linux 是~/.android/debug.keystore),密码是android,别名是androiddebugkey。
真正要上架、要接入 SDK 正式环境的包,用的往往是 release 签名,也就是你自己创建的 keystore。
第三方平台配置的 MD5 和你本地运行包用的签名不一致,是“签名校验失败”的第一大原因。很多人本地调通了,打包 release 后调不通,就是因为平台配置里填的是 debug 签名的 MD5,而 release 包用的是另一个签名。也有反过来踩坑的:平台配了 release 签名,自己拿 debug 包去联调,自然怎么都对不上。
拿到一个 APK 后,第一步不是急着查签名,而是先确认这个包是不是最终要发布、要对接的签名包。这个前置判断能省下大量排查时间。
2.2 从 Gradle 配置里核对签名来源
如果项目里配置了signingConfigs,你可以在app/build.gradle里直接看到签名文件的路径、别名和密码:
android { signingConfigs { release { storeFile file("release.jks") storePassword "your-store-password" keyAlias "your-alias" keyPassword "your-key-password" } } buildTypes { release { signingConfig signingConfigs.release } } }不过项目如果是从别人手里接过来的,密码可能写在别处,也可能是用占位符引用了环境变量、CI 配置,甚至可能在 IDE 的模板文件里。打开build.gradle看签名配置,是最快的核对方式:至少能看到现在这个工程用的是什么 keystore。
如果项目根本没有配置signingConfigs,那你用 Android Studio 直接构建出来的 release 包其实是未签名的。真正到提审、上传的时候,需要手动在向导里选 keystore。此时检查签名信息之前,一定要确认这个 APK 到底有没有被执行过签名动作。
2.3 构建一个“确定使用了某个 keystore”的 APK
如果你要查的签名信息是给第三方平台用的,最稳妥的办法是先明确地构建一个已经签名好的 APK,再拿它去查签名。否则你拿一个未签名或用了错误签名的包去查,填给平台的值一定不对。
在 Android Studio 里的操作路径是:Build > Generate Signed Bundle / APK...,选择 APK,然后选择 keystore,输入密码和别名,选择 build variant,最后在签名版本勾选时,建议把 v1 和 v2 都勾上。
如果项目配置了 Gradle 签名,也可以直接跑./gradlew assembleRelease,构建出的app-release.apk就是已经签名的包。相比之下,这种方式比图形界面更可控,重复执行也方便。我用项目工程构建时,基本都是命令行跑 task,很少再打开签名向导。
3. 四种获取应用签名的实操方法
3.1 Android Studio 的 APK Analyzer 图形界面
如果你只是想快速看一眼某个 APK 的签名证书信息,最省事的是 Android Studio 自带的 APK Analyzer。
操作路径是:Build > Analyze APK...,选中 APK 文件,打开后点击下方的Signature标签页。这里能看到签名方案(v1、v2、v3 是否启用)、证书 DN、证书有效期、指纹等信息。
这个方法最大的优点是“所见即所得”,完全不需要命令行,适合团队里不熟悉终端的产品、测试同学自己去核对。但它也有个局限:APK Analyzer 展示的指纹信息偏少,主要给到的是证书的 SHA-256 指纹,MD5 不是每个版本都会直接显示出来。如果你的目标是拿平台要的 MD5,光靠这个界面可能不够。
另外,APK Analyzer 打开的是 APK 文件,不是 keystore。如果你的 keystore 文件还在,但还没打包出 APK,或者不想打一个正式包,那就得用命令行方式。
3.2 keytool 命令行:一次拿到 MD5、SHA1、SHA256
keytool是 JDK 自带工具,对 APK 文件可以直接打印证书信息,这是我现在最常用的方式,没有之一。
对一个已经签名的 APK:
keytool -printcert -jarfile app-release.apk执行后,终端会输出 Owner、Issuer、有效期、签名算法名,以及完整的证书指纹,包括 MD5、SHA1、SHA256。输出示例大致这样:
Owner: CN=Android Debug, O=Android, C=US Issuer: CN=Android Debug, O=Android, C=US Serial number: 1 Valid from: ... Certificate fingerprints: MD5: A1:B2:C3:... SHA1: D4:E5:F6:... SHA256: 1A:2B:3C:...如果你手里是 keystore 文件,而不是 APK,用:
keytool -list -v -keystore release.jks -alias 你的别名 -storepass 你的密码同样会打印该别名下证书的 SHA1、SHA256 等信息。需要提醒的是:如果你不确定 keystore 里的别名,可以先不带-alias参数执行,让 keytool 列出所有别名,再针对具体别名查。
这里有个实际经验:keytool -printcert -jarfile依赖 JAR 签名结构。如果你构建 APK 时只勾了 v2、v3 签名,没有保留 v1 的META-INF证书文件,老版本 JDK 的keytool可能读不到信息。这时改用下一节的apksigner更稳。
3.3 apksigner:验证 APK 签名完整性的官方工具
apksigner是 Android SDK 构建工具包自带的官方工具,位置在 Android SDK 目录下的build-tools/版本号/里。用它对 APK 打印签名信息,最贴合实际场景:
apksigner verify --print-certs app-release.apk输出内容包括 Signer #1 的 certificate DN、SHA-256 digest、SHA-1 digest、MD5 digest。这个命令对纯 v2/v3 签名的 APK 也能正常解析,不像keytool那样受 v1 签名结构限制。
如果只想确认签名方案是否有效:
apksigner verify --verbose app-release.apk输出会显示:
Verified using v1 scheme (JAR signing): true Verified using v2 scheme (APK Signature Scheme v2): true Verified using v3 scheme (APK Signature Scheme v3): true这条命令在排查“为什么某个 APK 在部分设备上安装失败”“为什么平台识别不到签名”时非常有用。我已经不止一次遇到“签名包查出来是对的,但设备安装时报签名问题”的情况,一查apksigner verify --verbose,果然是 v1 或 v2 没勾全。
3.4 代码里动态获取签名
有些场景需要在应用运行时动态获取签名信息,比如防止 APK 被篡改、做灰度校验、SDK 请求前自检等。这种方式拿到的签名信息和用工具查出来的是一致,但代码里要注意版本适配。
API 28(Android 9)之前,使用PackageManager.GET_SIGNATURES:
PackageManager pm = getPackageManager(); String pkgName = getPackageName(); PackageInfo info = pm.getPackageInfo(pkgName, PackageManager.GET_SIGNATURES); Signature[] signatures = info.signatures;API 28 及之后,官方推荐使用GET_SIGNING_CERTIFICATES:
PackageManager pm = getPackageManager(); String pkgName = getPackageName(); PackageInfo info = pm.getPackageInfo(pkgName, PackageManager.GET_SIGNING_CERTIFICATES); Signature[] signatures = info.signingInfo.getApkContentsSigners();拿到Signature[]之后,可以用MessageDigest计算 MD5 或 SHA1:
MessageDigest md = MessageDigest.getInstance("SHA-1"); for (Signature signature : signatures) { byte[] certBytes = signature.toByteArray(); byte[] digest = md.digest(certBytes); String hexString = bytesToHex(digest); // 在这里使用或打印 }这个方式和keytool计算出来的指纹是一致的,因为Signature.toByteArray()拿到的就是证书的 DER 编码。要注意的是,GET_SIGNATURES在 API 28 已经废弃,工程里targetSdk如果比较高,用旧接口虽然还能跑,但建议尽早切到新的signingInfo方案。
另外要提醒:如果 APK 用到了签名轮换机制,系统 API 返回的可能不只是轮换后的验证证书,还包含历史证书。在多签名者场景下,第三方平台要你填的往往是当前激活的证书,这时要把输出整理清楚再给对方。
4. 拿到签名之后,最容易踩的几个实际问题
4.1 第三方平台提示“签名校验失败”
遇到这个提示,通常不是“查签名”这个动作出了问题,而是三个细节没对齐:
- 填错了指纹类型。平台要 MD5,你填了 SHA1。
- 格式不对。平台要求 32 位小写无冒号,你填的是大写带冒号。
- 签名来源不对。平台配的是 release 签名,你查的是 debug 包。
以我遇到过的支付类平台为例,它的“应用签名”字段要求的就是 32 位小写 MD5,不能带冒号。如果你复制 keytool 输出里带冒号的大写 MD5,直接粘贴,很大概率会校验失败。
解决办法是:先用 3.2 或 3.3 的方法拿到目标 APK 的指纹,然后按平台要求做处理。去冒号、转小写这种操作,推荐在本地用工具或脚本自动化,避免手动删错。我一般会在项目目录放一个小的文本记录,把每个对接平台的格式要求写清楚,下次直接对照着复制。
4.2 覆盖安装报“签名不一致”
老版本用户想升级,新 APK 包名相同但签名不同,系统会直接拦截,并提示INSTALL_FAILED_UPDATE_INCOMPATIBLE。这种情况分两类原因:
- 新旧包根本不是同一个 keystore、同一个 alias 打的。比如原来用的 keystore A 发布,后来换成了 keystore B。
- 同一个 keystore,但签名方案发生了变化。比如旧包只勾了 v1,新包只勾了 v2,部分设备在安装校验时走不同的签名读取路径,也有可能导致不一致或校验不通过。
排查方法很直接:拿新旧两个 APK,分别用apksigner verify --print-certs输出证书指纹,对比 MD5/SHA1/SHA256 是否一致。注意这里不能只对比包名,一定要对比签名。
从根源上避免的办法是:从第一次发布开始固定一套 keystore、一套 alias,签名勾选方案保持统一。不要因为换了台电脑、重新生成了 keystore 就把签名换了。签名文件丢失带来的成本远比想象中高。
4.3 v2/v3 签名下,动态获取签名返回空或不全
前面 3.4 的代码方式,用的是系统 API,正常情况都能拿到。但我在实际项目中遇到过一种场景:某个 SDK 内部自己解析 APK 文件去读签名信息,不走系统 API。这种 SDK 如果遇到一个只勾了 v1 签名的包,它在 APK 的 Signing Block 里读不到 v2/v3 签名,就可能返回空或解析失败。
表现是很典型的:同一个包在本地安装、运行都正常,但 SDK 上报签名数据时缺字段,或者平台那边一直显示“未签名”。
这种情况下,重新构建 APK 时把 v1 和 v2 都勾上,通常就能解决。这也再次说明,签名方案勾选不是随便定的,老设备要 v1,新系统对纯 v1 的包校验又更严格,所以兼容性最好的是 v1 + v2 同时开启。如果你的最低支持版本是 Android 9 以上,可以只开 v2 + v3,但前提是确认没有低版本设备需要覆盖。
4.4 多证书签名者时的排列问题
企业级应用有时会用到多签名者模式,或者做过签名轮换。同一个 APK 里可能包含多个证书。用apksigner verify --print-certs输出时,你会看到Signer #1、Signer #2这样的条目。
第三方平台让你填签名,通常只认第一个签名者或当前激活证书的指纹。遇到这种情况,不要只挑一个就填,最好把完整输出发给平台技术支持,让他们明确到底要哪个证书的信息。这个经验是我替某公司排查对接问题时总结出来的,对方技术文档写得并不清楚,最后靠人工确认才解决。
5. 避坑清单与效率技巧
5.1 keystore 信息丢了怎么办
keystore 文件、密码、别名这三位一体,丢了任何一个,都无法再生成相同签名的 APK。这是 Android 开发里最硬性的问题之一。
如果只是当前工程找不到签名文件,可以先在项目目录里搜索.jks、.keystore文件,检查 CI 配置里是否有备份,再看看 IDE 的模板文件有没有残留路径记录。如果全部丢失,旧包无法再升级,只能换新签名重新上架。
我的建议是:拿到任何 keystore 之后,第一时间在安全的位置做备份,并把路径、别名、密码(至少是密码提示)记录在团队内部文档里。不要只存在某个同事的电脑里。这个习惯救过我很多次。
5.2 快速分辨 debug 包和 release 包
拿到一个 APK,想快速判断它是 debug 签名还是 release 签名,看证书 DN 就行。默认 debug keystore 的证书 DN 是:
CN=Android Debug, O=Android, C=US用apksigner verify --print-certs扫一下,看到这个 CN 值,基本就能确定是 debug 包。release 签名的证书 DN 通常是你组织或个人的信息,不会是这种固定值。
这个方法在排查“为什么本地正常、上线报签名错误”时特别好用。很多时候就是开发手里跑的是 debug 包,报问题的用户装的是 release 包,两边证书根本不沾边。
5.3 给第三方平台提供签名信息时的整理格式
查签名不难,真正容易出错的是“给了又不对”。我的做法是,每发布一个版本,就把签名信息整理成固定格式的清单,存到项目文档或 wiki 里:
应用名:xxx 包名:com.example.app keystore 路径:release.jks alias:your-alias MD5:32 位小写无冒号 SHA1:40 位大写 SHA256:64 位大写 v1:开启 v2:开启 v3:视情况开启 证书有效期:2024-01-01 ~ 2035-01-01后续要和任何平台对接,直接复制对应字段即可,不用每次重新打包、重新查。平台要求格式有差异,也在清单里备注好,省得来回折腾。
查签名这件事,单独看很简单,但它背后牵扯签名方案、debug/release 身份、平台对接格式验证等一连串问题。我个人最顺手的流程是:先用apksigner verify --print-certs确认证书指纹,再用apksigner verify --verbose确认签名方案,最后再按平台要求格式化输出。Android Studio 的 APK Analyzer 则用来做图形化核对和给非技术同事展示。这套流程实测下来,从拿到一个陌生 APK 到确认完签名信息,通常一分钟内就能搞定。只要你从一开始就对签名保持敬畏,把 keystore 当压箱底的资产保管好,把每次发布的签名信息记录在案,后续对接、排查、换机重装这些事,基本不会再拖你后腿。