生成 Keystore 文件:keytool 命令详解
说到 Android 签名,第一个绕不开的工具就是 keytool。它是 JDK 自带的密钥和证书管理工具,说白了就是用来创建、查看、导入、导出密钥库的瑞士军刀。我刚开始做签名的时候,觉得这玩意儿就是个黑箱——敲几个参数就出来一个 .jks 文件,完全不知道里面装了啥。
后来踩过几次坑才明白,keytool 的每个参数都关乎签名能不能过、上线会不会报错。嗯,今天咱们就把它扒开看看。
1. 最基本的生成命令
假设你要给一个叫 "MyApp" 的应用生成签名文件,一般我会直接敲下面这条命令:
keytool -genkeypair -v -keystore myapp.keystore -alias myapp -keyalg RSA -keysize 2048 -validity 9125
它会让你输入一堆信息,包括密码、姓名、组织等。这里有几个坑:
- -keystore:输出文件名。别用中文名或带空格的路径,我在 CI 环境里吃过这个亏。
- -alias:别名,就相当于是这把钥匙的标签。记住它,后面签名打包还要用。
- -keyalg RSA:密钥算法。Android 要求必须使用 RSA,别手抖写成 DSA。
- -keysize 2048:密钥长度。1024 位在 2024 年已经被 Google Play 警告了,建议 2048。
- -validity 9125:有效期天数。9125 天 ≈ 25 年。我曾经因为只设了 10 年,结果应用还没淘汰证书先过期了……嗯,那个教训刻骨铭心。
重要提醒:-validity 至少要设到 9125 天(25 年),因为 Android 应用的生命周期可能非常长。Google Play 也有至少 25 年的要求。
2. -dname 参数:不用交互,一步到位
在自动化脚本里,交互式输入密码特别烦人。我个人习惯把「-dname」参数直接拼上,这样命令就可以静默运行:
keytool -genkeypair -v -keystore myapp.keystore -alias myapp -keyalg RSA -keysize 2048 -validity 9125 -storepass 123456 -keypass 123456 -dname "CN=ZhangSan, OU=Dev, O=MyCompany, L=Beijing, S=Beijing, C=86"
参数拆开看:
- -storepass:keystore 文件的保护密码
- -keypass:密钥本身的保护密码。可以跟 storepass 一样,但我建议设成不同值——安全一点。
- -dname:里面包含 CN(通用名称,通常是开发者名字或应用域名)、OU(组织单位)、O(组织)、L(城市)、S(省)、C(国家代码)。
小提示:-dname 里的 CN 不在乎写什么,它不会影响签名验证。但别乱填特殊符号,否则可能在 Gradle 解析时报奇怪的编码错误。
3. 查看已生成的 keystore
常用场景:同事给了你一个 .jks,你想看看里面到底有几个别名、有效期到哪一天。用这条命令:
keytool -list -v -keystore myapp.keystore -storepass 123456
输出里你会看到 SHA1、SHA256 指纹,还有有效期。有一次我在排查签名冲突时,才发现两个项目用了同一个别名,搞得应用覆盖安装一直报签名不一致——排查了好久才找到源头。
4. 修改 keystore 密码和别名
下面两个命令很实用,但很多人不知道:
| 操作 | 命令 |
|---|---|
| 更改 storepass | keytool -storepasswd -keystore myapp.keystore -storepass 旧密码 -new 新密码 |
| 更改 keypass | keytool -keypasswd -keystore myapp.keystore -storepass xxx -alias myapp -keypass 旧密码 -new 新密码 |
| 重命名别名 | keytool -changealias -keystore myapp.keystore -storepass xxx -alias 旧别名 -destalias 新别名 |
为什么需要改别名?我遇到过项目合并后别名冲突的情况,不改后面打包就会报错。嗯,用 -changealias 几秒钟搞定,不用重新生成 keystore。
5. 导出证书供三方使用
有时候需要把公钥证书发给合作伙伴,比如接入微信分享、Google API 时要填 SHA1 指纹。除了 -list -v 查看外,也可以导出 .cer 文件:
keytool -exportcert -v -keystore myapp.keystore -storepass 123456 -alias myapp -file myapp.cer -rfc
加上 -rfc 会输出 PEM 格式(文本),不加则是 DER 格式(二进制)。我个人喜欢 -rfc,因为可以用文本编辑器直接打开看内容。
⚠️ 重要警告:任何时候都不要把 .keystore 文件传到 Git 仓库里!包括 .jks、.bks 等。我在早期把 keystore 提交过一回,好在发现及时改了密码。密码泄露后光改密码还不够,你得重新生成证书并重新上传应用——这是个大坑,千万谨记。
6. 不同版本 JDK 的差异
keytool 在不同 JDK 版本下行为有点不一样,我自己遇到过:
- JDK 8:默认使用 JKS 格式(扩展名 .jks),命令最稳定,推荐 CI 环境用。
- JDK 11+:默认使用 PKCS12 格式(扩展名 .p12 或 .keystore),更加安全。但你如果一直用 JKS 也能用,只不过 JDK 11 会打印一个警告。
- JDK 17+:默认强制 PKCS12,而且 -keysize 必须 ≥ 2048,否则直接报错。
我的建议:统一使用 PKCS12 格式,兼容性更好,也抗未来升级。生成时显式指定:
keytool -genkeypair -storetype PKCS12 ...
7. 快速检查 keystore 是否损坏
有时候文件拷贝中断或者磁盘故障,keystore 可能打不开了。一个简单的诊断方法:
keytool -list -keystore myapp.keystore -storepass 123456
如果提示 "java.io.IOException: Keystore was tampered with, or password was incorrect",密码错误或文件损坏二选一。我碰到过一次就是因为把 .jks 当文本文件编辑保存了,结果整个结构乱掉——只能从备份恢复。
好了,keytool 的核心用法大概就这些。你把它当工具箱就好,平时常用的是前三四个命令,其他的知道有这功能就行。真要出问题时,你再翻回这一节看看,基本能解决 90% 的 keystore 相关故障。我自己这些年签过数百个应用,绝大部分坑都是因为密码记错、有效期太短、路径不对这几个老问题。多留个心眼,提前做好备份,比啥都强。