生成 Keystore 文件:keytool 命令详解

说到 Android 签名,第一个绕不开的工具就是 keytool。它是 JDK 自带的密钥和证书管理工具,说白了就是用来创建、查看、导入、导出密钥库的瑞士军刀。我刚开始做签名的时候,觉得这玩意儿就是个黑箱——敲几个参数就出来一个 .jks 文件,完全不知道里面装了啥。

后来踩过几次坑才明白,keytool 的每个参数都关乎签名能不能过、上线会不会报错。嗯,今天咱们就把它扒开看看。

keytool 生成 Keystore 核心流程 keytool -genkeypair 必选参数组:-alias, -keyalg, -keysize, -validity, -keystore -storepass, -keypass, -dname -alias 唯一别名标识 建议用应用名 -keyalg RSA 推荐 2048 位 密钥算法 -validity 有效期天数 至少 25 年 常见陷阱与避坑指南 ① 密码记不住 → 应用市场更新无法通过 ② 有效期太短 → 两年后要重新签名 ③ 别名不一致 → 多项目混淆 输出:your_keystore.jks 💡 一个 keystore 可存多个别名,每个别名对应一对密钥

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 相关故障。我自己这些年签过数百个应用,绝大部分坑都是因为密码记错、有效期太短、路径不对这几个老问题。多留个心眼,提前做好备份,比啥都强。