Android Studio之配置编译
学习网址:
https://developer.android.com/studio/build
如下文字是经过学习官网知识点,结合自身的需求进行整理的文档。这里,如有疑问,强烈建议看官网文档、强烈建议看官网文档、强烈建议看官网文档。
提问:
1.怎么多渠道管理apk的发布
2.各种渠道的apk,相互之间源码和资源文件都有差异,但仍希望使用同一套代码进行管理。
例如:AndroidManifest.xml有差异、某一个功能有差异、可能apk包名、签名也有差异也有差异
重点记录:
Android应用模块的编译流程
![](https://img.haomeiwen.com/i14090831/36c40d3a61f2d24a.png)
Android 应用模块的默认项目结构
![](https://img.haomeiwen.com/i14090831/88b87ec7c0f4210c.png)
模块下面的build.gradle分析
问题一、因应用商城的不同,需要上传自定义的不同的apk版本:
android {
...
defaultConfig {...}
buildTypes {
debug{...}
release{...}
}
// Specifies one flavor dimension.
flavorDimensions "version"
productFlavors {
huawei {
// Assigns this product flavor to the "version" flavor dimension.
// This property is optional if you are using only one dimension.
dimension "version"
applicationIdSuffix ".huawei"
versionNameSuffix "-huawei"
}
oppo {
dimension "version"
applicationIdSuffix ".oppo"
versionNameSuffix "-oppo"
}
}
}
关键点:
1)flavorDimensions
2)productFlavors
因为每个商场的渠道不一样,导致可能需要更改不同的版本信息。此时,huawei渠道有两个版本:debug和
release,oppo也有两个版本debug和release。所以,这里的编译版本有[huawei, oppo]x[debug, release]
编译方式:
gradlew build //4个编译出来
gradlew assemblehuaweiDebug //只编译华为的Debug版本
gradlew assemblehuaweiRealse //只编译华为的Release版本
注:huawei可以换成oppo
问题二、同一个apk,但是因不同的机器,需要的api版本不一样:
android {
...
buildTypes {
debug {...}
release {...}
}
// Specifies the flavor dimensions you want to use. The order in which you
// list each dimension determines its priority, from highest to lowest,
// when Gradle merges variant sources and configurations. You must assign
// each product flavor you configure to one of the flavor dimensions.
flavorDimensions "api", "mode"
productFlavors {
huawei{
// Assigns this product flavor to the "mode" flavor dimension.
dimension "mode"
...
}
oppo{
dimension "mode"
...
}
// Configurations in the "api" product flavors override those in "mode"
// flavors and the defaultConfig block. Gradle determines the priority
// between flavor dimensions based on the order in which they appear next
// to the flavorDimensions property above--the first dimension has a higher
// priority than the second, and so on.
minApi24 {
dimension "api"
minSdkVersion 24
// To ensure the target device receives the version of the app with
// the highest compatible API level, assign version codes in increasing
// value with API level. To learn more about assigning version codes to
// support app updates and uploading to Google Play, read Multiple APK Support
versionCode 30000 + android.defaultConfig.versionCode
versionNameSuffix "-minApi24"
...
}
minApi23 {
dimension "api"
minSdkVersion 23
versionCode 20000 + android.defaultConfig.versionCode
versionNameSuffix "-minApi23"
...
}
minApi21 {
dimension "api"
minSdkVersion 21
versionCode 10000 + android.defaultConfig.versionCode
versionNameSuffix "-minApi21"
...
}
}
}
...
关键点:
1)flavorDimensions "api", "mode"有两个值。谁在前面,谁的优先级高。也就是不能modeapi
2)productFlavors 下的版本级别,跟dimension关联,如果都是api,说明,这两个是同一个级别
也就是说,huawei和oppo都是mode,是一个级别;而minApi21、minApi23、minApi24是同一个级别。
这里编译的版本组合有:
这里的编译版本有[minApi21, minApi23, minApi24]x[huawei, oppo]x[debug, release],即12种
编译方式:
gradlew build //编译全部
gradlew assembleminApi21 //编译出来的版本[minApi21]x[huawei, oppo]x[debug, release],4种
gradlew assembleminApi21huawei //编译[minApi21]x[huawei]x[debug, release],2种
问题三、问题一的进一步展开,不同渠道的apk中的AndroidManifest.xml、java文件、资源文件都有点区别,应该怎么处理?
![](https://img.haomeiwen.com/i14090831/75d35abb422e729b.png)
只要huawei和oppo目录的名称跟productFlavors保持一致即可,android studio编译的是会自动编译此目录下的相关文件。如果不按照这种方式处理,就需要使用闭包:sourceSets。我们Android studio默认使用main/src的源码集合。这里,我们通过sourceSets自然也可以更改,例如:
android {
...
sourceSets {
// Encapsulates configurations for the main source set.
main {
// Changes the directory for Java sources. The default directory is
// 'src/main/java'.
java.srcDirs = ['other/java']
// If you list multiple directories, Gradle uses all of them to collect
// sources. Because Gradle gives these directories equal priority, if
// you define the same resource in more than one directory, you get an
// error when merging resources. The default directory is 'src/main/res'.
res.srcDirs = ['other/res1', 'other/res2']
// Note: You should avoid specifying a directory which is a parent to one
// or more other directories you specify. For example, avoid the following:
// res.srcDirs = ['other/res1', 'other/res1/layouts', 'other/res1/strings']
// You should specify either only the root 'other/res1' directory, or only the
// nested 'other/res1/layouts' and 'other/res1/strings' directories.
// For each source set, you can specify only one Android manifest.
// By default, Android Studio creates a manifest for your main source
// set in the src/main/ directory.
manifest.srcFile 'other/AndroidManifest.xml'
...
}
}
}
规则
1、资源文件的覆盖,图片、音频、 XML 类型的 Drawable 等资源文件,将会进行文件级的覆盖。
2、资源文件的合并,字符串、颜色值、整型等资源以及 AndroidManifest.xml ,将会进行元素级的覆盖(不同版本只要写与主版本不同的元素即可)。
3、代码资源的准备,代码文件不会覆盖或合并,同一个类文件, 在不同目录(buildTypes 、 productFlavors 、 main)中只能存在一次,否则会有类重复的错误。
特别说明AndroidManifest.xml
合并原理:
![](https://img.haomeiwen.com/i14090831/030850d36bd969dc.png)
合并算法
![](https://img.haomeiwen.com/i14090831/3311c24e605656c7.png)
关键的操作可以参考官网说明:
https://developer.android.com/studio/build/manifest-merge
问题四、build.gradle怎么与应用代码共享自定义字段和资源值
android {
...
buildTypes {
release {
// These values are defined only for the release build, which
// is typically used for full builds and continuous builds.
buildConfigField("String", "BUILD_TIME", "\"${minutesSinceEpoch}\"")
resValue("string", "build_time", "${minutesSinceEpoch}")
...
}
debug {
// Use static values for incremental builds to ensure that
// resource files and BuildConfig aren't rebuilt with each run.
// If they were dynamic, they would prevent certain benefits of
// Instant Run as well as Gradle UP-TO-DATE checks.
buildConfigField("String", "BUILD_TIME", "\"0\"")
resValue("string", "build_time", "0")
}
}
}
...
在构建时,Gradle 将生成 BuildConfig 类,以便您的应用代码可以检查与当前构建有关的信息。
我们还可以使用 buildConfigField() 方法从 Gradle 构建配置文件将自定义字段添加到 BuildConfig 类,
并在应用的运行时代码中访问这些值。同样,我们也可以使用 resValue() 添加应用资源值。
重点说明,我们gradle自动创建的BuildConfig类,可以让我们很方便用debug属性判断是否开启Log。因为
BuildConfig.DEBUG在Debug版本为true,在Release版本为false。例如:
Log.i(TAG, BuildConfig.BUILD_TIME);
Log.i(TAG, getString(R.string.build_time));
问题五、build.gradle怎么让AndroidManifest.xml和应用代码共享属性?
android {
// For settings specific to a product flavor, configure these properties
// for each flavor in the productFlavors block.
defaultConfig {
// Creates a property for the FileProvider authority.
def filesAuthorityValue = applicationId + ".files"
// Creates a placeholder property to use in the manifest.
manifestPlaceholders =
[filesAuthority: filesAuthorityValue]
// Adds a new field for the authority to the BuildConfig class.
buildConfigField("String",
"FILES_AUTHORITY",
"\"${filesAuthorityValue}\"")
}
...
}
...
关键点:buildConfigField、manifestPlaceholders 配合使用
AndroidManifest.xml如下:
<manifest>
...
<application>
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${filesAuthority}"
android:exported="false"
android:grantUriPermissions="true">
...
</provider>
</application>
</manifest>
代码如下:
...
Uri contentUri = FileProvider.getUriForFile(getContext(),
BuildConfig.FILES_AUTHORITY,
myFile);
问题六、不同的渠道的签名不一样,怎么此需求?
android {
defaultConfig {
······
}
signingConfigs {
huawei_sign {
storeFile file("../key/xxx.keystore")
storePassword "xxxxxx"
keyAlias "xxx"
keyPassword "xxxxxx"
}
oppo_sign {
storeFile file("../key/xxx.keystore")
storePassword "xxxxxxx"
keyAlias "xxx"
keyPassword "xxxxxxx"
}
}
flavorDimensions "default"
productFlavors {
huawei {
···
signingConfig signingConfigs.huawei_sign
}
oppo {
···
signingConfig = signingConfigs.oppo_sign
}
}
buildTypes {
release {
···
signingConfig null
}
debug {
···
signingConfig null
}
}
}
关联点三处:
1)productFlavors 把各自signingConfig值定义了
2)buildTypes把signingConfig置为null
3)signingConfigs进行统一申明
常用命令
gradle命令一般是./gradlew +参数, gradlew 代表gradle wrapper,意思是gradle的一层包装,大家可以理解为在这个项目本地就封装了gradle,即gradle wrapper, 在gradle/wrapper/gralde-wrapper.properties 文件中声明了它指向的目录和版本。只要下载成功即可用grdlew wrapper的命令代替全局的gradle命令。
- ./gradlew -v 版本号
- ./gradlew clean 清除app目录下的build文件夹
- ./gradlew build 检查依赖并编译打包
这里注意的是 ./gradlew build 命令把debug、release环境的包都打出来,如果正式发布只需要打Release的包,该怎么办呢,下面介绍一个很有用的命令 assemble, 如:
- ./gradlew assembleDebug 编译并打Debug包
- ./gradlew assembleRelease 编译并打Release的包
除此之外,assemble还可以和productFlavors结合使用:
- ./gradlew installReleaseRelease模式打包并安装
- ./gradlew uninstallRelease 卸载Release模式包
Android Studio其实用的就是gradle打包,所以,可以直接使用gradle指令进行打包,这样可以更加快捷。
参考学习
https://blog.csdn.net/u014314614/article/details/83868648
https://www.jianshu.com/p/d485db2970f9
https://developer.android.com/studio/build
https://blog.csdn.net/growing_tree/article/details/74938536
https://blog.csdn.net/m0_37168878/article/details/81530499
https://blog.csdn.net/s13383754499/article/details/80312514