Gradle多渠道打包(動態設定App名稱,應用圖標,替換常量,更改包名,變動渠道)

若是本文幫助到你,本人不勝榮幸,若是浪費了你的時間,本人深感抱歉。 但願用最簡單的大白話來幫助那些像我同樣的人。若是有什麼錯誤,請必定指出,以避免誤導你們、也誤導我。 本文來自:www.jianshu.com/users/320f9… 感謝您的關注。java

最近有個需求一次要打包9個類型的App,並且常量和String.xml都有變量。雖然以前也是一直存在變量,可是每次也僅僅只打包一個。這讓我每次改變量,打包9個。要是之後每次都打包9次,我得瘋了。 根據以前的瞭解,gradle 應該是能夠解決這個問題的。因此就仔細研究了一番。android


先放一個完整的 多渠道/多環境 打包的配置,而後再來說解。git

實現了:github

  1. 不一樣環境,不一樣包名;
  2. 不一樣環境,修改不一樣的 string.xml 資源文件;
  3. 不一樣環境,修改指定的常量;
  4. 不一樣環境,修改 AndroidManifest.xml 裏渠道變量;
  5. 不一樣環境,引用不一樣的 module。

先放一個完整的配置,能夠參考:網絡

apply plugin: 'com.android.application'

android {
	compileSdkVersion 22
	buildToolsVersion '22.0.1'

	// 簽名文件
	signingConfigs {
		config {
			keyAlias 'lyl'
			keyPassword '123456'
			storeFile file('../lyl.jks')
			storePassword '123456'
		}
	}

	// 默認配置
	defaultConfig {
		//applicationId "com.lyl.app"
		minSdkVersion 16
		targetSdkVersion 22
		versionCode 1
		versionName "1.0.0"

		signingConfig signingConfigs.config
		multiDexEnabled true
        
        // gradle 3.0.0 以上須要有這個
        // flavorDimensions "app"
	}

	// 多渠道/多環境 的不一樣配置
	productFlavors {
		dev {
            // gradle 3.0.0 以上須要有這個
            // dimension "app"
            
			// 每一個環境包名不一樣
			applicationId "com.lyl.dev"
			// 動態添加 string.xml 字段;
			// 注意,這裏是添加,在 string.xml 不能有這個字段,會重名!!!
			resValue "string", "app_name", "dev_myapp"
			resValue "bool", "isrRank", 'false'
			// 動態修改 常量 字段
			buildConfigField "String", "ENVIRONMENT", '"dev"'
			// 修改 AndroidManifest.xml 裏渠道變量
            manifestPlaceholders = [UMENG_CHANNEL_VALUE: "dev"]
		}
		stage {
            // gradle 3.0.0 以上須要有這個
            // dimension "app"
        
			applicationId "com.lyl.stage"

			resValue "string", "app_name", "stage_myapp"
			resValue "bool", "isrRank", 'true'

			buildConfigField "String", "ENVIRONMENT", '"stage"'

			manifestPlaceholders = [UMENG_CHANNEL_VALUE: "stage"]
		}
		prod {
            // gradle 3.0.0 以上須要有這個
            // dimension "app"
        
			applicationId "com.lyl.prod"

			resValue "string", "app_name", "myapp"
			resValue "bool", "isrRank", 'true'

			buildConfigField "String", "ENVIRONMENT", '"prod"'

			manifestPlaceholders = [UMENG_CHANNEL_VALUE: "prod"]
		}
	}

    dexOptions {
        incremental true
        // javaMaxHeapSize "4g"
    }

	//移除lint檢測的error
	lintOptions {
		abortOnError false
	}

    def releaseTime() {
        return new Date().format("yyyy-MM-dd", TimeZone.getTimeZone("UTC"))
    }

	buildTypes {
		debug {
			signingConfig signingConfigs.config
		}

		release {
			buildConfigField("boolean", "LOG_DEBUG", "false")
			minifyEnabled false
			zipAlignEnabled true
			//移除無用的resource文件
			shrinkResources true
			proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
			signingConfig signingConfigs.config

			// 批量打包(gradle 3.0.0 如下)
			applicationVariants.all { variant ->
				variant.outputs.each { output ->
					def outputFile = output.outputFile
					if (outputFile != null && outputFile.name.endsWith('.apk')) {
						//輸出apk名稱爲:渠道名_版本名_時間.apk
						def fileName = "${variant.productFlavors[0].name}_v${defaultConfig.versionName}_${releaseTime()}.apk"
						output.outputFile = new File(outputFile.parent, fileName)
					}
				}
			}
            
            // 批量打包(gradle 3.0.0 以上)
            // android.applicationVariants.all { variant ->
            // variant.outputs.all {
            //     outputFileName = // "${variant.productFlavors[0].name}_v${defaultConfig.versionName}_${releaseTime()}.apk"
            // }
        }
		}
	}
}

repositories {
	mavenCentral()
}

dependencies {
	compile 'com.facebook.android:facebook-android-sdk:4.0.0'
	compile project(':qrscan')
	compile 'com.android.support:appcompat-v7:22.0.0'
	compile 'com.google.code.gson:gson:2.3'
	compile files('libs/android-async-http-1.4.6.jar')
	compile 'com.google.android.gms:play-services:7.5.0'
	compile 'com.android.support:support-annotations:22.1.1'
	compile 'com.github.bumptech.glide:glide:3.7.0'
	compile 'de.hdodenhof:circleimageview:2.1.0'
}
複製代碼

接下來咱們來詳細看看修改特定的字段。app

不一樣環境的設置基本都是在 productFlavors 裏設置的, 並且在裏面你想添加多少個環境均可以。async

1. 不一樣環境,不一樣包名;

productFlavors {
	dev {
		applicationId "com.lyl.dev"
	}

	stage {
		applicationId "com.lyl.stage"
	}

	prod {
		applicationId "com.lyl.prod"
	}
}
複製代碼

這裏注意,在 defaultConfig 中,你們應該都是寫了個默認的 applicationId 的。 經測試,productFlavors 設置的不一樣環境包名會覆蓋 defaultConfig 裏面的設置, 因此咱們能夠推測,它執行的順序應該是先執行默認的,而後在執行分渠道的,若是衝突,會覆蓋處理,這也很符合邏輯。maven


2. 不一樣環境,添加 string.xml 資源文件;

利用 resValue 來定義資源的值,顧名思義 res 底下的內容應該均可以建立,最後用 R.xxx.xxx 來引用。 以下就根據不一樣的類型,添加了不一樣的 app_name 字段,以及定義了 布爾值,能夠經過 R.string.app_name 來引用。ide

注意,這裏是添加,是在 string.xml 裏面添加了一個字段app_name,因此在現有的 string.xml 中不能有這個字段,不然會報錯!!!
productFlavors {
	dev {
		resValue "string", "app_name", "dev_myapp"
		resValue "bool", "isrRank", 'false'
	}
	stage {
		resValue "string", "app_name", "stage_myapp"
		resValue "bool", "isrRank", 'true'
	}
	prod {
		resValue "string", "app_name", "myapp"
		resValue "bool", "isrRank", 'true'
	}
}
複製代碼

經過以上咱們大概能夠推測出 color、dimen 也能夠經過相似的方法添加。測試


3. 不一樣環境,動態修改指定的常量;

使用 BuildConfig 的變量。

①定義字段

當咱們定義以下字段以後,編譯後自動生成文件,在 app/build/source/BuildConfig/dev/com.lyl.dev/BuildConfig 目錄, 打開這個文件,咱們就能看到咱們所定義的字段了。

productFlavors {
	dev {
		buildConfigField "String", "ENVIRONMENT", '"dev"'
	}
	stage {
		buildConfigField "String", "ENVIRONMENT", '"stage"'
	}
	prod {
		buildConfigField "String", "ENVIRONMENT", '"prod"'
	}
}
複製代碼
②引用字段

在咱們本身的任意的類中,來直接經過 BuildConfig 就能夠調用咱們定義的字段。

public class Constants {
	public static final String ENVIRONMENT = BuildConfig.ENVIRONMENT;

}
複製代碼

注意: 這裏有個小細節,看其中第三個參數,是先用了「'」,而後在用了「"」,這種語法在 Java 裏可能比較陌生,可是在不少其餘語言中,這種用法是很常見的。 它的意思是 "dev" 這個總體是屬於一個字符串,至於爲何要這麼寫,你把單引號去掉,而後去 app/build/source/BuildConfig/dev/com.lyl.dev/BuildConfig 這個文件看一看就知道了。


4. 不一樣環境,修改 AndroidManifest.xml 裏渠道變量

①在 AndroidManifest.xml 裏添加渠道變量
<application
	android:icon="${app_icon}"
	android:label="@string/app_name"
	android:theme="@style/AppTheme">
	...
	<meta-data
		android:name="UMENG_CHANNEL"
		android:value="${ENVIRONMENT}" />
	...
</application>
複製代碼
②在 build.gradle 設置 productFlavors
productFlavors {
    dev {
        manifestPlaceholders = [ENVIRONMENT: "dev",
								app_icon   : "@drawable/icon_dev"]
	}
	stage {
		manifestPlaceholders = [ENVIRONMENT: "stage",
								app_icon   : "@drawable/icon_stage"]
	}
	prod {
		manifestPlaceholders = [ENVIRONMENT: "prod",
								app_icon   : "@drawable/icon_prod"]
	}
}
複製代碼

這樣咱們能夠在不一樣環境使用不一樣的 key 值。


5. 不一樣環境,引用不一樣的 module

這個就很強大了,根據不一樣的環境,引用對應的 module。 你能夠替換大量的圖片,string,color,vaule等等。

首先,要創建跟渠道對應的 module,而後再引用。 引用方式以下:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    // 引用本的項目
    devCompile project(':devModule')
    stageCompile project(':stageModule')
    prodCompile project(':prodModule')

    // 也能夠分渠道引用網絡的。由於這裏都相同,因此地址也就都同樣了
    devCompile 'com.roughike:bottom-bar:2.0.2'
    stageCompile 'com.roughike:bottom-bar:2.0.2'
    prodCompile 'com.roughike:bottom-bar:2.0.2'
}
複製代碼

xxxCompile 表明 各個渠道的名稱。 而後把須要分渠道的文件,放到不一樣的 module 裏面,把主項目的文件刪掉。 **千萬注意:**若是這樣作了,每次須要引用的時候,在各個渠道的 module 裏面都必需要放置文件哦,否則會找不到資源。 經過這種方式能夠替換整套素材資源,具體如何使用還得看項目需求。



經過以上方式,咱們基本能夠 經過 gradle 動態設定應用標題,應用圖標,替換常量,設置不一樣包名,更改渠道等等。


打包編譯

最後,作完全部的配置以後,而後就是打包操做了。

打包某一個(平常編譯)

由於 buildTypes 裏面有兩種,因此每一個渠道都會有兩種模式。

打包全部的,就是正常打包流程

如圖所示:

圖片來源網絡

圖片來源網絡


打包完成以後,而後就能夠在咱們指定的目錄下,看到咱們所生成的apk包。

使用 local.properties 存放私密配置

以上就能夠基本實現 gradle 的設置,可是若是咱們要將咱們的項目上傳到 Github ,或者要將項目發送給別人。上面有些私密的東西就會被別人看到。好比:.jks 文件的密碼。 在項目跟目錄下,有個 local.properties 文件,咱們可使用它來存放一些私密的屬性,而後在 gradle 中讀取,而 local.properties 文件不須要上傳。 local.properties 文件裏設置以下:

sdk.dir=D\:\\Android\\android-sdk

gaodeKey=e348025dd034d1c347dd0345e34802

keyPassword=123456
複製代碼

在 build.gradle 讀取 local.properties 字段信息

// 加載 local.properties 資源
Properties properties = new Properties()
InputStream inputStream = project.rootProject.file('local.properties').newDataInputStream() ;
properties.load( inputStream )

android {
	...

	// 簽名文件
	signingConfigs {
		config {
			keyAlias 'lyl'
			// 獲取 local.properties 字段信息
			keyPassword properties.getProperty( 'keyPassword' )
			storeFile file('../lyl.jks')
			storePassword properties.getProperty( 'keyPassword' )
		}
	}

	...
}
複製代碼

這樣就能夠將本身想要隱藏的一些數據隱藏起來。


可能加快 Android Studio 編譯的辦法

1. 在根目錄的 build.gradle 里加上以下代碼:
allprojects {
    // 加上這個
    tasks.withType(JavaCompile) {
        //使在一個單獨的守護進程編譯
        options.fork = true
        //增量編譯
        options.incremental = true
    }

    repositories {
        jcenter()
    }
}
複製代碼
2. 在 app 級別下 build.gradle 裏 加上
android {
    dexOptions {
        incremental true
    }
}
複製代碼

最後放上一個多渠道的項目地址,能夠參考: github.com/Wing-Li/boo…

OK。 若是本文有什麼問題,請必定指出。 O(∩_∩)O

相關文章
相關標籤/搜索