专栏名称: 鸿洋
你好,欢迎关注鸿洋的公众号,每天为您推送高质量文章,让你每天都能涨知识。点击历史消息,查看所有已推送的文章,喜欢可以置顶本公众号。此外,本公众号支持投稿,如果你有原创的文章,希望通过本公众号发布,欢迎投稿。
目录
相关文章推荐
鸿洋  ·  突发,这可能是软考最好过的一年! ·  3 天前  
郭霖  ·  一文了解 Gradle 插件 ·  5 天前  
鸿洋  ·  ANR?谁控制了触发时间? ·  5 天前  
鸿洋  ·  WebView 经历的各种干货方案分享 ·  6 天前  
郭霖  ·  使用 Jetpack Compose ... ·  1 周前  
51好读  ›  专栏  ›  鸿洋

Gradle配置,Android应用签名详解

鸿洋  · 公众号  · android  · 2024-10-28 08:35

正文


本文作者


作者:yechaoa

链接:

https://juejin.cn/post/7404778275019407412

本文由作者授权发布。


1
签名简介

应用签名是一种数字签名,主要用来验证应用的完整性以及发布者身份认证。
在Android应用发布之前非常重要的一环就是应用签名,Android系统要求所有APK在安装到设备上或更新之前都必须使用证书进行数字签名,Android系统会验证应用的签名。

版本更新时,新版本APK必须使用相同密钥签名,否则无法覆盖安装;如果签名变更,也无法更新应用,必须卸载重新安装。可见签名对Android应用发布的重要性。

2
签名文件

在Android中,签名一般包含三个信息,密钥库、秘钥和证书,在应用首次发布时,我们可以借助Android Studio工具来生成它们。
选择Build > Generate Signed Bundle / APK开始生成密钥库和秘钥。
选择签名类型,这里选择APK,然后点击Next按钮。
点击Create new按钮来创建新的秘钥库文件,如果已有秘钥库文件,选择对应路径即可。
在表单中填写如下两部分信息。
  1. 密钥库
    1. 密钥库路径(Key store path):输入一个存储密钥库文件的路径并命名,例如my-release-key.jks
    2. 密钥库密码(Password):输入并确认密钥库的密码。
  2. 秘钥
    1. 秘钥别名(Alias):为新的密钥创建一个别名,例如my-key-alias
    2. 秘钥密码(Key password):输入并确认密钥的密码。通常与密钥库的密码相同,但也可以选择不同的密码。
    3. 有效期(Validity (years)):设置密钥的有效期,例如25年(通常是设置一个较长的时间)。
    4. 证书(Certificate):填写证书信息,包括名字、组织单位、组织、市、州/省和国家代码(例:CN)。

    填写完所有信息之后,点击OK按钮即可创建密钥文件。

    3
    应用签名

    密钥库和秘钥创建成功之后,会自动回到上一页并填充我们刚才填好的签名信息。
    然后点击Next按钮,选择需要签名的构建变体。
    一般选择release,也可以多选。
    点击Create按钮即开始构建并签名了。
    打包构建完成后,签名好的APK文件在app/变体/目录下:


    4
    签名配置

    上面可视化的签名打包方式,一般适用于临时构建,或应用渠道较少的场景。
    好处是操作方便,不易泄露秘钥的密码等关键信息。
    不足的是不适用自动化构建(CI/CD)场景,以及多渠道构建场景下,可能会出现渠道选漏的情况。
    如果在工作中,渠道包是自动化构建的,那么就需要在build.gradle文件中进行签名配置了。
    签名配置步骤如下:
    第一步,在项目的根目录下创建一个名为keystore.properties的文件,并在其中包含以下信息:
    storePassword=myStorePassword
    keyPassword=myKeyPassword
    keyAlias=myKeyAlias
    storeFile=myStoreFileLocation
    第二步,在build.gradle文件中,按如下方式加载keystore.properties文件(必须在android代码块前面):
    import java.util.Properties
    import java.io.FileInputStream

    val keystorePropertiesFile = rootProject.file("keystore.properties")
    val keystoreProperties = Properties()
    keystoreProperties.load(FileInputStream(keystorePropertiesFile))

    android {
      ...
    }
    ...
    第三步,在signingConfigs{ }中配置存储在keystoreProperties文件中的签名信息:
    android {
        signingConfigs {
            create("config") {
                keyAlias = keystoreProperties["keyAlias"as String
                keyPassword = keystoreProperties["keyPassword"as String
                storeFile = file(keystoreProperties["storeFile"as String)
                storePassword = keystoreProperties["storePassword"as String
            }
        }
        ...
      }
    第四步,在构建类型buildTypes中引用signingConfigs{ }中的签名配置:
        buildTypes {
            release {
                signingConfig = signingConfigs.getByName("release")
                // ...
            }
        }
    最后点击Sync同步即可。
    这样就可以使用命令./gradlew assembleRelease来进行批量签名打包了。
    在本地开发阶段,Android Studio会自动生成Debug签名,无需手动配置,但是Debug签名无法用于应用发布。


    5
    签名方案

    5.1、介绍

    v1签名 (Jar签名):传统的JAR签名机制,验证速度慢,但兼容早期版本(7.0以前)。v1 签名不保护APK的某些部分,例如ZIP元数据。
    v2签名 (APK签名方案):Android 7.0引入,基于Merkle哈希树,比v1签名更安全,验证速度更快,支持Android 7.0及以上。
    v3签名 (APK签名方案):Android 9.0引入,继承了v2签名的性能优势和安全性,并对整个APK文件进行签名检查,还增加了秘钥轮换能力,就是允许对应用的签名密钥进行更新,而不会影响应用的安装和更新。
    v3.1签名 (APK签名方案):Fix版本,Android 13.0引入,修复了v3方案中秘钥轮换的已知问题。
    v4签名 (APK签名方案):Android 11.0引入,主要是在验证方面,提升了APK增量更新和安装速度。
    美团基于v2签名方案的多渠道打包方案(walle)原理是:打包过程中在META-INF目录下添加空文件用来作为渠道的唯一标识。
    在v3签名方案中,基于 Merkle 哈希树对整个APK文件进行签名检查,确保APK文件的完整性,对APK进行的任何修改都会使APK签名作废,从而导致安装失败。而META-INF作为APK的一部分(签名块),自然也是会被签名检查,且不能修改的。
    所以这也是walle为什么会在Android 9.0(v3)以后失效的原因。

    5.2、选择签名方案

    那这几个签名方案怎么选呢?不妨先看看市面上大型APP它们是怎么选的?


    在查看了微信、淘宝和拼多多的签名方案之后,发现它们都惊人的一致。
    v1、v2的兼容性和安全性不错,一般是必选的,v3、v4有新特性,性能较好,可以结合自己的项目按需配置(v4需要与v2或v3结合使用)。

    5.3、配置签名方案

    确定了签名方案之后,就是怎么让签名方案生效了,这就需要在build.gradle文件中添加签名方案配置了。
    示例配置如下:
        // 配置签名方案
        buildTypes {
            release {
                // ...

                // 启用v1签名
                v1SigningEnabled true

                // 启用v2签名
                v2SigningEnabled true

                // 启用v3签名
                v3SigningEnabled true

                // 启用v4签名
                v4SigningEnabled true
            }
        }
    新的签名格式向后兼容,比如使用v3签名方案的APK可以在5.0的设备上安装,前提是包含v1签名方案。

    5.4、APK签名验证流程

    以v4签名为例,验证流程如下:
    1. 校验APK文件中是否存在v4签名文件,存在则继续确认v2或v3方案,因为v4签名本身不足以验证APK的完整性和来源,所以需要与v2或v3方案结合使用,验证通过则允许安装;如果不存在v4签名文件或验证不通过则继续走v3签名验证流程。
    2. v3签名方案的验证流程,先校验APK文件中是否存在v3签名方案的签名块,存在且校验通过则允许安装,否则拒接安装;如果不存在则继续走v2签名验证流程。
    3. v2签名方案的验证流程,先校验APK文件中是否存在v2签名方案的签名块,存在且校验通过则允许安装,否则拒接安装;如果不存在则继续走v1签名验证流程。
    4. v1签名方案的验证流程,验证通过则允许安装,否则拒接安装。
    在v2、v3、v4签名验证流程中,最大的区别在于,v2、v3的签名规则验证不通过会直接拒接安装,v4则是继续往下走。

    5.5、查看应用签名方案

    查看一个已经签名的APK文件使用了哪种签名方案,通常需要一些工具来解析和分析APK的签名信息。
    我们可以使用Android SDK提供的apksigner工具,apksigner主要用于签名和验证APK文件,通过apksigner可以查看APK的签名信息。

    5.5.1、配置环境

    在使用apksigner之前,需要先确认环境变量是否配置正确。
    以macOS系统为例:
    找到~/.bash_profile~/.bashrc 文件,进入编辑。
    在文件末尾添加以下内容:
    export PATH=$PATH:~/Library/Android/sdk/build-tools/33.0.1
    Android SDK路径和版本号替换成你自己的。
    然后执行命令刷新文件是环境变量配置立即生效:
    source ~/.bashrc
    // or
    source ~/.zshrc

    5.5.2、apksigner使用

    配置好环境之后,执行以下命令:
    apksigner verify --verbose --print-certs /Users/yechao/AndroidStudioProjects/GradleX/app/release/app-release.apk
    apk地址换成你自己的。
    输出如下图:

    在输出信息中,可以看到v1 scheme、v2 scheme、v3 scheme和v4 scheme的相关信息,true表示该签名方案开启,false表示关闭,默认开启v1、v2方案。

    6
    获取签名信息

    在上传应用市场或集成第三方SDK的时候,通常会要求填写APK相关的信息来进行验证,其中包括签名信息,比如SHA-1、SHA-256。
    下面来介绍几种常用的提取签名信息的方式。

    6.1、signingReport

    signingReport是Gradle插件提供的一个能力,用于生成签名报告。
    在Gradle面板中找到signingReport任务,app > Tasks > android > signingReport。
    在执行signingReport任务前,确认在build.gradle文件中已经正确配置了signingConfigs。
    双击执行signingReport任务,在构建日志中会同时输出debug和release签名信息。
    如下图:

    6.2、keytool

    keytool是Java SDK自带的一个工具,可以用来查看密钥库文件(例如.jks或.keystore)中的签名信息,包括SHA-1指纹。
    keytool 支持两种文件方式查看签名信息,分别是keystore和apk。

    6.2.1、keystore方式

    命令如下:
    keytool -list -v -keystore your-keystore-file.jks
    输出:

    6.2.2、apk方式

    命令如下:
    keytool -printcert -jarfile your-apk-file.apk
    输出:

    7
    签名安全

    如果签名文件丢失或者损坏,唯一的解决办法就是生成新的签名文件,但是会导致应用版本更新问题,需要用户卸载重装,沉没成本较大。
    所以,签名文件和签名相关信息一定要保存好,定期做好备份。
    一些安全建议:
    • 不要直接明文配置在build.gradle文件中。
    • 尽量不要使用网络传输,选择离线传输方式,避免签名秘钥泄露。
    • 如果是出海应用,可以将签名秘钥上传至Google Play,由Google来对秘钥进行管理和保护,可以提高签名秘钥的安全性。
    • 可以将签名文件放在远端,打包时将签名文件下载到本地,打包结束后自动删除文件。
    • 在CI/CD构建中,可以将签名文件放在CI服务上,并将签名信息配置到环境变量中,运行时从CI服务中读取。
    • 将签名文件和签名配置单独抽成一个项目,然后以插件的形式依赖进主项目里,也可以做到隔离效果。

    8
    总结

    本章我们了解了Android应用签名的重要性、具体的实现方法,和签名方案的介绍及方案选择,还有签名验证流程,最后是一些关于签名安全的建议。

    GitHub

    https://github.com/yechaoa/GradleX

    相关文档

    Sign your app

    https://developer.android.com/studio/publish/app-signing

    apksigner

    https://developer.android.com/tools/apksigner?hl=zh-cn

    SigningConfig

    https://developer.android.com/reference/tools/gradle-api/8.2/com/android/build/api/dsl/SigningConfig

    Application Signing

    https://source.android.com/docs/security/features/apksigning




    最后推荐一下我做的网站,玩Android: wanandroid.com ,包含详尽的知识体系、好用的工具,还有本公众号文章合集,欢迎体验和收藏!


    推荐阅读

    Android Gradle Plugin插件详解
    简洁高效:类抖音视频列表设计思路
    【Android】谷歌为什么不帮我默认实现啊,ImageGetter 和 TagHandler 的作用与区别



    扫一扫 关注我的公众号

    如果你想要跟大家分享你的文章,欢迎投稿~


    ┏(^0^)┛明天见!