Gradle笔记_4-创建构建Variant

Gradle笔记_4-创建构建Variant

开发一个应用时,通常有几个不同版本。
最常见的情况是,测试版本和生产版本,可能 baseUrl 不同,Logger 开关不同等。
除此之外,你的应用可能还有一个免费版和付费版。
这样的话,就需要处理四种不同的版本:免费测试版、付费测试版、免费生产版、付费生产版。
不同版本的不同配置让项目变得是非复杂。

在 Gradle 中有一些便捷和可扩展的概念用来定位这些常见问题。

  • 构建类型:每个由 Android Studio 创建的新项目都会生成 debug 和 release 构建类型(buildType)。
  • product flavor:不同定制的产品,用于管理多个应用或依赖库版本。

构建类型(buildType)和 product flavor 能很容易解决上面测试、生产版本和免费、付费版本的问题。
构建类型(buildType)和 product flavor的结合称之为 variant(变体; 变种,变形,变量,转化)。

4.1 构建类型(buildType)

可以在 buildTypes 代码块中定义构建类型。Android Studio 构建文件的标准 buildTypes 代码块:

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

新模块的默认 build.gradle 文件配置了一个构建类型,release。该构件类型用于:

  • 禁用清除无用的资源(通过设置 minifyEnabled 为 false)
  • 定义默认 proguard 配置文件的位置

release 并不是被创建的唯一的构建类型。默认情况下,每个模块都有一个 debug 构建类型。它是默认构建类型,可以在 buildTypes 代码块中覆写它。

debug 构建类型中,debuggable 属性默认为 true,其他构建类型中,默认为 false。

4.1.1 创建构建类型

当默认设置不够用时,可以创建自定义构建类型,只需在 buildTypes 代码块中新增一个对象,例如下面 staging 自定义构建类型:

android {
	buildTypes {
		staging {
			applicationIdSuffix ".staging"
			versionNameSuffix "-staging"
			buildConfigField "String", "API_URL", "\"http://staging.example.com/api\""
		}
	}
}

注意:在 app 模块添加了 staging 构建类型,相应地在每个模块中都要添加 staging 构建类型,否则构建失败。

applicationIdSuffix

staging 构建类型针对 applicationId 定义了一个新的后缀,使其和 debug 以及 release 版本的 applicationId 不一样。如下:

  • debug:com.package
  • release.package
  • staging:com.package.staging
    因 applicationId不同,相同设备上可以同时安装 release 版本 和 staging 版本。

versionNameSuffix

staging 构建类型定义了一个版本名后缀,使生成的 apk 带上 -staging 后缀(app-staging.apk,默认有:app-release.apk 和 app-debug.apk)。

buildConfigField

buildConfigField 属性相当于在 BuildConfig 中添加了一个 String 类型的变量 API_URL。可以在不同的构建类型中配置相同变量,设置不同的值。
项目代码中,可以通过 BuildConfig.API_URL 获取到对应的值。(新添加的变量,需要 rebuild 一下)

在创建一个新的构建类型时,还可以用另一个构建类型的属性来初始化该构建类型:

android {
	buildTypes {
		release {
			staging.initWith(buildTypes.debug)
			staging {
				applicationIdSuffix ".staging"
				versionNameSuffix "-staging"
				debuggable false
			}
		}
	}
}

initWith() 创建了一个新的构建类型,并且复制了一个已存在的构建类型的所有属性到新的构建类型中。
我们可以在新的构建类型中复写属性和定义额外的属性。

更多的配置可通过点击 Android Studio 工具栏上 Build > Edit Build Types,会弹出一个对话框,里面可对每个构建类型(build type)作修改。下面是构建类型可修改的属性:

  • Application ID Suffix:对应 applicationId 后缀。
  • Version Name Suffix:对应 versionNameSuffix 版本名称后缀。
  • Debuggle:对应 debuggable,是否可调试。
  • Signing Config:对应 signingConfig,可创建 signingConfigs 代码块,配置每个构建类型的签名配置,再在这里赋值签名配置。
  • Minify Enable:对应 minifyEnabled,是否清楚无用资源。
  • ProGuard Files:对应 proguardFiles,配置混淆文件。
  • Manifest Placeholder:对应 manifestPlaceholders,清单文件中的占位符(可在清单文件中通过 ${}获取到)。
  • Multi Dex Enable:对应 multiDexEnabled。

  • 另外还有前面提到过的 resValue(会在 build 目录下生成 build\generated\res\resValues\debug\values\gradleResValues.xml,里面包含所有的 resValue 属性)。
4.1.2 源集

源集即 source set。

当创建一个新的构建类型时,Gradle 也会创建一个新的源集。
源集目录名称默认和构建类型相同,需要手动创建该源集的目录,用于存放构建类型对应的源码和资源。

Android Studio 中,选中 src 目录,右键,New > Folder > Java Folder,创建 Java Folder,会弹出对话框,里面可以选择 Target Source Set。
通过上面的配置,目前可以选择,debug、release、staging。
右键 > New,选择其他选项,比如 Activity,弹出对话框中也都可以选择 Source Set。

下面是标准的 debug 和 release,以及新创建的 staging 构建类型的目录结构。
app

  • src
    • debug
      • java
        • com.package
          • Constants.java
      • res
        • layout
          • activity_main.xml
      • AndroidManifest.xml
    • main
      • java
        • com.package
          • MainActivity.java
      • res
        • drawable
        • layout
          • activity_main.xml
      • AndroidManifest.xml
    • release
      • java
        • com.package
          • Constants.java
      • res
        • layout
          • activity_main.xml
      • AndroidManifest.xml
    • staging
      • java
        • com.package
          • Constants.java
      • AndroidManifest.xml

你可以针对特定的构建类型复写某些属性,为某些构建类型添加自定义代码,以及为不同构建类型添加自定义布局或字符串。

当添加 Java 类到构建类型时,记住这一过程是互斥的。比如,在 staging 源集中添加了 CustomLogic.java,能够添加相同的类到 debug 和 release,但不能添加到 main 中。

当使用不同的源集时,资源会被一种特殊的方式处理:

  • Drawables 和 layout 文件将完全覆盖在 main 源集中有相同名称的资源。
  • values 文件夹中的文件不会被覆盖(例如 strings.xml),Gradle 将合并构建类型中的资源到 main 资源中。

例如,在 main 源集中 strings.xml 如下:

<resources>
	<string name="app_name">TypesAndFlavors</string>
	<string name="hellow_world">Hello world!</string>
</resources>

并且在 staging 构建类型源集中 strings.xml 如下:

<resources>
	<string name="app_name">TypesAndFlavors STAGING</string>
</resources>

那么构建 staging 时,会合并两个文件,合并后的 strings.xml 如下:

<resources>
	<string name="app_name">TypesAndFlavors STAGING</string>
	<string name="hellow_world">Hello world!</string>
</resources>

即 staging 与 main 中资源取并集,相同部分,staging 中的资源会覆盖 main 源集中的资源。
release 和 debug 也一样。

manifest 文件与之类同。当一个构建类型中创建了 manifest 文件,只需添加需要的标签,最终Android插件会合并 manifest。

4.1.3 依赖

每个构建类型都可以有自己的依赖。Gradle 会为每个构建类型创建新的依赖配置,如下所示:

dependencies {
	implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.2.1'
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
	
    debugImplementation 'de.mindpipe.android:android-logging-log4j:1.0.3'
    // releaseImplementation ''
    stagingImplementation 'de.mindpipe.android:android-logging-log4j:1.0.3'
}

你可以以这种方式结合任何构建配置的构建类型,让依赖变得更加具体。

4.2 product flavor

product flavor 用来创建不同的版本。
应用场景:

  • 应用的免费版和付费版。
  • 一个机构为多个客户端构建相同功能而品牌不同的应用(项目)。
  • 多渠道打包等。

product flavors 极大简化了基于相同代码构建多个版本的应用的进程。

如果你需要一个全新的 App,独立于你已有的应用发布,那么 product flavor 就是你需要的。

4.2.1 创建 product flavor

与创建构建类型相似,你可以通过在 productFlavors 代码块中添加新的 product flavor 来创建:

android {
    flavorDimensions 'color'
    productFlavors {
        red {
            applicationId 'com.gradleforandroid.red'
            versionCode 3
        }
        blue {
            applicationId 'com.gradleforandroid.blue'
            minSdkVersion 21
            versionCode 4
        }
    }
}

product flavor 和构建类型相比有不同的属性。
product flavor 是 ProductFlavor 类的对象,就像构建脚本的 defaultConfig 对象。这就意味着 defaultConfig 和你的所有 product flavors 享有相同的属性。

4.2.2 源集(source set)

和构建类型类似,product flavor 也可以拥有它们自己的源集(source set)目录。

为一个 flavor 创建一个源集文件夹,就和创建一个有 flavor 名称的文件夹一样,甚至可以为一个特定构建类型和 flavor 的结合体创建一个文件夹,该文件夹的名称将是 flavor 名称 + 构建类型名称。
比如,你想让 blue flavor 的 release 版本有一个不同的应用图标,name文件夹名称将会被叫做 blueRelease。
合并文件夹的组成将比构建文件夹和 product flavor 文件夹拥有更高优先级。

可能的源集名称可以看做是构建类型和 flavor 的组合。

经过上面和之前的配置,我们有以下源集:

main
red
blue
debug
release
staging
redDebug
blueDebug
redRelease
blueRelease
redStaging
blueStaging

main 源集(主源集)是创建项目时默认的源集,其他源集都可以看成是对它的覆盖(Java文件不能被覆盖)。
根据上面的源集名称,我们可以根据需要,在 src 目录下创建对应的源集(source set)目录。

4.2.3 多种定制的版本

某些情况下,可能需要更进一步,创建 produce flavor 的结合体。
例如:客户 A 和客户 B 在他们的 App 中都想要免费版和付费版,并且使基于相同的代码、不同的品牌。
通常思维下,你可能增加创建四个 flavor,redFree、redPaid、blueFree、bluePaid,这样比较冗杂,并不是最佳做法。
使用 flavor 维度(dimension) 是结合 flavor 的有效方法。如下所示;

android {
    flavorDimensions 'color', 'price'
    productFlavors {
        red {
            dimension 'color'
        }
        blue {
            dimension 'color'
        }
        free {
            dimension 'price'
        }
        paid {
            dimension 'price'
        }
    }
}

当为 flavor 添加了维度(dimension)后,要为每个 flavor 都添加维度(dimension),否则会构建(build)错误。
flavorDimensions 数组定义了维度,维度的顺序非常重要。当结合两个 flavor 时,他们可能定义了相同的属性或资源。在这种情况下,flavor 维度数组的顺序就决定了哪个 flavor 配置将被覆盖。上面例子中,color 维度覆盖了 price 维度。该顺序也决定了构建 variant 的名称。

结合之前的配置,上面配置的 flavor 将会生成下面这些构建 variant:

blueFreeDebug
blueFreeRelease
blueFreeStaging
bluePaidDebug
bluePaidRelease
bluePaidStaging
redFreeDebug
redFreeRelease
redFreeStaging
redPaidDebug
redPaidRelease
redPaidStaging

构建 variant 查看可以在 Android Studio 左侧栏 Build Variants 查看(Active Build Variant 栏下,点击每个 module 的这一栏,比如 app 的,就会弹出下拉列表,显示所有的 variant。
如果没有找到,可以点击 View > ToolWindows > Build Variants 。
build variants
在打包的时候也可以看到所有的 Build Variants:
在这里插入图片描述

点击工具栏 Build > Edit flavors
Edit flavors
弹出对话框
flavors
可以创建 flavors,以及配置 flavor 的参数。常用可配置参数如下:

  • Dimension:dimension,维度。
  • Application ID:applicationId,应用id。
  • Application ID Suffix:applicationIdSuffix,应用id后缀。
  • Version Code:versionCode,版本号。
  • Version Name:versionName,版本名称。
  • Version Name Suffix:versionNameSuffix,版本名后缀。
  • Target SDK Version:targetSdkVersion,目标 sdk 版本。
  • Min SDK Version:minSdkVersion,最小 sdk 版本。
  • Signing Config:singingConfig,签名配置。
  • ProGuard Files:proGuardFiles,混淆文件路径配置。
  • Manifest Placeholders:manifestPlaceholders,清单文件占位符,配置以后,可在 manifest 通过 ${} 引用。
  • Multi Dex Enabled: multiDexEnabled,多分包开关。

可以看到,很多参数与 defaultConfig 代码块相同,印证了上面提到的:defaultConfig 和你的所有 product flavors 享有相同的属性。配置了这些参数会覆盖 defaultConfg 中的属性:

android {
    defaultConfig {
        applicationId "com.wzhy.gradlestu"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
}

manifestPlaceHolders

上面提到 manifestPlaceHolders,清单文件占位符,当在 manifest 中通过 ${} 引用后,可以在构建时动态替换 manifest 中的值。在用同一套代码构建不同版本或项目时,可以动态配置第三方 SDK 的 AppKey 等,非常有用。例如配置友盟的 appKey:

<meta-data
	android:name="UMENG_APPKEY"
	android:value="${umeng_app_key}"/>
androdid {
    flavorDimensions 'color', 'price'
    productFlavors {
        red {
            dimension 'color'
            applicationId 'com.gradleforandroid.red'
            versionCode 3
        }
        blue {
            dimension 'color'
            applicationId 'com.gradleforandroid.blue'
            minSdkVersion 21
            versionCode 4
        }
        free {
            dimension 'price'
            manifestPlaceholders = [umeng_app_key: "免费版 appKey"]
 			// 或 manifestPlaceholders umeng_app_key: "免费版 appKey"
        }
        paid {
            dimension 'price'
            manifestPlaceholders = [umeng_app_key: "付费版 appKey"]
        }
    }
}

注意:在一个 flavor 的 manifestPlaceHolders 中配置了一个参数后,相同 维度(dimension)的其他 flavor 都要配置,Key 相同,值可以不同。

manifestPlaceHolders 既可以在 productFlavors 中配置,也可以在 构建类型(buildTypes)中配置。

4.3 构建 variant

构建 variant 是构建类型(build type)和 product flavor 结合的结果。
点击 Android Studio 左侧栏 Build Variants,弹出工具窗。
如果没有找到,可以点击 View > ToolWindows > Build Variants 。

build variants window
在 Build Variants 工具窗的 Active Build Variant 栏下,点击每个 module 的这一栏,比如 app 的,就会弹出下拉列表,列出了所有的 variant,并允许他们之间切换。修改选中的构建 variant,将会影响当 Run 按钮被点击时运行哪个 variant。

select variant
通过构建 variant,点击 Run 按钮或 Make Project时,运行到真机或模拟器后,会在 app/build/outputs/apk 下生成相应的目录(与源集对应的)。经过上面 build variant 的选择,会在相应目录下生成 apk。比如:build\outputs\apk\blueFree\debug\app-blue-free-debug.apk

apks

4.3.1 任务

Gradle 的 Android 插件将会为你配置的每一个构建 variant 创建任务。
一个新的 Android 应用默认有 debug 和 release 两种构建类型,所以你可以用 $ gradlew assembleDebug$ gradlew assembleRelease来分别构建两个 APKs,也可以用 $ gradlew assemble 一次生成两个 APKs。
使用命令

$ gradlew tasks

可以找到 assembleassembleDebugassembleRelease 三个任务。

当添加一个新的构建类型时,新的任务也将被创建,比如添加 staging,会新增一个 assembleStaging

一旦开始添加 flavor ,构建类型 和 flavor 相结合,全新的任务系列将会被创建。
假设添加一个 blue flavor,使用命令查看任务:

$ gradlew tasks

可以看到下面几个任务:
assemble:组装所有的 variant 对应的 apks。
assembleBlue:组装 blue flavor 下,每个构建类型对应的 apks,blueRelease 和 blueDebug。
assembleDebug:组装 debug 构建类型下,每个 flavor 对应的 apks,即 blueDebug。
assembleRelease:组装 release 构建类型下,每个 flavor 对应的 apks, 即 blueRelease。

使用命令行还可以具体执行:
assembleBlueDebug:组装 blue flavor 的 debug 版本。
assembleBlueRelease:组装 blue flavor 的 release 版本。

4.3.2 源集(source set)

构建 Varient,是一个构建类型和一个或多个 product flavor 的结合体,其可以有自己的源集文件夹。
例如,debug 构建类型和 blue flavor 和 free flavor 创建的 variant 可以有自己的源集 src/blueFreeDebug/java/。其可以通过使用 sourceSets 代码块开覆盖文件夹的位置。

可通过 右键 > New > Folder > Java Folder,弹出 New Android Component 弹框,可以指定 Target Source Set。如下所示:

Target Source Set

4.3.3 源集合并资源和 manifest

源集的引入额外增加了构建进程的复杂性。Gradle 的 Android 插件在打包之前将 main 源集和构建类型源集合并在一起。
此外,library 项目也可以提供额外的资源,这些也需要被合并。
这同样适用于 manifest 文件,最终所有的 manifest 文件会合并为一个。

如果资源在 flavor 和 main 源集中都有申明,flavor 中的资源优先级更高,其中的资源最终会被打包。
在 library 项目中申明的资源通常具有最低优先级。

资源和 manifest 的优先级顺序:Build Type > Flavor > Main > Dependencies

4.3.4 创建构建 variant

Gradle 让处理复杂的构建 variant 变得简单。即使如下 3 种构建类型(build type),4 个 product flavor(产品品类)(2个维度(dimension)),构建文件依然很简洁:

android {
	defaultConfig{//...}
    buildTypes {
        debug {
            minifyEnabled false
            debuggable true
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            buildConfigField "String", "API_URL", "\"http://test.example.com/api\""
            resValue "string", "appname", "gradlestu_debug"
        }
        release {
            minifyEnabled false
            debuggable false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            buildConfigField "String", "API_URL", "\"http://release.example.com/api\""
            debuggable false
            resValue "string", "appname", "gradlestu_release"
        }
        staging.initWith(buildTypes.debug)
        staging {
            applicationIdSuffix ".staging"
            versionNameSuffix "-staging"
            buildConfigField "String", "API_URL", "\"http://staging.example.com/api\""
            debuggable true
            resValue "string", "appname", "gradlestu_staging"
        }
    }
    
    flavorDimensions 'color', 'price'
    productFlavors {
        red {
            dimension 'color'
            applicationId 'com.gradleforandroid.red'
            versionCode 3
            resValue "color", "flavor_color", "#ff0000"
        }
        blue {
            dimension 'color'
            applicationId 'com.gradleforandroid.blue'
            minSdkVersion 21
            versionCode 4
            resValue "color", "flavor_color", "#0000ff"
        }
        free {
            dimension 'price'
            manifestPlaceholders umeng_app_key: "免费版 appKey"

        }
        paid {
            dimension 'price'
            manifestPlaceholders umeng_app_key: "免费版 appKey"
        }
    }
}

上面代码中,在构建类型(build type)中添加了 buildConfigField ,一个 String 类型的变量 API_URL,用来区分不同环境的 Api Url ;在构建类型中添加了 resValue, 一个 String 类型的变量 appname 用于 manifest 中设置应用名称;在 productFlavors(产品品类)中的 color 维度的 flavor 中也添加 resValue,变量名是 flavor_color,是一个颜色,blue flavor 为蓝色,red flavor 为红色。

通过上面的配置,可以通过 BuildConfig.API_URL 获取到构建文件中通过 buildConfigFileld 配置的值,而且不同构建类型(build type)的 variant 下的 APK 使用对应不同的值。还以通过 R.string.appname 获取构建类型中通过 resValue 配置的值,不同构建类型取对应不同的值,通过 R.color.flavor_color 获取 flavor 中对应的值,不同 flavor 获取对应不同的值。

那么,为什么可以通过 BuildConfig.R. 取到构建文件中的值?答案就在下面:

在 Android Studio 中的 Teriminal 使用命令

$ gradlew assemble

组装构建所有的 variant 的 apk,在 app/generated 目录下会生成一些文件。
首先就是 BuildConfig.java 文件,如下图所示,

BuildConfig
运行 assemble 命令后,Gradle 为我们在 app/build/source/buildConfg 目录下生成了所有的构建 variant 目录(即 <flavor 目录>/ <build type 目录>),每个 build type 目录/包名下会有一个 BuildConfig.java 文件,打开文件,我们就可以看到在构建文件中配置的 API_URL 变量。同时,还有其他相关信息,如 APPLICATION_IDBUILD_TYPEFLAVOR 等,都可以用 BuidConfig. 获取。换一个文件打开,里面的数据对应改变,如下图所示:

BuildConfig_bluePaid_staging
接着,就是 resValue 对应的文件,Gradle 同样会在 assemble 的同时生成对应文件,如下图所示:

resValue_blueFree_debug
在 app/build/generated/res/ 下会生成 resValues 目录,下面是 flavor 目录,flavor 下是 build type 目录,里面会有 values 目录,里面就是我们要找的文件 gradleResValues.xml。打开文件,我们就找到了构建文件(build.gradle)中配置的 resValue。不同的 variant 对应的文件中的值不同,如下是 app/build/generated/res/redPaid/Staging/values/gradleResValues.xml。

resValue_redPaid_staging
下面就是生成的资源文件目录,app/build/generated/res 对应项目的 res 目录,app/build/generated/source 对应项目的 src 目录。

generated_files
上面所有的文件最终都会被打包合并到对应输出的 apk 文件中,如下所示:

apks
一个注意点,app-blue-free-release-unsigned.apk ,后面有一个 unsigned 后缀。它表示这个 apk 没有被签名,除了 debug 包默认有签名,其他apk 默认都是需要签名的,没有签名就会有 unsigned 后缀。发现 staging 包后也没有 unsigned 后缀,是因为这行代码

buildTypes {
	......
	staging.initWith(buildTypes.debug)
	......
}

签名涉及到签名配置。

双击生成的 apk,比如 app-blue-free-release-unsigned.apk ,Android Studio 会展是 apk 中的内容。如下图所示:

app-blue-free-release-unsigned.apk

发现 flavor_color 最终被合并打包到对应的 apk 的 resources.arsc 下,色值与构建文件中和生成文件中的相互对应。
同样可以在 classes.dex 下找到 BuildConfig.java,里面可以找到 API_URL 属性。如打开 app-blue-paid-staging.apk,可以看到多个 .dex 文件,从 classes2.dex (有的是在其他 dex 文件) 中找到了 BuildConfig.java 文件,右键点击查看字节码文件,找到了属性 API_URL,与构建文件中的配置和上面所生成的 BuildConfig.java 文件中内容对应。


如果还想知道主源集(main)中的资源和其他源集中的资源是如何合并的,可以通过分析 apk 来得知。比如可以点开 AndroidManifest.xml 文件看一看。

一些名词:构建类型 build type, 产品品类 product flavor,(品类的)维度 dimension

4.3.5 variant 过滤器

在构建中,可以忽略某些 variant。
作用:

  • 可以通过 assemble 命令来加快构建所有 variant 的进程,并且你的任务列表不会被任何无须执行的任务污染。
  • Android Studio 的 BuildVariants 侧边栏切换默认 variant 时,不会显示过滤的构建 variant。

在 app 或 library 构建文件中 添加如下示例代码:

android.variantFilter { variant ->
    if (variant.buildType.name.equals('release')) {
        variant.getFlavors().each() { flavor ->
            if (flavor.name.equals('blue')) {
                variant.setIgnore(true)
            }
        }
    }
}

同步一下 gradle,发现侧边栏对应的 blue flavor 的 release variant 没有了,如下图所示

BuildVariants ignore

clean 一下工程, 重新执行命令 $ gradlew assemble,发现生成的文件和 apk 目录中,blueFree 和 bluePaid 目录下的 release 目录及其文件都不见了。可见确实是被过滤掉了。

variant ignore

4.4 签名配置

上面我们提到,未签名的 apk 文件会带有 unsigned 后缀,比如 app-blue-free-release-unsigned.apk

在应用发布到应用市场之前,都需要用私钥给它签名。

如果你有一个付费版和免费版或针对不同用户的不同应用,那么需要为每个 flavor 使用不同的私钥签名。

签名配置示例代码如下:

android {
	signingConfigs {
		staging.initWith(signingConfigs.debug)
		
		release {
			storeFile file("gradlestu.keystore")
			storePassword "gs123456"
			storeAlias "gradlestu"
			keyPassword "gs123456"
		}
	}
}

代码中,我们创建了两个不同的签名配置。

Android 插件使用了一个通用 keystore 和一个已知密码自动创建了 debug 配置,所以没有必要为 debug 构建类型再创建一个签名配置了。

上面代码中,staging 配置使用了 initWith(),会从另外一个签名配置中复制所有属性,意味着 staging 构建是通过 debug 秘钥签名的。

release 配置中,storeFile 指定了 keysotre 文件的路径为该构建文件所在目录的 gradlestu.keystore 文件,之后就是别名和两个密码(秘钥库口令和秘钥口令)。

定义了签名配置以后,需要将它们用到构建类型或 flavor 中。构建类型和 flavor 中都有一个 signingConfig 属性,如下所示:

android {

	buildTypes {
		release {
			signingConfig signingConfigs.release
		}
	}
    flavorDimensions 'color'
    productFlavors {
        red {
            dimension 'color'
        }
        blue {
            dimension 'color'
            signingConfig signingConfigs.staging
        }
    }
}

如果想为每个 flavor 使用不同的凭证,需要创建不同的签名配置,配置到对应的 flavor 下。

android {
    flavorDimensions 'color'
    productFlavors {
        red {
            dimension 'color'
            signingConfig signingConfigs.release
        }
        blue {
            dimension 'color'
            signingConfig signingConfigs.relsease
        }
    }
}

当为 flavor 添加了签名配置后,会覆盖构建类型的签名配置,上面的配置就会影响 debug 和 staging 的签名。
如果不想这样,应该为每个构建类型的每个 flavor 分配不同的秘钥,如下所示:

android {
	buildTypes {
		release {
			productFlavors.red.signingConfig singningConfig.red
			productFlavors.blue.signingConfig singningConfig.blue
		}
	}
}

这样就在不影响 debug 和 staging 构建类型的情况下为 red flavor 和 blue flavor 配置了不同的签名。

4.4.1 生成签名文件

两种方式:

  1. 使用命令行生成签名文件(使用 JDK bin 目录下的 keytool.exe 工具来生成数字证书)。
  2. 利用 Android Studio 生成签名文件。

使用命令行生成签名文件

$ keytool -genkeypair -alias gradlestu -keyalg RSA -validity 400 -keystore gradlestu.keystore

选项说明:

  • genkeypair:指定生成数字证书
  • alias:指定生成数字证书的别名
  • keyalg:指定生成数字证书的算法。使用RSA算法
  • validity:指定生成数字证书的有效期
  • keystore:指定生成数字证书的存储路径
C:\Users\wzy\Desktop>keytool -genkeypair -alias gradlestu -keyalg RSA -validity 400 -keystore gradlestu.keystore
输入密钥库口令:
再次输入新口令:
它们不匹配。请重试
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
  [Unknown]:  wzy
您的组织单位名称是什么?
  [Unknown]:  wzy
您的组织名称是什么?
  [Unknown]:  wzy
您所在的城市或区域名称是什么?
  [Unknown]:  Beijing
您所在的省/市/自治区名称是什么?
  [Unknown]:  Beijing
该单位的双字母国家/地区代码是什么?
  [Unknown]:  86
CN=wzy, OU=wzy, O=wzy, L=Beijing, ST=Beijing, C=86是否正确?
  [否]:  y

输入 <gradlestu> 的密钥口令
        (如果和密钥库口令相同, 按回车):
再次输入新口令:

Warning:
JKS 密钥库使用专用格式。建议使用 "keytool -importkeystore -srckeystore gradlestu.keystore -destkeystore gradlestu.keystore -deststoretype pkcs12" 迁移到行业标准格式 PKCS12。

C:\Users\wzy\Desktop>keytool -importkeystore -srckeystore gradlestu.keystore -destkeystore gradlestu.keystore -deststoretype pkcs12
输入源密钥库口令:
已成功导入别名 gradlestu 的条目。
已完成导入命令: 1 个条目成功导入, 0 个条目失败或取消

Warning:
已将 "gradlestu.keystore" 迁移到 Non JKS/JCEKS。将 JKS 密钥库作为 "gradlestu.keystore.old" 进行了备份。

C:\Users\wzy\Desktop>

签名:使用 Android 的 apksigner.bat 命令对未签名的 APK 安装包进行签名,apksigner.bat 位于 Android SDK 的 build-tools 目录下。apksigner 命令就是 V2 版本的签名(API29 为 V3)。

$ apksigner sign --ks C:\Users\wzy\gradlestu.keystore --ks-key-alias gradlestu --out C:\Users\wzy\Desktop\app-red-free-release_sign.apk C:\wzhy\space_demos\GradleStu\app\build\outputs\apk\redFree\release\app-red-free-release-unsigned.apk

选项说明:

  • sign:指定使用apksigner命令执行签名
  • ks:指定数字证书的存储路径
  • ks-key-alias:指定数字证书的别名
  • out 文件路径:指定签名后的APK文件路径及文件名
  • 最后一个参数则代表未签名的APK文件

输入命令后回车输入数字证书的密码,如果签名成功,该命令不会有任何提示。
apksigner 还提供了 verif y子命令来验证签名是否有效。
在命令行窗口输入以下命令对APK安装包的签名状态执行检查:

$ apksigner verify -v C:\Users\wzy\Desktop\app-red-free-release_sign.apk 

利用 Android Studio 生成签名文件
点击工具栏 Build -> Generate signed Bundle or APK -> 选 apk 点击 Next > 点击 Create new key store -> 填入签名文件信息即可。
build
Generate signed Bundle or APK

Create new...

New Key Store

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值