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: MingHuang1024@foxmail.com

微信:724360018

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值