一.Gradle多渠道打包使用多个.gradle文件
1.简介
上述章节讲述了,多渠道打包时,配置不同包的不同配置。但这些不同的配置都是在APP的Gradle文件中声明的,如果渠道多了,然后不同的配置也多了。那么APP的Gradle文件代码就会特别多,也会显得特别乱。我们可以分开不同的文件,根据不同的渠道来加载不同文件夹中的属性。
2.文件截图
blue.properties文件
#blue包
#Url配置
HOST_URL=https://aaa.bbb.ccc.blue:1234
#PROVIDER配置
PROVIDER=com.wjn.okhttpmvpdemo.blue
#MAPKEY
KEY_MAP=sdfasfds2345dfafFDg_Blue
red.properties文件
#red包
#Url配置
HOST_URL=https://aaa.bbb.ccc.red:4321
#PROVIDER配置
PROVIDER=com.wjn.okhttpmvpdemo.red
#MAPKEY
KEY_MAP=sdfasfds2345dfafFDg_Red
3.代码
APP的Gradle文件
apply plugin: 'com.android.application'
/** ext闭包 在本Gradle中配置 versionCode&versionName 本Gradle的defaultConfig{}包使用 */
ext {
versionInt = 2
versionString = "2.0.0"
releaseTime = releaseTime()
}
android {
compileSdkVersion 28
/** defaultConfig闭包 默认配置 */
defaultConfig {
applicationId "com.wjn.okhttpmvpdemo"
minSdkVersion 19
targetSdkVersion 27
versionCode versionInt
versionName versionString
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
/** signingConfigs闭包 项目签名配置 */
signingConfigs {
release {
storeFile file('C:\\Users\\wujianning\\AndroidStudioProjects\\demo\\OKHttpMVPDemo\\test.jks')
storePassword '123456'
keyAlias 'key0'
keyPassword '123456'
v1SigningEnabled true
v2SigningEnabled true
}
debug {
storeFile file('C:\\Users\\wujianning\\AndroidStudioProjects\\demo\\OKHttpMVPDemo\\test.jks')
storePassword '123456'
keyAlias 'key0'
keyPassword '123456'
v1SigningEnabled true
v2SigningEnabled true
}
}
/** buildTypes闭包 项目打包配置 比如是否混淆 是否压缩 是否支持调式等等 这里为了区分下面多渠道打包Debug包和Release包 在versionName后添加了不同的后缀*/
buildTypes {
release {
minifyEnabled false
debuggable false
multiDexEnabled false
}
debug {
minifyEnabled false
debuggable true
multiDexEnabled false
buildConfigField "String", "MAPID", "\"" + rootProject.ext.android.mapId + "\""
}
}
/** productFlavors闭包 多渠道打包 flavorDimensions属性确定维度 分支&免费付费 */
flavorDimensions "branch", "free_pay"
productFlavors {
red {
dimension "branch"
signingConfig signingConfigs.release
//加载不同的Gradle文件 这里加载red.properties文件
Properties branch_config = loadConfigGradle("red")
buildConfigField("String", "HOST_URL", "\"${branch_config['HOST_URL']}\"")
getManifestPlaceholders().put("PROVIDER", "${branch_config['PROVIDER']}")
getManifestPlaceholders().put("KEY_MAP", "${branch_config['KEY_MAP']}")
}
blue {
dimension "branch"
signingConfig signingConfigs.debug
//加载不同的Gradle文件 这里加载red.properties文件
Properties branch_config = loadConfigGradle("blue")
buildConfigField("String", "HOST_URL", "\"${branch_config['HOST_URL']}\"")
getManifestPlaceholders().put("PROVIDER", "${branch_config['PROVIDER']}")
getManifestPlaceholders().put("KEY_MAP", "${branch_config['KEY_MAP']}")
}
free {
dimension "free_pay"
buildConfigField "boolean", "IS_FREE", "true"
}
pay {
dimension "free_pay"
buildConfigField "boolean", "IS_FREE", "false"
}
}
/** variantFilter闭包 过滤变体 可以设置忽略那个包 比如这里过滤掉了不在列表中的包*/
variantFilter { variant ->
def needed = variant.name in [
'redFreeRelease',
'redFreeDebug',
'redPayRelease',
'redPayDebug',
'blueFreeRelease',
'blueFreeDebug',
'bluePayRelease',
'bluePayDebug',
]
setIgnore(!needed)
}
/** compileOptions闭包 配置项目使用JDK1.8 */
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
/** applicationVariants闭包 配置项目打包包名 */
android.applicationVariants.all {
variant ->
variant.outputs.all { output ->
//获取分支 red&blue
def appBranch = variant.productFlavors[0].name
//获取免费付费 free&pay
def free_pay = variant.productFlavors[1].name
//默认的包名
def result = "OkHttp_" + versionString
//操作包名 blue的包 拼后面的字符串 red的包使用默认的字符串不需要拼后面的字符串
if (appBranch == "blue") {
result = result + "_" + free_pay.toUpperCase() + "_" + releaseTime() + ".apk"
} else {
result = result + ".apk"
}
//更新打出的包的名称
outputFileName = result
//更新VersionName
output.setVersionNameOverride(result)
}
}
/** sourceSets闭包 配置项目文件 */
sourceSets {
/** 默认 配置项目文件 */
main {
jniLibs.srcDirs = ['libs']
assets.srcDirs = ['src/main/assets']
}
/** blue包 配置项目文件 */
blue {
assets.srcDirs = ['../protectFileConfig/assets/blue']
}
/** red包 配置项目文件 */
red {
assets.srcDirs = ['../protectFileConfig/assets/red']
}
}
}
static def releaseTime() {
return new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+8"))
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:support-v4:27.1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'io.reactivex:rxjava:1.3.2'
implementation 'io.reactivex:rxandroid:1.2.1'
implementation 'com.squareup.okhttp3:okhttp:3.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.6.0'
implementation 'com.readystatesoftware.systembartint:systembartint:1.0.3'
implementation 'com.squareup.retrofit2:retrofit:2.7.0'
implementation 'com.github.bumptech.glide:glide:4.4.0'
}
/** loadConfigGradle方法 用来加载不同的gradle文件 */
def loadConfigGradle(name) {
Properties props = new Properties()
FileInputStream fis = new FileInputStream(file("../protectFileConfig/gradle/" + name + ".properties"))
BufferedReader bf = new BufferedReader(new InputStreamReader(fis, "UTF-8"))
props.load(bf)
return props
}
清单文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wjn.okhttpmvpdemo">
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!-- provider的authorities属性 使用PROVIDER占位符 -->
<provider
android:name=".MyContentProvider"
android:authorities="${PROVIDER}.provider"
android:enabled="true"
android:exported="false">
</provider>
<activity android:name=".view.impl.activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- meta-data的value值 使用KEY_MAP占位符 -->
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="${KEY_MAP}"/>
</application>
</manifest>
Java代码
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String HOST_URL = BuildConfig.HOST_URL;
Log.d("MainActivity", "HOST_URL----:" + HOST_URL);
}
}
4.验证
打两个包验证 OkHttp_2.0.0_FREE_20170428.apk和OkHttp_2.0.0.apk。截图
OkHttp_2.0.0_FREE_20170428.apk包
清单文件
<provider
android:name="com.wjn.okhttpmvpdemo.MyContentProvider"
android:enabled="true"
android:exported="false"
android:authorities="com.wjn.okhttpmvpdemo.blue.provider" />
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="sdfasfds2345dfafFDg_Blue" />
日志
D/MainActivity: HOST_URL----:https://aaa.bbb.ccc.blue:1234
OkHttp_2.0.0.apk包
清单文件
<provider
android:name="com.wjn.okhttpmvpdemo.MyContentProvider"
android:enabled="true"
android:exported="false"
android:authorities="com.wjn.okhttpmvpdemo.red.provider" />
<meta-data
android:name="com.google.android.maps.v2.API_KEY"
android:value="sdfasfds2345dfafFDg_Red" />
日志
D/MainActivity: HOST_URL----:https://aaa.bbb.ccc.red:4321
5.注意
上述在多渠道时,在两个渠道都加载了不同的properties文件,如果有多个渠道需要在每一个渠道写一份代码,而每一份的代码仅仅是加载的properties名字不一样。我们可以有更简洁的写法。
/** productFlavors闭包 多渠道打包 简洁写法 */
productFlavors.all { flavor ->
def name = flavor.name//name可能的值:red blue free pay 所以要过滤一下
if (name == "red" || name == "blue") {
//加载不同的Gradle文件 加载name.properties文件
Properties branch_config = loadConfigGradle(name)
buildConfigField("String", "HOST_URL", "\"${branch_config['HOST_URL']}\"")
getManifestPlaceholders().put("PROVIDER", "${branch_config['PROVIDER']}")
getManifestPlaceholders().put("KEY_MAP", "${branch_config['KEY_MAP']}")
}
}