Android多渠道打包配置

Android多渠道打包配置

之前爲了在同一臺手機能同時安裝測試包和生產包,採用配置buildType的方式來實現,相比於flavor,感覺是挺輕量又恰到好處的配置,具體見通過配置applicationId來實現測試包和生產包安裝在同一臺手機上。最近因爲業務需要,需要多個渠道的包了,這就必須要用到flavor這個大殺器了。一路配置下來,感覺還挺順,下面就具體記錄一下。

###目標
先說一下需求,增加一個渠道

  1. 功能代碼幾乎完全相同,個別接口要根據渠道傳參
  2. logo要按渠道配置
  3. 應用程序的名子也要不同
  4. 部分頁面的標識性圖片要按渠道配置

大概就是這麼些東西需要根據渠道來配置的。不過還有一些潛在的東西也需要按渠道來配置,如:

  • applicationId,肯定是要不同的
  • 簽名肯定是區分的
  • 百度地圖的key也必須要根據渠道配置的,以及其它類似的三方鑑權相關配置
  • 自動升級時安裝app所需要的fileProviderAuthority也要區分

由於我還保留着degbug與release包使用不同的applicationId,實際上兩個渠道共4個包都是不同id的,某些參數除了要根據渠道區分還要再根據buildType做相應的配置。

實施

一、先把flavor配置起來,在app的build.gradle文件中的 android 代碼塊中添加

// 定義flavor的dimension,至少要有一個dimension,名字隨便取,這個必須要的,不然會報錯
flavorDimensions "version"

// 渠道包定義,默認定義的名稱就是渠道名稱
productFlavors {
    // google渠道
    google {
        applicationId = "com.my.google"
    }
    // twitter渠道
    twitter {
        applicationId = "com.my.twitter"
    }
}

這裏配置了兩個渠道,並指定了它們各自的applicationId,值得注意的是必須要先設置flavorDimensions,值可以隨便取。

二、配置簽名

//配置簽名
signingConfigs {
    google {
        storeFile file("D:/docs/keyStore/googleKeyStore.jks")
        storePassword "111111"
        keyAlias "key0"
        keyPassword "222222"
    }
    twitter {
        storeFile file("D:/docs/keyStore/twitterKeyStore.jks")
        storePassword "333333"
        keyAlias "key1"
        keyPassword "444444"
    }
}

storeFile是KeyStore.jks文件所在的目錄,這裏配置的所有內容都是創建jks的時候自己填的。

jks的創建

as菜單 Build–>Generate Signed Bundle/APK…->選中APK–>Next–>Create new…

在打開的填寫文件路徑、密碼等內容,一路next就行了

配置好之後,在flavor塊中加上對簽名的引用,如下

productFlavors {
    // google渠道
    google {
        applicationId = "com.my.google"
        signingConfig signingConfigs.google
    }
    // twitter渠道
    twitter {
        applicationId = "com.my.twitter"
        signingConfig signingConfigs.twitter
    }
}
  • 注意一點,signingConfigs{…}代碼塊要放在引用它的代碼之前,否則會找不到引用的簽名

三、 配置只需要區分渠道而不需要區分buildType的參數,如:頁面中的圖片,接口參數等

這些參數都可以用buildConfigField方法來設置,這個方法將在BuildConfig類中添加一個字段,它接受三個參數,第一個是數據類型,第二個是字段名,第三個是字段值,如:

buildConfigField "Integer", "LOGIN_ICON", "R.drawable.login_icon_google"
buildConfigField "String", "LOGIN_TEXT", "請輸入google賬號"

在java代碼中直接用 BuildConfig.LOGIN_ICONBuildConfig.LOGIN_TEXT 來引用對應的圖片或文字,非常方便。將這個代碼寫在flavor塊內,如下:

productFlavors {
    // google渠道
    google {
        applicationId = "com.my.google"
        signingConfig signingConfigs.google
		buildConfigField "Integer", "LOGIN_ICON", "R.drawable.login_icon_google"
		buildConfigField "String", "LOGIN_TEXT", "\"請輸入google賬號\""
    }
    // twitter渠道
    twitter {
        applicationId = "com.my.twitter"
        signingConfig signingConfigs.twitter
		buildConfigField "Integer", "LOGIN_ICON", "R.drawable.login_icon_twitter"
		buildConfigField "String", "LOGIN_TEXT", "\"請輸入twitter賬號\""
    }
}

四、配置buildType的內容,有部分內容還要區分flavor,如:appName,百度地圖key等

buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
			// 配置生產環境url
            buildConfigField "String", "BASE_URL", "\"https://a.b.c.release.com\""
            // 要區分渠道的內容
            if (mFlavor == "google") {
                // google渠道生產版百度地圖key
                manifestPlaceholders = [baiduMapKey          : "11111111111",
                                        fileProviderAuthority: "aaaaaaaa",
                                        logo                 : "R.drawable.logo_google_release"
                ]

                resValue 'string', 'app_name', "我的應用google版"
                resValue 'string', 'authority', "aaaaaaaa"

            } else {
                // twitter渠道生產版百度地圖key
                manifestPlaceholders = [baiduMapKey          : "22222222",
                                        fileProviderAuthority: "bbbbbbbbb",
                                        logo                 : "R.drawable.logo_twitter_release",
                ]
                resValue 'string', 'app_name', "我的應用twitter版"
                resValue 'string', 'authority', "bbbbbbbbb"
            }
        }
        debug {
			// debug包的applicationId在生產包的後面加上後綴".abc"
            applicationIdSuffix ".abc"
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            // 配置測試環境url
            buildConfigField "String", "BASE_URL", "\"https://a.b.c.release.com\""
            // 要區分渠道的內容
            if (mFlavor == "google") {
                // google渠道測試版百度地圖key
                manifestPlaceholders = [baiduMapKey          : "88888888",
                                        fileProviderAuthority: "mmmmmmmmm",
                                        logo                 : "R.drawable.logo_google_debug"
                ]

                resValue 'string', 'app_name', "我的應用google版_測試包"
                resValue 'string', 'authority', "mmmmmmmmm"

            } else {
                // twitter渠道測試版百度地圖key
                manifestPlaceholders = [baiduMapKey          : "99999999",
                                        fileProviderAuthority: "nnnnnnnnn",
                                        logo                 : "R.drawable.logo_twitter_debug"
                ]
                resValue 'string', 'app_name', "我的應用twitter版_測試包"
                resValue 'string', 'authority', "nnnnnnnnn"
            }
        }
}

這裏用到了另外兩種配置參數的方法,一是manifestPlaceholders,二是resValue。
manifestPlaceholders 可以在 AndroidManifest.xml 中替換參數的值,它接受一個 Map<String, Object> 類型的參數,如以下配置

manifestPlaceholders = [baiduMapKey          : "99999999",
                        logo                 : "R.drawable.logo_twitter_debug"
                ]

在 AndroidManifest.xml 文件中用以下方式來取得配置的值:

<!-- 百度地圖開發者key -->
<meta-data
    android:name="com.baidu.lbsapi.API_KEY"
    android:value="${baiduMapKey}" />

android:icon="${logo}"

這樣,不同渠道取出來的 baiduMapKey 值就不一樣了,達到了動態配置的目的

resValue 相當於在 res/values 文件夾下的某個資源文件中增加一個資源,比如在 res/values/strings 中增加一個字符串

resValue 'string', 'app_name', "我的應用twitter版_測試包"

在 xml 文件中就可以引用這個字符串了

android:label="@string/app_name"

這種方式要注意一點:如果原先 strings.xml 文件中已經定義了一個 app_name 的字符串,必須要將這個定義去掉,否則會報資源重複的錯誤。

還有一點值得注意的是:在 buildType 代碼塊中怎麼判斷 flavor ,我借鑑了網上的一種方法,是根據taskName來判斷當前編譯的代碼是屬於哪個渠道,不知道有沒有更好方式來判斷了。

def getFlavor() {
    def runTasks = gradle.startParameter.taskNames
    def gR = ':app:assembleGoogleRelease'
    def gD = ':app:assembleGoogleDebug'
    def tR = ':app:assembleTwitterRelease'
    def tD = ':app:assembleTwitterDebug'
    if (gR in runTasks || gD in runTasks) {
        return "google"
    }
    if (tR in runTasks || tD in runTasks) {
        return "twitter"
    }
    return ""
}

這樣,整個配置就完成了,下面把完整的 app下的build.gradle文件中跟渠道配置相關的代碼貼出來

android {
	// 獲取渠道名
    def mFlavor = getFlavor()

    compileSdkVersion 28
    defaultConfig {
        minSdkVersion 15
        targetSdkVersion 26
        // 版本號
        versionCode 123
        // 版本名
        versionName 1.2.3
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        multiDexEnabled true
    }

	//配置簽名
    signingConfigs {
        google {
            storeFile file("D:/docs/keyStore/googleKeyStore.jks")
            storePassword "111111"
            keyAlias "key0"
            keyPassword "222222"
        }
        twitter {
            storeFile file("D:/docs/keyStore/twitterKeyStore.jks")
            storePassword "333333"
            keyAlias "key1"
            keyPassword "444444"
        }
    }

	buildTypes {
	    release {
	        minifyEnabled true
	        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
		 	// 配置生產環境url
	        buildConfigField "String", "BASE_URL", "\"https://a.b.c.release.com\""
	        // 要區分渠道的內容
	        if (mFlavor == "google") {
	            // google渠道生產版百度地圖key
	            manifestPlaceholders = [baiduMapKey          : "11111111111",
	                                    fileProviderAuthority: "aaaaaaaa",
	                                    logo                 : "R.drawable.logo_google_release"
	            ]
	    
	            resValue 'string', 'app_name', "我的應用google版"
	            resValue 'string', 'authority', "aaaaaaaa"
	    
	        } else {
	            // twitter渠道生產版百度地圖key
	            manifestPlaceholders = [baiduMapKey          : "22222222",
	                                    fileProviderAuthority: "bbbbbbbbb",
	                                    logo                 : "R.drawable.logo_twitter_release",
	            ]
	            resValue 'string', 'app_name', "我的應用twitter版"
	            resValue 'string', 'authority', "bbbbbbbbb"
	        }
	    }
	    debug {
		 	// debug包的applicationId在生產包的後面加上後綴".abc"
	        applicationIdSuffix ".abc"
	        minifyEnabled false
	        proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
	        // 配置測試環境url
	        buildConfigField "String", "BASE_URL", "\"https://a.b.c.release.com\""
	        // 要區分渠道的內容
	        if (mFlavor == "google") {
	            // google渠道測試版百度地圖key
	            manifestPlaceholders = [baiduMapKey          : "88888888",
	                                    fileProviderAuthority: "mmmmmmmmm",
	                                    logo                 : "R.drawable.logo_google_debug"
	            ]
	    
	            resValue 'string', 'app_name', "我的應用google版_測試包"
	            resValue 'string', 'authority', "mmmmmmmmm"
	    
	        } else {
	            // twitter渠道測試版百度地圖key
	            manifestPlaceholders = [baiduMapKey          : "99999999",
	                                    fileProviderAuthority: "nnnnnnnnn",
	                                    logo                 : "R.drawable.logo_twitter_debug"
	            ]
	            resValue 'string', 'app_name', "我的應用twitter版_測試包"
	            resValue 'string', 'authority', "nnnnnnnnn"
	        }
	    }
    }

    // 定義flavor的dimension,至少要有一個dimension,名字隨便取,這個必須要的,不然會報錯
    flavorDimensions "version"

	productFlavors {
        // google渠道
        google {
            applicationId = "com.my.google"
            signingConfig signingConfigs.google
			buildConfigField "Integer", "LOGIN_ICON", "R.drawable.login_icon_google"
    		buildConfigField "String", "LOGIN_TEXT", "\"請輸入google賬號\""
        }
        // twitter渠道
        twitter {
            applicationId = "com.my.twitter"
            signingConfig signingConfigs.twitter
			buildConfigField "Integer", "LOGIN_ICON", "R.drawable.login_icon_twitter"
    		buildConfigField "String", "LOGIN_TEXT", "\"請輸入twitter賬號\""
        }
    }
}

def getFlavor() {
    def runTasks = gradle.startParameter.taskNames
    def gR = ':app:assembleGoogleRelease'
    def gD = ':app:assembleGoogleDebug'
    def tR = ':app:assembleTwitterRelease'
    def tD = ':app:assembleTwitterDebug'
    if (gR in runTasks || gD in runTasks) {
        return "google"
    }
    if (tR in runTasks || tD in runTasks) {
        return "twitter"
    }
    return ""
}




由於水平有限,如果文中存在錯誤之處,請大家批評指正,歡迎大家一起來分享、探討!

博客:http://blog.csdn.net/MingHuang2017

GitHub:https://github.com/MingHuang1024

Email: [email protected]

微信:724360018

發佈了24 篇原創文章 · 獲贊 31 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章