在日常开发中,我们或多或少都会碰到多渠道打包的一些问题,有些是同一个版本要上传到不同的平台,有些是要提供给不同的代理商,中间可能需要改动里面的图片或其他的一些资源文件,对于版本比较少的我们可以简单的替换,但是遇到很多版本时,相信再通过手动替换会令人吐血~
废话不说,先来看下效果图,下面是根据不同平台需要打包出来的两个apk

apk界面展示效果如下(为了方便展示我在productFlavors里用了不同的applicationId “包名”,防止安装apk时被替换)

下面先来介绍一下如何根据不同版本的需求存放不同的资源文件

资源文件的适配

假如有这么一个需求:现在需要打包两个版本,小米和华为,其页面仅有一张图片,但要求两个版本的图片不一样,并且app的名称也不同,简单的做下适配
1、首先看下页面布局

<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.liuw.gradle.MainActivity"><ImageViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:src="@mipmap/userhead"/></LinearLayout>

正如需求所说,仅有一张图片,默认我们的res资源文件夹下肯定会有一张默认的userhead图片,但是要做到不同版本展示不同的图片,是不是很自然的会想到根据不同版本建立不同的资源文件目录

2、这里我建立了两个资源文件,res-huawei和res-xiaomi,展开看一下里面的内容

这里我直接将华为和小米平台所需的图片和文字用了相同的名称添加了进去,这样项目在打包时就会直接覆盖res文件下对应的资源
3、在gradle里配置不同平台采用不同的资源文件

//以下代码放在android{}内
//配置资源文件路径,可动态指定不同版本资源文件sourceSets {main {manifest.srcFile 'src/main/AndroidManifest.xml'java.srcDirs = ['src/main/java']resources.srcDirs = ['src/main/resources']aidl.srcDirs = ['src/main/aidl']renderscript.srcDirs = ['src/maom']res.srcDirs = ['src/main/res']assets.srcDirs = ['src/main/assets']jniLibs.srcDir 'src/main/jniLibs'}//用各自对应的资源文件路径xiaomi.res.srcDirs = ['src/main/res-xiaomi']huawei.res.srcDirs = ['src/main/res-huawei']// Move the tests to tests/java, tests/res, etc...instrumentTest.setRoot('tests')// Move the build types to build-types/<type>// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...// This moves them out of them default location under src/<type>/... which would// conflict with src/ being used by the main source set.// Adding new build types or product flavors should be accompanied// by a similar customization.debug.setRoot('build-types/debug')release.setRoot('build-types/release')}//渠道Flavors,配置不同风格的app
productFlavors {xiaomi{}huawei{}}//批量配置productFlavors.all {flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]}

配置完gradle里,别忘了在AndroidManifest里配置渠道标签

 <meta-dataandroid:name="UMENG_CHANNEL"android:value="${UMENG_CHANNEL_VALUE}"></meta-data>

到这里资源文件的基本配置就算结束了

配置多渠道打包

内容比较多,代码里注释也比较详细,这里就直接上代码了

apply plugin: 'com.android.application'android {compileSdkVersion 25buildToolsVersion "26.0.0"defaultConfig {applicationId "com.liuw.gradle"minSdkVersion 15targetSdkVersion 25versionCode 1versionName "1.0"testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"}//配置资源文件路径,可动态指定不同版本资源文件sourceSets {main {manifest.srcFile 'src/main/AndroidManifest.xml'java.srcDirs = ['src/main/java']resources.srcDirs = ['src/main/resources']aidl.srcDirs = ['src/main/aidl']renderscript.srcDirs = ['src/maom']res.srcDirs = ['src/main/res']assets.srcDirs = ['src/main/assets']jniLibs.srcDir 'src/main/jniLibs'}//用各自对应的资源文件路径xiaomi.res.srcDirs = ['src/main/res-xiaomi']huawei.res.srcDirs = ['src/main/res-huawei']// Move the tests to tests/java, tests/res, etc...instrumentTest.setRoot('tests')// Move the build types to build-types/<type>// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...// This moves them out of them default location under src/<type>/... which would// conflict with src/ being used by the main source set.// Adding new build types or product flavors should be accompanied// by a similar customization.debug.setRoot('build-types/debug')release.setRoot('build-types/release')}// rename the apk with the version name,版本比较多时,自定义导出的APK名称,不同的渠道编出的APK的文件名应该是不一样的applicationVariants.all { variant ->variant.outputs.each { output ->def outputFile = output.outputFileMap<String, String> map = System.getenv();String userName = map.get("USER");def des = '/Users/' + userName + '/Desktop/release/'//根据apk类型打包(release和debug两个版本,一般供单个应用打包使用)
//            if (variant.buildType.name.equals('release')) {
//                def releaseApkName = 'gradle_v' + getVersionName(project) + '.apk'
//                output.outputFile = new File(des + releaseApkName)
//            }
//            if (variant.buildType.name.equals('debug')) {
//            }//根据apk名称打包(这里就用到了同个apk,为不同平台打包,也可以打debug版本)if (outputFile != null) {//不知道名称的可以提前跑一遍,看下这里打印出来的日志println "======outputFile.name======" + outputFile.name;def fileName;if (outputFile.name.endsWith('app-xiaomi-release.apk')) {//打出包的包名,版本号为当前gradle里的versionName//fileName="xiaomi-gradle_v-${defaultConfig.versionName}.apk"//打出包的包名,版本号为AndroidManifest里获取的versionName fileName="xiaomi-gradle_v-${getVersionName(project)}.apk" }else if(outputFile.name.endsWith('app-huawei-release.apk')){
//                    fileName="huawei-gradle_v-${defaultConfig.versionName}.apk"fileName="huawei-gradle_v-${getVersionName(project)}.apk"} else {fileName='liuw-release.apk';//or debug版本}//默认outputs/apk目录下//output.outputFile = new File(outputFile.parent, fileName)//指定目录,根据自己需要指定output.outputFile = new File(des + fileName)}}}//debug和release版本的签名配置signingConfigs {debug {//这样写就得把keystore.jks文件放在项目目录,绝对路径storeFile file("keystore.jks")keyAlias = 'keystore'keyPassword = '123456'storePassword = '123456'}release {//这样keystore.jks文件可以放在桌面任何地方,配置一下路径即可storeFile file(getKeyStorePath())keyAlias = 'keystore'keyPassword = '123456'storePassword = '123456'}//有不同签名时,可定义多个,在productFlavors中调用
//        release1 {
//            storeFile file(getKeyStorePath())
//            keyAlias = 'keystore'
//            keyPassword = '123456'
//            storePassword = '123456'
//        }}//构建类型,通常有release和debug两种buildTypes {debug {// 显示LogbuildConfigField "boolean", "LOG_DEBUG", "true"versionNameSuffix "-debug"minifyEnabled falsezipAlignEnabled falseshrinkResources falsesigningConfig signingConfigs.debugmanifestPlaceholders=[jpush_appkey:"0f56521436362122"]}release {// 不显示LogbuildConfigField "boolean", "LOG_DEBUG", "false"//混淆minifyEnabled true//Zipalign优化zipAlignEnabled true// 移除无用的resource文件shrinkResources true//前一部分代表系统默认的android程序的混淆文件,该文件已经包含了基本的混淆声明//如果需要自定义混淆可把后面参数替换成混淆文件proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'//指定打包时的签名,如果有不同的签名可放在productFlavors不同项目下执行,不过一般都会相同signingConfig signingConfigs.release//manifestPlaceholders 可以替换androidmanifest文件中的标签的value值,可作为快速渠道打包替换渠道名的一种方式//也可以自定义标签用来替换需要的文本,多作为不同环境不同key的修改(如debug、release模式)manifestPlaceholders=[jpush_appkey:"0d14522663255632"]}}/** 渠道Flavors,配置不同风格的app* 资源文件不能用test字段命令(这里我尝试过会运行错误,如res-test)* debug模式下添加的资源文件默认只有一个,可以根据res图标看出来,运行时默认运行上次的文件,不过对打包无影响* */productFlavors {xiaomi{}huawei{}
//        baidu{
//            applicationId "com.liuw.badu"//可为不同版本动态指定包名
//            manifestPlaceholders=[UMENG_CHANNEL_VALUE:"xiaomi"] //可以替换AndroidManifest中标签的value值,此处也可用作多渠道打包标识,不过一般采用下面的批量配置
//            signingConfig signingConfigs.release1//此处可单独指定签名,前提是在signingConfigs里定义过了
//        }
//注意一点,这里的flavor名如果是数字开头,必须用引号引起来,如"360"{}}//批量配置productFlavors.all {flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name]}dexOptions {//最大堆内存javaMaxHeapSize '2048m'//预编译preDexLibraries = true//线程数threadCount = 16dexInProcess = true}
}android {//lint检查lintOptions {//所有正式版构建执行规则生成崩溃的lint检查,如果有崩溃问题将停止构建checkReleaseBuilds false// Or, if you prefer, you can continue to check for errors in release builds,// but continue the build even when errors are found://错误发生后停止gradle构建abortOnError false}
}//以下的两个def方法可以放在总工程路径下的build.gradle里使用ext置成全局供多个Module调用(通过rootProject.ext.xxx调用获取)
//获取桌面上的keystore路径
def getKeyStorePath() {Map<String, String> map = System.getenv();String userName = map.get("USER");def des = '/Users/' + userName + '/' + 'keystore.jks'return des
}//获取AndroidManifest中的versionName
def getVersionName(Project project) {def xmlFile = project.file("src/main/AndroidManifest.xml")def rootManifest = new XmlSlurper().parse(xmlFile)def versionName = rootManifest['@android:versionName']return versionName
}//依赖的jar包
dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {exclude group: 'com.android.support', module: 'support-annotations'})compile 'com.android.support:appcompat-v7:25.3.1'testCompile 'junit:junit:4.12'
}

如果想要看渠道命名是否成功,可以在主页面里调用以下代码

String channel;try {ApplicationInfo appInfo = getPackageManager().getApplicationInfo(getPackageName(),PackageManager.GET_META_DATA);channel = appInfo.metaData.getString("UMENG_CHANNEL");Log.i("TAG","UMENG_CHANNEL_VALUE=" + channel);} catch (PackageManager.NameNotFoundException e) {e.printStackTrace();}

签名文件如果有不会的可以参考下生成签名,我这里为了方便测试,在桌面上和项目根目录各放了一份,MAC和windows路径可能不一样,如果出现错误,可能要自己修改一下。
Ok,到这里基本就算结束了,我们可以执行一下./gradlew assembleRelease,等着打包完成吧。
assemble 这个命令,会结合 Build Type 创建自己的task,如:

./gradlew assembleDebug
./gradlew assembleRelease

除此之外 assemble 还能和 Product Flavor 结合创建新的任务,其实 assemble 是和 Build Variants 一起结合使用的,而 Build Variants = Build Type + Product Flavor , 举个例子大家就明白了:

如果我们想打包xiaomi渠道的release版本,执行如下命令就好了:

./gradlew assembleXiaomiRelease

如果我们只打xiaomi渠道版本,则:

./gradlew assembleXiaomi

此命令会生成xiaomi渠道的Release和Debug版本
同理我想打全部Release版本:
./gradlew assembleRelease
这条命令会把Product Flavor下的所有渠道的Release版本都打出来。

当我们productFlavors有多个版本,并且只想打包其中一个版本时,除了以上这种执行单个命令外,还可以在gradle里动态配置
1、先在根目录的gradle里添加一个全局参数

ext {LAUNCHER_FLAVOR = 'xiaomi'
}

2、再去Module的gradle里添加variantFilter进行过滤

android {
//用于指定版本,只打包指定版本variantFilter { variant ->def flavor = variant.flavors*.nameprintln "======variant.flavors======" + flavor;String name = 'defaultProject'if (project.hasProperty('LAUNCHER_FLAVOR')) {name = LAUNCHER_FLAVOR}if (!flavor.contains(name)) {setIgnore(true)} else if (flavor.contains('xiaomi')) {dependencies {xiaomiCompile project(':依赖的文件名')  // 动态添加依赖,括号内格式可能要注意下}}}}

这样打出来的包就只有xiaomi版本的apk。
那么又有人问了,上面的方法是通过命令打不同版本的包,如果我想编译debug包直接打包安装测试怎么办,这时候通过命令也是可以实现的,不过这里我们介绍另一种简单的直接使用as里的Build Variants工具,先选择不同版本的release和dubug再点击启动即可编译成对应的版本,如图所示:

完整项目已上传至CSDN资源,因为写在一起可能不便理解,可下载下来跑一遍对比看下效果可能会更容易理解些~
Gradle功能还是比较强大的,这里只是简单介绍,如有不妥之处,欢迎指正更改~
还看到两篇不错的文章,说的比较详细,也一起分享出来供大家参考Android打包的那些事,Gradle配置最佳实践

Gradle实现多渠道打包(不同资源文件打不同的包)相关推荐

  1. java jar包资源文件_深入jar包:从jar包中读取资源文件

    我们常常在代码中读取一些资源文件(比如图片,音乐,文本等等).在单独运行的时候这些简单的处理当然不会有问题.但是,如果我们把代码打成一个jar包以后,即使将资源文件一并打包,这些东西也找不出来了.看看 ...

  2. Android studio 多渠道打包(包括不同的包使用不同的资源文件、不同的包写不同的代码,包名等等)

    1,创建一个项目 ** 2,在项目中创建几个文件夹,等级和main文件夹平级,我这里创建了2个文件夹作为测试用.分别为ou1,out2.(文件夹名字按自己需求创建,用于区分不同渠道就行) ** 3,两 ...

  3. iOS架构-静态库.a打包之资源文件打包成bundle(4)

    iOS架构-静态库.a的打包及使用(一) iOS架构-静态库.a的脚本化打包及使用(二) 资源文件主要包括:xib.图片以及其他文件资源(json.string等).这里主要介绍 xib.图片.其他的 ...

  4. gin embed打包静态资源文件

    问题 在gin项目中如果单纯的只是实现api接口,那打包出来的是一个可执行文件.但如果项目中如果包含一些页面,则必定会引入一些css,jss,html文件.这样会使打包出来后会挂着对应的静态资源文件夹 ...

  5. 反编译用unity打包的资源文件

    如何反编译破解别人家的游戏包,美术资源是维权和侵权一直杠下去的话题,如果作为商业用途,我是反对破坏原作者的创意,侵害作者的劳动果实行为.但是如果是仅仅为了学习,实验,不妨参考我的文章,我相信你可以从我 ...

  6. Gradle配置多渠道打包

    项目开发的过程都会有打包的需求,如果项目规模不大,对渠道的要求不高可以只打一个release包,然后上传到所有应用市场就行了.但是如果有一些特殊需求,比如做ASO优化,应用数据分析等等就需要打包上传应 ...

  7. android——利用gradle实现多渠道打包并自定义包名(umeng多渠道)

    1.首先在mainfest.xml文件中,给umeng_channel设置一个变量"${UMENG_CHANNEL_VALUE}" 2.在gradle中,配置flavors. pr ...

  8. 【解决方案】IDEA 配合 gradle 时候无法正确编译资源文件resources的问题

    问题说明: 使用的是 gradle 导入项目,没想到发现编译之后测试的时候出错了,报的错误为 file cannot be opened because it does not exist 也就是文件 ...

  9. Maven打包Resource资源文件损坏解决

    将静态文件拷贝到static/public/resource文件夹下访问时,图标与字体文件会进行过滤导致损坏,需要在pom文件中进行设置 <build><resources>& ...

  10. android一行命令实现多渠道打包并自动进行资源混淆(Walle,AndResGuard)

    多渠道打包和资源混淆的作用这里我就不再阐述了.网上有很多. 本篇博客我们来介绍一下如何实现多渠道打包之前先进行资源混淆,这样一来我们打出来的包都是已经进行过资源混淆的了. 如果你还有其他的需求,也可以 ...

最新文章

  1. tensorflow 入门实例(二)
  2. pandas中loc、iloc与ix的用法比较
  3. SpringCloud教程- 服务链路追踪(Spring Cloud Sleuth)(SpringCloud版本Greenwich.SR4)
  4. linux openssh升级8.1,Centos7利用rpm升级OpenSSH到openssh-8.1p1版本
  5. LeetCode 207. 课程表(拓扑排序)
  6. 经典面试题(22):以下代码将输出的结果是什么?
  7. Hive篇--搭建Hive集群
  8. 基类Object的子类有哪些以及字符串和数组的方法
  9. ./configure,make,make install 的作用
  10. AI 深度关键短语生成
  11. 【语音判别】基于matlab双门限法判别语音信号【含Matlab源码 1720期】
  12. m6000查看端口状态_中兴ZXR10 M6000维护最常用命令精要
  13. 浅析json_encode
  14. ligerUI的dialog
  15. [CTF]天下武功唯快不破
  16. 吕旭军:如何打造区块链数字资产交易?
  17. 2019.01.17【BZOJ4399】 魔法少女LJJ(FHQ_treap)(ODT)
  18. css实现人走路效果,纯css实现机器人走路动画
  19. unbound部署DNS服务器
  20. 【Linux】linux进程--进程控制:进程创建、进程终止、进程等待、进程程序替换

热门文章

  1. 2017前端开发手册三-前端职位描述
  2. Ubuntu安装应用商店中没有的软件
  3. [html5游戏开发]数独游戏-完整算法-开源讲座
  4. jquery使用 validate 插件进行验证是否通过
  5. linux考试中的7654_7654支持的未启用卡指的是()
  6. 咏红梅花——曹雪芹_ywyuan_新浪博客
  7. 如何将分表汇总到总表_如何快速将几个分表合并到一张表
  8. Excel把表中一个单元格对应多个数据汇总到一个单元格内
  9. RT-Preempt笔记
  10. 手机总是显示服务器太忙,手机总提示服务器太忙请稍后重试