6、签名配置(Signing Config):Keystore生成与管理、signingConfigs配置块、签名信息保护、APK签名v1/v2/v3/v4

签名这件事,说白了就是给你的APK盖个章。证明这玩意儿是你写的,没被人动过手脚。我刚开始做Android开发那会儿,觉得签名就是个形式,随便搞个debug keystore就往上怼。直到有一次,我打release包给测试,结果安装时报签名冲突——嗯,那场面,至今难忘。

今天咱们就把签名这件事彻底聊透。从Keystore怎么生成,到signingConfigs怎么写,再到签名信息怎么藏,最后把v1到v4那堆签名方案理清楚。

6.1 Keystore的生成与管理

Keystore,就是你的签名仓库。里面存着密钥对——私钥你藏着,公钥塞进APK里。生成它,最正统的方式是用keytool,这玩意儿是JDK自带的,不用额外装。

keytool -genkey -v -keystore my-release-key.jks \
        -keyalg RSA -keysize 2048 -validity 10000 \
        -alias my-alias

解释一下这几个参数:

  • -keystore:输出的文件名,.jks是Java KeyStore格式,现在主流都用这个
  • -keyalg RSA:加密算法,RSA是标配
  • -keysize 2048:密钥长度,别用1024了,不安全
  • -validity 10000:有效期,单位是天。10000天大概27年,够你用到退休
  • -alias:别名,一个keystore里可以存多个密钥,用别名区分
我的习惯:有效期我一般设20000天。为什么?因为Google Play要求密钥有效期至少到2033年之后。你想想看,万一你app活个十年八年,密钥过期了,那更新包都发不了,多尴尬。

执行完命令,它会问你一堆信息:姓名、组织、城市、国家。这些其实不重要,填什么都行。但密码一定要记牢——丢了密码,神仙也救不了你。

6.2 signingConfigs配置块

有了keystore,接下来就是在build.gradle里配置签名。这块我见过太多人写死密码了,咱们先看标准写法,再说怎么优化。

android {
    signingConfigs {
        release {
            storeFile file("my-release-key.jks")
            storePassword "123456"
            keyAlias "my-alias"
            keyPassword "123456"
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
}

这段代码,功能上没问题。但你把密码明文写在代码里,传到Git上,那就等于把家门钥匙挂在了大门口。我在项目中遇到过,有同事把带密码的build.gradle直接push到了公开仓库——第二天就有人用他的签名打了个恶意包。所以,密码必须藏起来。

6.3 签名信息保护

保护签名信息,主流做法有两种:gradle.properties和环境变量。我推荐两个都用,灵活切换。

方式一:gradle.properties

在项目根目录的gradle.properties里加几行:

RELEASE_STORE_FILE=my-release-key.jks
RELEASE_STORE_PASSWORD=your_store_password
RELEASE_KEY_ALIAS=your_key_alias
RELEASE_KEY_PASSWORD=your_key_password

然后build.gradle里改成这样:

signingConfigs {
    release {
        storeFile file(RELEASE_STORE_FILE)
        storePassword RELEASE_STORE_PASSWORD
        keyAlias RELEASE_KEY_ALIAS
        keyPassword RELEASE_KEY_PASSWORD
    }
}

注意,gradle.properties默认会被Git忽略?不,它默认是纳入版本控制的。所以你要手动把它加到.gitignore里,或者单独创建一个gradle.properties.example作为模板。

我曾经踩过的坑:有一次我忘了把gradle.properties加到.gitignore,结果CI构建时一直报密码错误。查了半天才发现,CI环境里用的gradle.properties是从仓库拉下来的空文件。后来我改成用环境变量,才彻底解决这个问题。

方式二:环境变量

在CI/CD平台(Jenkins、GitHub Actions等)上设置环境变量,然后在build.gradle里读取:

signingConfigs {
    release {
        storeFile file(System.getenv("RELEASE_STORE_FILE") ?: "debug.jks")
        storePassword System.getenv("RELEASE_STORE_PASSWORD") ?: ""
        keyAlias System.getenv("RELEASE_KEY_ALIAS") ?: ""
        keyPassword System.getenv("RELEASE_KEY_PASSWORD") ?: ""
    }
}

这里用了?:操作符,如果环境变量没设置,就fallback到debug签名。这样本地开发时不影响,CI构建时自动用环境变量里的值。

6.4 APK签名方案:v1/v2/v3/v4

说到签名方案,很多人只知道v1和v2,其实现在已经到v4了。咱们一个一个说。

一句话总结:v1是传统方案,v2是主流方案,v3支持密钥轮换,v4用于增量更新。

v1签名(JAR签名)

这是最老的方案,Android刚出来时就在用。它是对APK里的每个文件单独签名,签名信息存在META-INF目录下。缺点很明显——慢,而且不安全。因为你可以解压APK,删掉某个文件,重新打包,只要不碰签名文件,就能绕过检查。

我在项目中遇到过,有用户反馈安装包损坏,查了半天发现是某些渠道商在APK里插了广告SDK,重新打包后v1签名没更新,导致校验失败。从那以后,我强制要求所有release包必须用v2签名。

v2签名(APK签名方案v2)

v2是Android 7.0引入的。它把整个APK当成一个整体来签名,签名信息嵌在APK文件中间的一个区块里。这样你没法单独修改某个文件而不破坏签名。安全性高了很多,而且验证速度也快。

现在Google Play要求所有新应用必须使用v2签名。说白了,v2已经是底线了。

v3签名(APK签名方案v3)

v3是Android 9.0引入的。它最大的特点是支持密钥轮换。什么意思?就是你可以在不更换包名的情况下,更换签名密钥。比如你的密钥过期了,或者泄露了,可以用新密钥重新签名,同时保留旧密钥的信任链。

这个功能听起来很美好,但实际用的人不多。为什么?因为密钥轮换需要你在build.gradle里配置signingConfigrotation,而且Google Play对这块支持有限。我个人建议,除非你有明确的密钥轮换需求,否则用v2就够了。

v4签名(APK签名方案v4)

v4是Android 11引入的,主要用于增量更新(Android App Bundle的增量安装)。它不直接替换v2/v3,而是作为一个补充。v4签名会生成一个.idsig文件,里面包含了APK的哈希信息,这样增量更新时只需要传输变化的部分,不用重新下载整个APK。

说实话,v4对普通开发者影响不大。除非你在做App Bundle的增量更新,否则基本用不到。

6.5 签名方案配置实战

在build.gradle里,你可以指定使用哪些签名方案:

android {
    signingConfigs {
        release {
            // ... 前面那些配置
            enableV1Signing true
            enableV2Signing true
            enableV3Signing false
            enableV4Signing false
        }
    }
}

我的建议是:

  • v1:关掉。除非你的应用还要支持Android 6.0以下(现在基本不可能)
  • v2:必须开。这是底线
  • v3:如果你有密钥轮换需求就开,否则关掉
  • v4:如果你在用App Bundle做增量更新就开,否则关掉
一个小技巧:你可以用apksigner工具来验证APK的签名信息。命令是apksigner verify --verbose my-app.apk。它会告诉你这个APK用了哪些签名方案,以及签名是否有效。我每次打release包后都会跑一遍这个命令,确保万无一失。

6.6 知识体系总览

下面这张图,把签名配置的整个流程串起来了。从生成keystore,到配置signingConfigs,再到保护签名信息,最后选择签名方案,每一步都有讲究。

Android 签名配置知识体系 Keystore 生成 keytool -genkey -v signingConfigs 配置 storeFile / storePassword 签名信息保护 gradle.properties / 环境变量 选择签名方案(v1 / v2 / v3 / v4) v1 (JAR签名) Android 1.0+ v2 (主流) Android 7.0+ v3 (密钥轮换) Android 9.0+ v4 (增量更新) Android 11.0+ 建议:开启 v2,按需开启 v3/v4,关闭 v1

签名配置这件事,说难不难,说简单也不简单。关键是养成好习惯:密码别写死,签名方案选对,每次打包后验证一下。做到这三点,签名这块基本就不会出问题了。


公众号:蓝海资料掘金营,微信deep3321