概述
Android 有不同的应用市场,也就是不同的渠道,需要为每个应用市场打一个安装包,但主要的代码是一样的,可能部分资源不一样,部分代码不一样,如果每个渠道都需要修改,然后打包,非常耗时。所以 AS 是提供了多渠道打包的。
可能遇到的需求
- 不同渠道
applicationId
不一样; - 不同渠道配置参数不一样;
- 不同渠道签名文件不一样;
- 不同渠道资源文件不一样;
- 不同渠道部分代码不一样;
- 不同渠道依赖不一样;
这里会先说一下初级版配置,再说升级版配置—— Grovvy
进行自动化构建。
初级版多渠道配置
productFlavors
:不同产品口味,就是AS自带的不同渠道打包关键字。可以进行多渠道配置,有两种方式。
1、在 app 模块下的 build.gradle
配置
// 读取不同的签名文件
def getSignProperties(filename){
File signConfigFile = file("${rootProject.rootDir}/app/keystore/${filename}.properties")
Properties signProperties = new Properties()
signProperties.load(new FileInputStream(signConfigFile))
return signProperties
}
android {
compileSdk 32
defaultConfig {
applicationId "com.XXX"
minSdk 21
targetSdk 32
versionCode 5
versionName "3.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
// 不同渠道的签名
signingConfigs {
release {
def signProperties = getSignProperties('signing')
storeFile file(signProperties['KEYSTORE_FILE'])
storePassword signProperties['KEY_PASSWORD']
keyAlias signProperties['KEY_ALIAS']
keyPassword signProperties['KEY_PASSWORD']
}
//不同的渠道,定义不同的签名文件
huawei {
def signProperties = getSignProperties('signing-huawei')
storeFile file(signProperties['KEYSTORE_FILE'])
storePassword signProperties['KEY_PASSWORD']
keyAlias signProperties['KEY_ALIAS']
keyPassword signProperties['KEY_PASSWORD']
}
xiaomi {
def signProperties = getSignProperties('signing-xiaomi')
storeFile file(signProperties['KEYSTORE_FILE'])
storePassword signProperties['KEY_PASSWORD']
keyAlias signProperties['KEY_ALIAS']
keyPassword signProperties['KEY_PASSWORD']
}
}
// 配置不同渠道参数
productFlavors{
huawei{
applicationId ="com.xxx"
//渠道参数
buildConfigField "String", "token", ""XXXX""
// manifest 读取的参数,在 manifest 里如何使用,见后文
manifestPlaceholders=[
"app_name":"CCCCC"
]
}
// 其他渠道类似
}
// 配置打包签名
buildTypes {
debug {
minifyEnabled false
debuggable true
shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
signingConfig signingConfigs.release
}
release {
minifyEnabled true
debuggable false
shrinkResources false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),
'proguard-rules.pro'
//signingConfig signingConfigs.release
productFlavors.xiaoxing236.signingConfig signingConfigs.huawei
productFlavors.xiaoxing238.signingConfig signingConfigs.xiaomi
}
}
// 指定打包输出的路径
applicationVariants.all { variant ->
// 打包完成后输出路径
def name = variant.flavorName +
"_" + variant.buildType.name +
"_" + variant.versionName +
"_" + new Date().format('yyyyMMddhhmm') + ".apk"
//相对路径app/build/outputs/apk/huawei/release/
def path = "../../../../../apk/" //相当于路径 app/apk/
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk') && outputFile.name.contains('release')) {
//指定路径输出
output.outputFileName = new File(path, name)
}
}
}
//不同渠道不同资源文件
// sourceSets{ } 源文件目录设置
sourceSets {
// 公共代码及资源
main {
jniLibs.srcDirs = ['libs']
}
// 不同资源
huawei.res.srcDirs 'src/huawei/res'
xiaomi.res.srcDirs 'src/xiaomi/res'
// 其他渠道类似,以下不再重复
//不同代码
huawei.java.srcDirs 'src/huawei/java'
xiaomi.java.srcDirs 'src/xiaomi/java'
// 不同渠道 manifest 文件
huawei.manifest.srcFile 'src/huawei/AndroidManifest.xml'
xiaomi.manifest.srcFile 'src/xiaomi/AndroidManifest.xml'
}
}
// 不同渠道的依赖
dependencies {
// 公共的依赖
implementation 'ccccc'
// 不同渠道依赖
xiaomiApi('xxxxxxx')
huaweiImplementation('xxxxxxxx')
}
不同渠道配置的参数需要在 manifest 里使用
<application
android:name="${applicationId}.GlobalApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="${app_name}"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true">
</application>
在代码里使用 buildconfig 参数
private final String TOKEN = BuildConfig.token;
2、可以把以上不同渠道的配置单独放在一个 flavor.gradle
文件里,该文件与 setting.gradle
目录同级。 然后在 app 模块的 build.gradle
引用 flavor.gradle
文件即可。
apply from: ("${rootProject.rootDir}/flavor.gradle")
升级版渠道配置
按照以上配置方式,每增加一个渠道,就得每个渠道重新写一遍 huawei.manifest.srcFile
等这种操作,会让 build.gradle
显得非常臃肿。可以通过固定规则,写脚本解决以上问题。
1、在项目中创建出打包脚本文件夹 buildSrc,在此文件夹下创建 src/resource/**META-INF/gradle-plugins
路径及文件夹名固定。**
2、定义自动构建插件路径,在 src/resource/**META-INF/gradle-plugins
路径下创建一个 xxx.properties 文件,文件内定义构建脚本路径。**
// 路径是写脚本的文件路径
implementation-class=com.xxx.plugin.PackagePlugin
3、在 build.gradle 里引入相关仓库
//依赖 groovy 插件,这个是 Gradle 内置的插件
plugins {
`kotlin-dsl`
`java-gradle-plugin`
groovy
}
val androidGradlePlugin = "com.android.tools.build:gradle:4.2.2"
val kotlin_version = "1.6.10"
//引入相关的仓库
dependencies {
// 导入androidGradlePlugin,这样buildSrc可以使用gradle相关api
implementation(androidGradlePlugin)
// Depend on the kotlin plugin, since we want to access it in our plugin
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}")
// Depend on the default Gradle API since we want to build a custom plugin
implementation(gradleApi())
implementation(localGroovy())
}
4、在主模块(app)模块的 build.gradle
中引入插件。
// plugin 的名字是第 2 步创建 properties 的名字
apply plugin: 'PackPlugin'
5、在 PackagePlugin
中开始编写自动构建脚本
编写脚本用的是 groovy 语法,可以参考这篇文章:Gradle插件从入门到进阶
class PackagePlugin : Plugin<Project> {
// plugin 必须实现的方法
override fun apply(target: Project) {
// 获取 android extension
var appExtension = target.extensions.getByName("android") as AppExtension
// 多渠道构建
appExtension.productFlavors {
var channelList = getChannelList()
channelList.forEach { channelModel ->
register(channelModel.channelName) {
// 每个渠道的需要配置的参数,可以根据自己的规则订
applicationId = channelModel.packageName
versionCode = channelModel.versionCode
versionName = "${channelModel.versionCode}.0"
// manifest 需要配置的参数
manifestPlaceholders["ads_id"] = channelModel.adsId
manifestPlaceholders["app_name"] = channelModel.appName
// 代码里需要使用的不同渠道配置参数
buildConfigField("String", "XXX", ""${channelModel.定义的属性名}"")
buildConfigField("String", "XXX", ""${channelModel.定义的属性名}"")
}
}
}
// 签名文件
appExtension.signingConfigs {
var channelList = getChannelList()
channelList.forEach { channelModel ->
var channelName = channelModel.channelName
register(channelName) {
// 可以单独处理不一样的包
storeFile(getKeyStoreFile(channelName, target))
storePassword(channelName)
keyAlias(channelName)
keyPassword(channelName)
}
}
}
// 不同渠道配置不同的签名文件,签名文件的名字、别名、密码可以自行定义
appExtension.signingConfigs.forEach { signingConfig ->
println("PackagePlugin signing:${signingConfig.keyAlias.toString()}")
appExtension.productFlavors.getByName(signingConfig.keyAlias.toString()).signingConfig =
signingConfig
}
// 不同渠道的不同代码、资源、和 manifest
appExtension.sourceSets {
var channelList = getChannelList()
channelList.forEach { channelModel ->
var channelName = channelModel.channelName
getByName(channelName) {
res.srcDirs("src/${channelName}/res")
java.srcDirs("src/${channelName}/java")
manifest.srcFile("src/${channelName}/AndroidManifest.xml")
}
}
}
}
}
最后
以上就是跳跃飞机为你收集整理的Android Studio多渠道打包及自动化构建的全部内容,希望文章能够帮你解决Android Studio多渠道打包及自动化构建所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复