现在讲讲Gradle打包apk的事情
配置资源文件
在做马甲包的时候,一般都是每个apk有不同的icon、不同的名字及界面上显示的文字也不同。往往这样子就需要有额外的资源文件。
- 可以在src下建立新的目录来存放对应的资源文件,例如:
命名与渠道名相同, src下,与 main 同级。shenzhen 中 res 下的文件目录和 main/src/res相同。 - 可以在main下面建立个文件夹,比如华为和小米两个渠道,这里建立两个文件夹。
另外还需要再gradle中配置:
//以下代码放在android{}内
//配置资源文件路径,可动态指定不同版本资源文件
sourceSets {
main {
manifest.srcFile 'src/main/AndroidManifest.xml'
java.srcDirs = ['src/main/java']
resources.srcDirs = ['src/main/resources']
aidl.srcDirs = ['src/main/aidl']
renderscript.srcDirs = ['src/maom']
res.srcDirs = ['src/main/res']
assets.srcDirs = ['src/main/assets']
jniLibs.srcDir 'src/main/jniLibs'
}
//用各自对应的资源文件路径
xiaomi.res.srcDirs = ['src/main/res-xiaomi']
huawei.res.srcDirs = ['src/main/res-huawei']
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
//渠道Flavors,配置不同风格的app
productFlavors {
xiaomi{}
huawei{}
}
配置签名文件
对于签名文件的配置,可以写在local.properties
文件中,之后在 local.properties
下添加密钥信息,然后在 build.gradle 中读取使用.
/**local.properties*/
keystroe_storePassword=****
keystroe_storeFile=/Users/zhengxiaobo/Desktop/work/worksoure/key/balance6game
keystroe_keyAlias=balance
keystroe_keyPassword=****
/** build.gradle */
Properties properties = new Properties()
properties.load(project.rootProject.file('local.properties').newDataInputStream())
//sign key
signingConfigs{
release{
storeFile file(properties.getProperty("keystroe_storeFile"))
storePassword properties.getProperty("keystroe_storePassword")
keyAlias properties.getProperty("keystroe_keyAlias")
keyPassword properties.getProperty("keystroe_keyPassword")
}
}
配置AndroidManifest文件
由于不同的app使用的友盟统计也不同,这里需要设置占位符在gradle中进行动态的替换
<application>
<!-- 友盟统计 appkey-->
<meta-data
android:name="UMENG_APP_KEY"
android:value="${UMENG_APP_KEY_VALUE}"/>
<!-- 友盟统计 渠道-->
<meta-data
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL_VALUE}"/>
</application>
多渠道打包,配置applicationId
多渠道打包的关键之处在于,定义不同的product flavor, 并把AndroiManifest中的channel渠道编号替换为对应的flavor标识:
android{
productFlavors {
//开发环境
// demo {
// applicationId "com.balance6game.housingfund.test"
// manifestPlaceholders = [APP_NAME: "@string/gjj_app_name_debug"]
// buildConfigField "boolean", "APP_DEBUG", "true"
//
// }
// //测试环境
// dev {
// applicationId "com.balance6game.housingfund.dev"
// manifestPlaceholders = [APP_NAME: "@string/gjj_app_name_dev"]
// buildConfigField "boolean", "APP_DEBUG", "true"
// }
// //生产环境
// full {
// manifestPlaceholders = [APP_NAME: "@string/gjj_app_name"]
// buildConfigField "boolean", "APP_DEBUG", "false"
// }
shenzhen{
applicationId "com.gjj51.housingfund.shenzhen"
versionCode 13
versionName "2.3.0.0628"
manifestPlaceholders = [GJJ_APP_NAMETAG_VALUE: "gjjshenzhen", GJJ_SUBAPP_NAME_VALUE: "",UMENG_APPKEY_VALUE:"",UMENG_MESSAGE_SECRET_VALUE:"",UMENG_CHANNEL_VALUE:"baidu"]
//配置reslease的签名
signingConfig signingConfigs.release
}
}
}
自定义Build Type
一般情况下,gradle都会默认自带debug、release两个build type。现在要增加一种状态,但还是要保留原来的两个状态。其中在开发中还要针对开发服,测试服和正式服做区分,gradle针对不同build type做了很好的处理。只要替换API_HOST
,就可以得到我们想要的结果了。也可以配置不同的参数得到不同的包名和applicationId.
//开发环境
def API_KAIFA_HOST = "\"https://kaifa.jianbing.com\""
//测试环境
def API_TEST_HOST = "\"https://test.jianbing.com\""
//正式环境
def API_RELEASE_HOST = "\"https://b.jianbing.com\""
buildTypes {
//开发
demo {
//混淆处理
minifyEnabled false
//移除无用的resource文件
shrinkResources false
//Zipalign优化
zipAlignEnabled false
manifestPlaceholders = [APP_NAME:"@string/gjj_app_name_debug"]
applicationIdSuffix ".dev"
buildConfigField "String", "API_HOST", "${API_KAIFA_HOST}"
buildConfigField "boolean", "APP_DEBUG", "true"
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
//测试
debug {
minifyEnabled false
shrinkResources false
zipAlignEnabled false
manifestPlaceholders = [APP_NAME:"@string/gjj_app_name_dev"]
applicationIdSuffix ".test"
buildConfigField "String", "API_HOST", "${API_TEST_HOST}"
buildConfigField "boolean", "APP_DEBUG", "true"
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
//正式
release {
//混淆处理
minifyEnabled true
shrinkResources true
zipAlignEnabled true
manifestPlaceholders = [APP_NAME:"@string/gjj_app_name"]
buildConfigField "String", "API_HOST", "${API_RELEASE_HOST}"
buildConfigField "boolean", "APP_DEBUG", "false"
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
多Module下的全局配置
随着产品渠道的铺开,往往一套代码需要支持多个产品形态,这就需要抽象出主要代码到一个Library,然后基于Library扩展几个App Module。
就可以在project根目录下的build.gradle定义ext全局变量,之后就可以在子module下进行引用。
//root的build.gradle
ext {
compileSdkVersion = 27
buildToolsVersion = "27.0.3"
applicationId = "com.balance6game.***"
minSdkVersion = 14
targetSdkVersion = 23
versionCode = 125
versionName = "7.3.0.0702"
supportVersion = '27.1.1'
}
//子module的build.gradle
//基本配置
def cfg = rootProject.ext
android {
compileSdkVersion cfg.compileSdkVersion
buildToolsVersion cfg.buildToolsVersion
defaultConfig {
applicationId cfg.applicationId
minSdkVersion cfg.minSdkVersion
targetSdkVersion cfg.targetSdkVersion
multiDexEnabled true
versionCode cfg.versionCode
versionName cfg.versionName
......
}
}
dependencies {
implementation "com.android.support:design:${cfg.supportVersion}"
implementation "com.android.support:recyclerview-v7:${cfg.supportVersion}"
......
}
自定义导出的APK名称
在打包的时候往往有特定的包的命名,如果打出来再手动修改就很麻烦了,这个时候就需要自定义导出的APK名称了。
//给apk添加对应的版本号:区分不同目录
applicationVariants.all { variant ->
variant.outputs.all { output ->
// if(!variant.buildType.isDebuggable()){
// def outputFile = output.outputFile
// //def fileName = "gjj-${variant.productFlavors[0].name}-V${defaultConfig.versionName}-${variant.buildType.name}.apk".toLowerCase()
// //output.outputFile = new File(outputFile.parent + "/${variant.buildType.name}", fileName)
// //要被替换的源字符串
// def sourceFile = "-${variant.flavorName}-${variant.buildType.name}"
// //替换的字符串
// def replaceFile = "gjj_V${variant.versionName}_${variant.flavorName}_${variant.buildType.name}"
// outputFileName = output.outputFile.name.replace(sourceFile, replaceFile);
//
// }
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
def fileName = "gjj-${variant.productFlavors[0].name}-V${defaultConfig.versionName}-${variant.buildType.name}.apk".toLowerCase()
outputFileName = fileName
}
}
}
现在就可以到相对应的目录下面找你想要的包了。
Gradle命令打包
//根据不同命令 打区分不同通道的 dev full包
Gradle assembledebug
Gradle assemblerelease
Gradle assembledemo
Gradle assembleone
Gradle assembletwo
Gradle assemblethree