寫這篇文章主要是因為,公司的項目對打包有多重需求,有哪些需求呢?
1.多渠道,這是最基本的;
2.分為3個版本(內地版,海外版,精簡版),每個版本包名不同(這就意味著第三方sdk的各種key都不一樣),且logo,部分圖標也不一樣;
3.開發(fā)版本的區(qū)別,分為debug版,pre預覽版,release正式版;
4.開發(fā)版本的區(qū)別要通過app名稱直接體現(xiàn)在桌面上,即apk安裝后,app名稱直接是XXdebug版,XXrelease版本
現(xiàn)在我們就分別來實現(xiàn)以上的需求
一.多渠道打包
gradle的productFlavors用來配置渠道,這里主要介紹一下友盟的多渠道打包配置
- 在AndroidManifest.xml中做如下配置
<meta-data
android:name="UMENG_CHANNEL"
android:value="${UMENG_CHANNEL_VALUE}" />
${...}這個占位符很重要,下面我們動態(tài)配置一些屬性的時候都會用到這個占位符
- 在項目app這個module下的gradle中配置渠道,注意這個productFlavors是配置在android下的
//配置多渠道
flavorDimensions "default"
productFlavors {
wandoujia {dimension "default"}
_360 {dimension "default"}
baidu {dimension "default"}
xiaomi {dimension "default"}
tencent {dimension "default"}
taobao {dimension "default"}
}
productFlavors.all { flavor ->
flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]
}
-
如上配置后,在AndroidStudio的Build->Select Build Variants ,可以看到每個渠道都有debug和release兩個版本
- 4 多版本apk安裝在同一手機上,也就是打多版本
這是看到了這位大神的文章,覺得講的比我寫的更詳細,下面部分就直接使用大神文章,謝謝作者
這種情況只需要我們提供不同包名的apk即可完成。因為只要應用包名不一樣即使簽名信息一樣還是可以同時安裝在同一臺手機上的,因此我們應該在打包成apk時修改應用的包名就可以達到目的啦碉怔。接下來我們進入實際操作過程徐勃。這里我們先介紹一個知識點,請直接看下圖:
當然從截圖也可以看出礼患,配置多apk打包和上一篇文章配置多渠道打包是一樣的,都是在productFlavors中配置的是钥。如上圖,我們在productFlavors中配置了兩種flavor的apk信息一種是Beta版缅叠,一種是Releases版悄泥,同時每個flavor中我們都重新配置applicationId這個屬性,通過這個屬性我們就可以使打包出來的apk包名產生對應的變化啦肤粱。至于為什么重新配置了applicationId就行呢弹囚,原因圖已經說明啦,就是因為defaultConfig是Beta版和Releases版flavor的基礎配置领曼,只要我們重寫了applicationId這個屬性就會覆蓋defaultConfig中相對應屬性的信息鸥鹉,從而使打包出來的兩種apk的包名不一樣,達到在同一臺手機上安裝的目的庶骄。那么applicationId又是什么呢毁渗?看下圖(因此我們更改其實就是package屬性)
比如說不同版本要使用不同的icon,這時該如何做呢瓢姻?實際上還是在productFlavors的每個flavor中通過manifestPlaceholders屬性配置即可祝蝠,manifestPlaceholders是一個類似HashMap的容器,因此在manifestPlaceholders可以配置多個屬性幻碱,以便在AndroidManifest.xm中使用绎狭,比如我們需要為每種版本的apk替換特定的icon和appName這時我們可以這樣如下配置:
然后在AndroidManifest.xm中這樣使用即可:
defaultConfig {
applicationId "com.zejian.multi_versionapk"
minSdkVersion 10
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
signingConfig signingConfigs.debug4zj
minifyEnabled true
zipAlignEnabled true
}
}
//配置多版本的apk
productFlavors{
Beta{
applicationId "com.zejian.multi_versionapk.beta"
manifestPlaceholders = [app_name:"multi_versionapk.beta" ,icon: "@mipmap/ic_launcher_beta"]
//在java代碼中具體的使用方式為:context.getResources().getString(R.string.strKey);
resValue("string" , "strKey","beta版本")
}
Releases{
applicationId "com.zejian.multi_versionapk.release"
manifestPlaceholders = [app_name:"multi_versionapk.release",icon: "@mipmap/ic_launcher_releases"]
resValue("string" , "strKey","release版本")
}
}
}
同時,我們Generate signed APK就可以打出release和debug的每個版本和每個渠道的包
至此,我們就可以通過Build Variants來控制當前的運行環(huán)境,來決定當前的包是屬于哪個版本和哪個渠道
二. 多渠道包跟多版本包不同的內容,如何來區(qū)分,也就是文章開頭第二條中的icon,logo,包名等信息不同時候如何來區(qū)別對待,那就要用到manifestPlaceholders了,文章上面說過,我們使用${...}占位符能夠動態(tài)替換AndroidManitest里面的很多東西,如何操作請往下看
wandoujia {
dimension "default"
manifestPlaceholders = [
applicationId :"com.app.test",
app_name : "@string/AppName",
icon : "@string/ic_launcher",
app_key : "1234567",
umeng_channel: "豌豆莢"
]
}
wandoujia_oas {
dimension "default"
manifestPlaceholders = [
applicationId :"com.app.oas",
app_name : "@string/AppNameOas",
icon : "@string/ic_launcher",
app_key : "910JQKA",
umeng_channel: "豌豆莢海外版"
]
}
<application
android:allowBackup="false"
android:icon="${icon}"
android:label="${app_name}"
android:persistent="true"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:replace="android:allowBackup,android:label, android:icon, android:theme">
這樣第三方SDK的不同key都可以采用占位符來動態(tài)替換,就像上面,當我們打海外版包時,就會將app_key和logo替換成另一套
三. 針對debug版本和release版本一些控制,就要用到 buildConfigField 了,buildConfigField 能夠在debug和release中生成不同的BuildConfig,我們在開發(fā)中的是否需要打印日志的控制就可以使用它
buildTypes {
release {
minifyEnabled false
debuggable false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField("boolean","show_log","false")
}
//預覽版
pre {
minifyEnabled false
debuggable false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField("boolean","show_log","true")
}
debug {
minifyEnabled false
debuggable true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
buildConfigField("boolean","show_log","true")
}
}
配置之后我們得到的BuildConfig如下,在代碼中使用直接BuildConfig.xxx就可以
public final class BuildConfig {
public static final boolean DEBUG = false;
public static final String APPLICATION_ID = "kotlin.app.com.gradledemo";
public static final String BUILD_TYPE = "release";
public static final String FLAVOR = "baidu";
public static final int VERSION_CODE = 1;
public static final String VERSION_NAME = "1.0";
// Fields from build type: release
public static final boolean show_log = false;
}
除了日志開關,其他用的最多的地方還有url環(huán)境的切換,比如debug版本一般我們會用內網(wǎng)的url,那么release版本就需要用生產環(huán)境的url
四. 要實現(xiàn)開篇的不同版本的apk名稱不一樣,就需要用到resValue了,它能夠定義資源,并且可以在debug和release等不同版本中來分別定義,例如resValue "string" 就是字符串資源,可以用R.String 來引用對應的字符串資源
//在debug下設置如下
resValue "string","AppName","測試DEV"
resValue "string","AppNameOas","測試海外版DEV"
resValue "string","AppNameSimple","測試1精簡版DEV"
這時候一編譯,就會自動在R.String下生成AppName,AppNameOas,AppNameSimple三個字符串,通過R.String.xxx就可以引用到;
注意:需要將之前values下string下的appName刪除,否則會報資源重復異常
五. 全局配置文件
project的build.gradle中的ext可以為各位module進行全局配置參數(shù)褥傍,防止各個module之間的不統(tǒng)一儡嘶,不可控。而且當我們升級sdk恍风、build tool蹦狂、target sdk等,幾個module都要更改朋贬,非常的麻煩凯楔。
在項目根目錄建立gradleConfig,然后
ext {
//統(tǒng)一管理依賴版本
android = [
compileSdkVersion: 25,
buildToolsVersion: '25.0.2',
applicationId : "com.test.xxx",
minSdkVersion : 17,
targetSdkVersion : 24,
versionCode : 2
versionName : "0.1"
]
def dependVersion = [
support: "25.1.0"
]
dependencies = [
"appcompat-v7" : "com.android.support:appcompat-v7:${dependVersion.support}",
"cardview-v7" : "com.android.support:cardview-v7:${dependVersion.support}",
"recyclerview-v7": "com.android.support:recyclerview-v7:${dependVersion.support}",
"design" : "com.android.support:design:${dependVersion.support}",
"support-v4" : "com.android.support:support-v4:${dependVersion.support}"
]
}
然后在每個module中引用
android {
compileSdkVersion rootProject.ext.compileSdkVersion
buildToolsVersion rootProject.ext.buildToolsVersion
defaultConfig {
applicationId "com.xxx.xxx"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode rootProject.ext.versionCode
versionName rootProject.ext.versionName
}
}
六. module 調整目錄結構sourceSets
默認情況下,java文件和resource文件分別在src/main/java和src/main/res目錄下锦募,在build.gradle文件摆屯,andorid{}里面添加下面的代碼,便可以將java文件和resource文件放到src/java和src/resources目錄下糠亩。
sourceSets {
main {
java {
srcDir 'src/java'
}
resources {
srcDir 'src/resources'
}
}
}
簡便寫法
sourceSets {
min.java.srcDirs = ['src/java']
min.resources.srcDirs = ['src/resources']
}