☰
Android应用签名获取全攻略:从Android Studio到keytool实战
2026/10/13 11:32:41 网站建设 项目流程

搞 Android 开发的,几乎没人能绕开“应用签名”这四个字。尤其是当你去某个开放平台申请接入、或者手里拿着一堆不同渠道包需要核对身份的时候,有没有签名、拿到的签名对不对,直接决定你这一天是顺顺利利还是从早调到晚。前阵子帮一个同事排查 SDK 登录失败,最后就是签名对不上,平台后台报“应用签名校验失败”,查了一圈才发现他对着 debug 包拉了签名,线上 release 包的签名压根不是那回事。

这种坑踩过的人不在少数。所以这期我直接把“Android Studio 获取 app 应用签名”这件事儿从头到尾拆开来讲,把平时最常用的、能直接抄走用的几种方法全给你列清楚,顺带把背后容易踩的细节一起理一遍。

1. 先说清楚:应用签名到底是“什么”又是“给谁用的”

你要搞懂怎么获取签名,得先知道签名的本质是什么。简单说,签名就是应用包(APK/AAB)的身份证,用你手里的 keystore(签名文件,通常后缀是 .jks 或 .keystore)配合密钥生成出来的一组指纹信息,包含 MD5、SHA1、SHA256 这几类。系统在安装应用时会校验这个指纹,第三方 SDK 平台也会校验。

日常开发中你需要用到签名的场景主要集中在这么几种:

  • 接入第三方 SDK 服务时,对方平台要求上传包名和“应用签名”,尤其是支付、地图、登录、推送这类能力,基本是必填项。
  • 应用做多渠道打包、热修复、插件化时,校验签名是否一致。
  • 排查上线后安装失败,或者覆盖安装被拒时,需要确认签名算法和指纹是否符合预期。

很多没经验的朋友容易有误区,以为同一个项目所有包签名都一样。实际上 debug 包默认使用 debug.keystore,release 包必须指定自己的正式签名文件,这俩的指纹完全是两码事。你拿 debug 签名去填平台,再把 release 包传上去,必然校验失败。

还有一点你得清楚,获取签名不是为了“看”,而是为了“填到该填的地方”。所以后面每个方法我都会顺便讲清楚,拿到手的字符串应该怎么处理才能用。

2. Android Studio 图形化查看签名:signingReport 任务

这是最省事的方法,不需要装额外工具,也不需要你记得命令行参数。打开 Android Studio,右下角找到 Gradle 面板(没有的话在 View > Tool Windows > Gradle 里找),展开你的项目模块,找到Tasks再找到android分组,里面有一个叫signingReport的任务。双击跑一下,输出会直接列出当前模块所有 build variant 对应的签名信息。

输出内容大概是这个样子:

Variant: debug Config: debug Store: /Users/yourname/.android/debug.keystore Alias: AndroidDebugKey MD5: 6B:62:3F:... SHA1: 3A:41:... SHA-256: 7E:... Variant: release Config: release Store: /path/to/your-release.keystore Alias: release MD5: ... SHA1: ... SHA-256: ...

这个方式最大的好处是可视化,不用记命令,而且把所有 variant 的信息一次性列全。我一般第一次接手项目时就会先跑一次 signingReport,几秒钟就能把项目里 debug/release 的指纹底细摸清,后续核对的时候心里有数。

但有几个注意事项:

  1. 前提是模块里的 signingConfigs 有配置。如果项目里没有配置签名,release 那栏很可能显示Config: release但下面没有指纹信息,只显示一行Signing certificate后面跟着CN=Unknown。这不代表系统没有签名,而是 Gradle 层面没读到 signingConfig。这种情况下更推荐用命令行方式(下面会讲)。
  2. 输出内容可能滚动很长。模块多、多渠道多的时候,要自己找准对应 flavor 的输出,别复制串了。
  3. 个别新版本 Android Studio 里 Gradle 面板默认不展开 Task 列表,对着“android”双击展开就行,找不到就点一下刷新按钮。

如果你只用 AS 自带这种方式,日常填平台签名已经够了。但它有个限制:一旦你手里没有项目工程、只有一个 APK 文件,这套就没法用了。这种情况要往下看命令行和 APK 解析的方式。

3. 命令行武器:keytool 获取签名信息

keytool 是 JDK 自带的密钥和证书管理工具。只要你本机装过 JDK,命令行里基本可以直接用。这是我认为最通用、也是最快的方法,适用面比 AS 图形化方式广得多,不管是拿到 jks 文件、debug.keystore 文件,还是想顺便核对密码对不对,都靠它。

先看最核心的命令:

keytool -list -v -keystore /你的绝对路径/xxx.jks -alias 别名 -storepass 密码

解释一下关键参数:

  • -list表示要列出证书信息。
  • -v表示以详细模式输出,否则默认只会输出指纹的简短列表,信息太少。
  • -keystore后面跟签名文件的绝对路径,尽量写绝对路径,避免当前目录不对导致No such file or directory。
  • -alias指定别名,不是必填,但建议带上。一个 keystore 里可以放多个证书,不带别名会把所有证书都列出来,带别名更精准。
  • -storepass是 keystore 的密码,不写的话命令会提示你交互输入,安全性高一点,但脚本化执行时必须写。

如果不想填别名,也可以直接拉列表:

keytool -list -v -keystore /你的绝对路径/xxx.jks

执行后输出中有三块我们最关心:

证书指纹: SHA1: 3A:41:6B:... SHA256: 7E:62:3F:... 签名算法名称: SHA256withRSA 版本: 3

等等,这里有个关键区别要先说明:keytool 的输出默认是包含SHA1和SHA256的,但很多第三方平台(比如一些开放平台)让你填的“应用签名”其实是MD5,而且要求去掉冒号、全小写。那么 keytool 能不能直接给你输出 MD5?能,但要换一个不带-v的简短列表格式:

keytool -list -keystore /你的绝对路径/xxx.jks -alias 别名 -storepass 密码

这样输出的 MD5 格式是6B:62:3F:...,带冒号且大写。你需要再处理一下:去掉冒号、转成小写,最终类似于6b623f...这样一串 32 位字符。这个点我遇到过太多次,很多人拿到了完整带冒号的 MD5 直接就粘贴进平台,结果平台上显示校验失败,折腾半天才发现是格式问题。

Debug 包的默认签名文件,在 macOS/Linux 是~/.android/debug.keystore,Windows 是C:\Users\你的用户名\.android\debug.keystore,默认别名是androiddebugkey,默认密码是android。所以获取 debug 签名可以直接用这条:

keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android

还有一个很常见的坑:命令行输入keytool提示“不是内部或外部命令”。说明JAVA_HOME没配好,或者说 Java 没安装。解决方式是直接用 Android Studio 内置的 JDK 路径去调用,比如 macOS 上 AS 自带 JBR(JetBrains Runtime)路径,Windows 上也有对应的 jbr 目录,cd 到该目录的 bin 下再执行 keytool。

这种方式我平时用得最多,因为它不依赖项目工程,只要手上有一个签名文件就能干活,而且输出很快。唯一的门槛是要记住命令参数,不过把这条命令存成 alias 或者写进自己的 scripts 目录,一次配置永远复用。

4. 运行时直接拿签名:App 内自查与跨包校验

第三种场景稍微特殊一点:你需要验证当前手机上正在运行的这个 App,它安装到设备上的包签名到底是什么,而不是去看构建产物的文件。这种场景最典型的就是接入了某些统计平台,需要上报本机签名做反作弊;或者是多渠道归因排查时,要确认线上包是不是真的由某个特定 keystore 签出来的。

这种时候 Java/Kotlin 代码直接读包管理器的信息,比什么都准。核心逻辑是:通过PackageManager拿到PackageInfo,再去拿签名数组,然后用MessageDigest分别算 MD5、SHA1、SHA256。

直接上 Kotlin 代码:

import android.content.pm.PackageManager import java.security.MessageDigest import java.security.cert.CertificateFactory import java.io.ByteArrayInputStream fun getAppSignature() { val packageInfo = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNING_CERTIFICATES) } else { packageManager.getPackageInfo(packageName, PackageManager.GET_SIGNATURES) } // 兼容新老 API val signatureByteArray = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { packageInfo.signingInfo ?.apkContentsSigners ?.get(0) ?.toByteArray() } else { packageInfo.signatures?.get(0)?.toByteArray() } val md5 = MessageDigest.getInstance("MD5").digest(signatureByteArray) val sha1 = MessageDigest.getInstance("SHA1").digest(signatureByteArray) val sha256 = MessageDigest.getInstance("SHA256").digest(signatureByteArray) // 转成十六进制带冒号形式 println("MD5: " + md5.joinToString(":") { "%02x".format(it) }) println("SHA1: " + sha1.joinToString(":") { "%02x".format(it) }) println("SHA256:" + sha256.joinToString(":") { "%02x".format(it) }) }

这里特别说一下,Android 9(API 28)开始,PackageManager.GET_SIGNATURES这个常量和方法虽然还能用,但是已经标记为过时,系统会建议你用GET_SIGNING_CERTIFICATES配合signingInfo来获取。但从兼容性角度,你仍然可以在低版本分支里保留旧写法,这在写 SDK 的时候非常常见。实际项目里我一般会把这套逻辑做成一个单独工具类,既方便内部调用,也方便直接打印 Log 查看。

需要注意,这种方式拿到的信息来自安装包本身的签名块,只要 App 是从正规渠道安装的,签名信息就是真实的。即便你本地构建一个包出来,拿 keytool 查文件和运行时查签名,出来的指纹一定是一致的。这样反过来也可以做本地校验:把命令行查到的指纹和运行时查到的指纹对一下,能不能对上,一眼就知道签名到底用没用对。

另外,如果你是想在build.gradle里直接写 Task 打印签名,理论上也能实现,但复杂度比前面几种高不少,而且灵活性不如直接看命令行,这里就不展开了。日常开发用上面这个工具类足够。

5. 手里只有 APK 没有签名文件:从安装包提取签名

刚才说的都是拿着签名文件或者项目工程就能查。现实里还有一种很常见的情况:项目交接、客户甩过来一个 APK,又或者你是测试方,需要核对线上 APK 和源仓库里的签名是否一致。这时候 keystore 文件不一定在你手上,但你依然有办法查出这个 APK 的签名。

最正统的查法是使用 Android SDK 构建工具里的apksigner工具,它在build-tools目录下,比如sdk/build-tools/34.0.0/apksigner。直接执行:

apksigner verify --print-certs app-release.apk

这个命令会打印非常完整的信息,包括签名算法版本(v1/v2/v3)、证书指纹的 SHA-256、SHA-1、MD5 等,以及证书 DN 信息。这个方法我最推荐,因为它能顺带看出这个 APK 用的是 v1 还是 v2 签名,对于排查低版本兼容性很有用。

如果你不习惯命令行,也可以直接把 APK 当成 zip 解压,用在线证书查看器去打开META-INF/CERT.RSA这个文件。但这条路有点绕,从效率角度我基本不用。还有一类第三方工具比如 APK 信息查看器,虽然可视化程度高一点,但都需要安装外部软件,没必要专门为了查个签名多装工具。

走 apksigner 这个方式需要注意一点:APK 的签名信息是构建时写进包里的,它不像 keystore 文件那样可以反复查,APK 一旦构建完,你就没法再改变它的签名。所以如果你需要比较两个包是不是同一个 keystore 签的,就把两个 APK 都跑一条 apksigner 命令,对比 SHA256 是否一致,这是最可靠的判断手段。

另外提醒一句:如果是 AAB(Android App Bundle)格式的话,apksigner 不能直接解析 AAB,但你可以用bundletool先构建出 APK 再来验签。不过实际开发中更容易出现的是“商店渠道给的是 AAB,测试装的是商店下载的 APK”,所以这个对比链条反而常被用到,不要觉得 AAB 就彻底和签名无关。

6. 签名获取时的常见错误与避坑实操

技术方法本身不复杂,但我在实际开发里见过太多因为“签名没对上”导致的问题,所以专门把这部分单拎出来写一节。一张表看明白:

常见现象根本原因解决办法
平台提示“应用签名校验失败”填了 debug 签名,线上包是 release 签名确认线上包用的 keystore,重新获取 release 指纹填进去
平台要求填 MD5,自己填了 SHA1没看平台字段要求看清楚要求,keytool 不带-v或者 apksigner 输出里找 MD5
填了带冒号大写的 MD5,平台说是错的平台要求去掉冒号小写格式统一做字符串处理:去冒号、转小写
两个渠道包指纹对不上每个渠道用了不同 keystore 签名检查打包脚本,统一签名配置
keytool命令找不到JDK 环境没配置用 Android Studio 自带 jbr 目录下的 keytool
覆盖安装提示“签名不一致”debug 包覆盖已安装的 release 包测试机先用 release 包卸载旧版本,再装新包
signingReport 里看不到 release 签名模块里 signingConfig 没配置完整改用 keytool 命令行从 keystore 文件直接查
安卓 7.0 以下安装 v2 签名包失败v1/v2 签名兼容性问题构建时同时开启 v1 与 v2 签名,或至少保证 v1 存在

这里重点说几个容易被忽略的点。

第一个是debug 和 release 签名混用的问题。有的人图省事,直接把 release 签名配置到 debug 里,全局都用同一个签名。这样做确实规避了“签名不一致”的问题,但代价是 debug 包占用的存储标识和线上一致,某些内部灰度统计会把 debug 当成线上流量。如果项目还没有正式发版,倒没太大影响;但一旦线上已有大量用户,不建议这么做。我的习惯是 debug 保持默认 debug 签名,release 独立签名,两个互不干扰,靠打包脚本控制。

第二个是MD5 的格式细节。很多平台文档会写“应用签名为 MD5(去除冒号,且为小写)”。keytool 默认输出的 MD5 是大写带冒号,apksigner 输出也是十六进制片段拼接。所以最保险的做法是在提交前统一处理成一个 32 位的小写十六进制串。我自己写过一个简单的脚本,自动从 keytool 输出里抓 MD5 并格式化,避免每次手动改。

第三个是v1/v2/v3 签名算法对校验的影响。部分老平台的校验逻辑停留在 v1 签名读取上,如果你的 APK 只启用了 v2 签名,某些服务端校验可能读不到有效证书,从而报签名异常。现在新的构建工具默认同时启用 v1+v2+v3,除非你手动降级,否则通常是没问题的。但如果你在build.gradle里写了signingConfig自己控制签名启用,那么低版本兼容性的问题就要额外注意。

第四个坑,也是比较隐蔽的一种:同一个 keystore 但别名不同。一个 jks 文件里可能存了好几个证书,你在 Gradle 里配的是别名 A,结果用命令行查的时候用了别名 B,拿到的指纹当然不一样。这种出错往往让人怀疑 keystore 有问题,其实是别名没对上。解决办法很简单,先用不带-alias参数的命令把 keystore 里所有别名都列出来,看清了再定向查。

另外再分享一个对排查很有用的小习惯:把签名信息输出保存到一个固定文件里,比如signature.md,并在每次发版前更新一次。别小看这一步,等你要去开放平台申请能力、或者回答客服“这个包签名是多少”的时候,翻一下文件比重新跑命令快得多,也好核对版本差异。

7. 顺带的经验之谈

这部分不属于某个具体方法,但多花几十秒看完能帮你少走弯路。我实际工作中一旦遇到跟签名相关的问题,第一反应不是去改代码,而是先跑一条 signatureReport 或者 keytool 命令,把当前包的指纹和平台上的记录对齐做对比。因为签名校验这个环节出现差异,绝大多数情况都是配置层面的问题,代码逻辑本身没问题,你自己瞎猜半天不如直接拉数据说话。

如果要在 App 内自检签名,建议不要只打 Log,可以在隐藏的调试页面里把签名指纹显示出来,方便测试人员截图反馈。我参与过的某个项目就是这么做的,排查线上偶发登录失败时,测试直接截图发签名指纹,后端一看就知道是不是包的问题,效率高很多。

还有一点,签名文件(.jks/.keystore)本身属于高度敏感信息,它一旦泄露,别人就能拿着你的签名文件加上你的包名去伪造一个“正版 App”,这对用户和品牌都是灾难。所以任何情况下都不要把签名文件提交到代码仓库,哪怕私有仓库也尽量不要。如果团队协作,签名文件建议放在加密的密码管理工具里,或者由固定的发布负责人保管,通过受控的构建产物分发来保证所有人拿到的是可信的包。项目里曾经出过同事把 jks 连同密码直接推到仓库、离职后密码外流的事情,后来我们花了很大成本才把整个应用签名体系换掉,这个代价是非常大的。

签名获取本身只是一项基础技能,但把它背后的配置、格式、算法和协作管理都理顺了,你才算是真正吃得透。希望这篇内容能帮你把“获取签名”这条链路彻底打通,下一次再碰到签名校验、改包核对之类的需求时,至少能先选对工具、拿对数据、避掉明坑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询