Gradle的神奇之处
转载请注明出处:http://blog.csdn.net/crazy1235/article/details/50465885
Google I/O 2013大会上发布了AS,如今已经发展到2.0-beta版本。相信已经大部分人做Android开发的都已经由Eclipse IDE转为AS IDE。
随着AS版本的更迭,也带来不少为为开发者提供便利的工具。比如这篇blog所描述的:http://blog.csdn.net/crazy1235/article/details/49747141
本人从AS1.2版本开始使用,如今也用了大半年了。现将使用过程中的一些经验分享给大家。
- gradle的基本配置
- gradle的签名配置
- 配置buildTypes
- 配置productFlavor
- manifest占位符
- 添加自定义字段
- 自定义导出APK的名称
- Demo下载
gradle的基本配置
apply plugin: 'com.android.application'android {compileSdkVersion 23buildToolsVersion "23.0.2"defaultConfig {applicationId "com.jacksen.multichannel"minSdkVersion 14targetSdkVersion 23versionCode 1versionName "1.0"}buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'}}
}dependencies {compile fileTree(dir: 'libs', include: ['*.jar'])testCompile 'junit:junit:4.12'compile 'com.android.support:appcompat-v7:23.1.1'compile 'com.android.support:design:23.1.1'
}
上面的就是一个项目gradle的基本配置。
apply plugin: 'com.android.application'
表示该module是一个app module,应用了com.android.application插件,也就是主程序。如果是一个第三方library,则应该是app plugin: ‘com.android.library’
buildTypes { } 表示构建类型。包括release和debug两种。可以在这里面配置启用混淆、zipAlign、签名信息等。
dependencies { } 里面是项目的依赖信息,包括jar包和第三方库等信息。
ApplicationId与PackageName的区别:
此前使用eclipse进行开发的时候,应用程序的包名是由manifest文件的package属性决定的:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.xxx.xxxx"android:versionCode="1"android:versionName="1.0" >
然而在使用gradle构建的时候却多了一个applicationId。通常gradle中的applicationId和Manifest中的package是一样的。其实可以使二者一致。
官方解释说是:applicationId是你的应用在商店的唯一标识。而package是引用资源的路径名,也就是R文件的包名。
上面我们说到二者可以不一致,我们可以通过对不同的Flavor设置不同的applicationId,从而可以导出不同“包名”的apk,而不需要修改其他的代码。后面会仔细说明。
gradle的签名配置
关于签名的概念不懂得,可以参考这篇blog:Android从零单排之签名打包
我们通常运行项目都是使用debug的签名。不过有些使用到第三方sdk的时候,需要用到正式版的签名,通过打包正式签名的方式又不好调试。不过我们可以在gradle里面配置正式版的签名。
android {signingConfigs {config_release {keyAlias 'releaseKey'keyPassword '123456'storePassword '123456'storeFile file('key/releaseKey.jks')}config_debug {keyAlias 'debugKey'keyPassword '123456'storePassword '123456'storeFile file('key/debugKey.jks')}}......//省略其他配置
}
这里配置了两个签名。jsk都放在app下面的key文件夹中。所以使用的是相对路径。
之前有人问我是怎么知道keyAlias 、keyPassword这些语法的。其实在项目的【Project Structure】中都可以找到。
配置buildTypes
一般在buildTypes{ }里面配置两个(release和debug):
buildTypes {release {minifyEnabled falseproguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'shrinkResources true //移除无效的resource文件,必须允许ProGuard才能生效zipAlignEnabled truebuildConfigField "boolean", "APP_TYPE", "true"manifestPlaceholders = [APP_NAME: "@string/app_name_release"]signingConfig signingConfigs.config}debug {buildConfigField "boolean", "APP_TYPE", "false"
// manifestPlaceholders = [APP_NAME: "@string/app_name_debug"]applicationIdSuffix 'debug'}}
这里可配置的信息很多,比如:是否可以是debug模式、签名配置、混淆文件等。
配置productFlavor
多渠道打包,关键就在于定义多个productFlavor。
在一个flavor里面可配置的信息很多。
productFlavors {flavor_release {buildConfigField "boolean", "APP_TYPE", "false"applicationId 'com.jacksen.multichannel.release'signingConfig signingConfigs.config_releaseminSdkVersion 9targetSdkVersion 15versionCode 2versionName '2.0.1'}flavor_debug {minSdkVersion 10applicationId 'com.jacksen.multichannel.debug'signingConfig signingConfigs.config_debugversionCode 5versionName '5.0'}}
最主要的是可以在这里配置applicationId,就是我们上面一开始说的打包多个不同“包名”的apk。
这样有一个应用场景就是,我们一般通过debug版本进行测试之后,在进行release版本的测试。不过同一个applicationId的apk在一个测试机上只能存在一个。现在我们通过配置多个flavor对应多个applicationId,就可以在测试机上运行测试版和正式版两个apk了。
productFlavors{ } 与 buildTypes{ }里面的配置是多对多的关系。
比如:
buildTypes {release {...}debug {...}
}
productFlavors {flavor_1 {...}flavor_2 {...}
}
此时的配置可以打包出四个apk,分别是:
我们在使用as的打包工具时,可以选择打包某一个Build type的某一个或多个Flavors:
如果在gradle里面配置了签名信息,那么在【Generate Signed APK】的第一步填写的签名信息是以在gradle里面配置并引用的为准。
我们还可以借助gradlew命令来打包:
比如打包flavor_1对应的release和debug版本:
打包flavor_2对应的release版本:
实际上,我们不用再记住这些命令。AS里面的gradle插件就可以实现。
在AS的右侧会有【Gradle】tab页面。打开之后,先刷新一下。会看到如下图示:
通过双击右边的命令打包不同的版本。
除了build下面的命令,还有其他的命令,大家都可以尝试一下,根据名字应该就能知道什么意思,这里不多介绍了。
manifest占位符
在打包多个版本的时候,会遇到修改应用名称等需求。不同的flavor有要求不通的名称。此时可以在Manifest文件中使用占位符,然后在build.gradle中替换占位符就行了。
首先定义占位符:
applicationandroid:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="${APP_NAME}"android:supportsRtl="true"android:theme="@style/AppTheme"><activityandroid:name=".LoginActivity"android:label="${APP_NAME}"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application>
在build.gradle中替换:
buildTypes {release {manifestPlaceholders = [APP_NAME: "@string/app_name1"]}debug {manifestPlaceholders = [APP_NAME: "@string/app_name1"]}}
productFlavors {flavor_1 {manifestPlaceholders = [APP_NAME: "@string/app_name1"]}flavor_2 {manifestPlaceholders = [APP_NAME: "@string/app_name2"]}}
如果在productFlavors和buildTypes里面都进行了替换,那么是以productFlavors里面的为准。
如果不区分productFlavors和buildTypes的话,也可以在defaultConfig里进行替换:
defaultConfig {manifestPlaceholders = [APP_NAME: "@string/app_name_release"]}
其实defaultConfig也是productFlavors的一个子集。
添加自定义字段
Gradle在generateSources阶段为每一个flavor生成两个BuildConfig.java文件(对应在release和debug文件夹下)。
BuildConfig类默认会提供一些常量字段。
public final class BuildConfig {public static final boolean DEBUG = Boolean.parseBoolean("true");public static final String APPLICATION_ID = "com.jacksen.multichannel";public static final String BUILD_TYPE = "debug";public static final String FLAVOR = "";public static final int VERSION_CODE = 1;public static final String VERSION_NAME = "1.0";
}
虽然通过上面的操作,我们可以同时打包出一个debug版本和一个release版本。但是我们还需要运行的时候有不同的表现。比如,release版本不显示一些控件。
令人惊奇的是,我们可以通过buildConfigField在gradle里面自定义一些字段。
buildConfigField "String", "APP_TYPE", "debug"
我们可以查看buildConfigField的源码:
/*** Adds a new field to the generated BuildConfig class.** <p>The field is generated as: <code><type> <name> = <value>;</code>** <p>This means each of these must have valid Java content. If the type is a String, then the* value should include quotes.** @param type the type of the field* @param name the name of the field* @param value the value of the field*/public void buildConfigField(@NonNull String type,@NonNull String name,@NonNull String value) {ClassField alreadyPresent = getBuildConfigFields().get(name);if (alreadyPresent != null) {logger.info("BuildType(${getName()}): buildConfigField '$name' value is being replaced: ${alreadyPresent.value} -> $value");}addBuildConfigField(AndroidBuilder.createClassField(type, name, value));}
注释写的很详细。该方法就是添加一个field到BuildConfig类中。三个参数都是不可为空的。
添加完毕之后,就可以在代码中使用了:
textView.setText("BuildConfig.APP_TYPE : " + BuildConfig.APP_TYPE);
自定义导出APK的名称
我直接上代码吧。
/*applicationVariants.all {variant ->variant.outputs.each {output ->def outputFile = output.outputFileif (outputFile != null && outputFile.name.endsWith('.apk')) {
// def fileName = outputFile.name.replace(".apk", "-${defaultConfig.versionName}.apk")def apkType = ""if (variant.flavorName.equals("releaseFlavor")){apkType = "release"}else if(variant.flavorName.equals("debugFlavor")){apkType = "debug"}def fileName = new File(output.outputFile.getParent(), "app-" + apkType + "-${variant.versionName}.apk")
// output.outputFile = new File(outputFile.parent, fileName)output.outputFile = fileName}}}*/applicationVariants.all {variant ->variant.outputs.each {output ->def outputFile = output.outputFileif (outputFile != null && outputFile.name.endsWith('.apk')) {def fileName = outputFile.name.replace(".apk", "-${defaultConfig.versionCode}-${defaultConfig.versionName}.apk")output.outputFile = new File(outputFile.parent, fileName)}}}
这里有两种方式,大家运行一下测试一下就明白了。
以上就是我对gradle的一些认识~~~
Demo下载
https://github.com/crazy1235/MultiChannel
欢迎star~~
参考:
http://tech.meituan.com/mt-apk-adaptation.html
http://www.jayfeng.com/2015/11/07/Android%E6%89%93%E5%8C%85%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B/
http://www.jcodecraeer.com/a/anzhuokaifa/Android_Studio/2015/0810/3281.html
此篇blog到此结束~
感谢大家支持!如有错误,请指出~
谢谢~
Gradle的神奇之处相关推荐
- 揭秘:蓝光光碟“造”太阳能电池的神奇之处
OFweek光学网讯:蓝光光碟以提供高存储容量和高品质影音著称.不过最近,美国西北大学材料科学与工程系黄嘉兴副教授的研究团队发现,只用蓝光光碟看片实在太屈才了--他们将成龙的<警察故事Ⅲ:超级警 ...
- 【转】RNN的神奇之处(The Unreasonable Effectiveness of Recurrent Neural Networks)
转自:https://blog.csdn.net/menc15/article/details/78775010 本文译自http://karpathy.github.io/2015/05/21/rn ...
- RNN的神奇之处(The Unreasonable Effectiveness of Recurrent Neural Networks)
本文译自http://karpathy.github.io/2015/05/21/rnn-effectiveness/.结合个人背景知识,忠于原文翻译,如有不明欢迎讨论. 以下正文. RNN有很多神奇 ...
- 究竟Python语言有什么神奇之处,让它如此火爆?
从你开始学习编程的那一刻起,就注定了以后所要走的路-从编程学习者开始,依次经历实习生.程序员.软件工程师.架构师.CTO等职位的磨砺:当你站在职位顶峰的位置蓦然回首时,会发现自己的成功并不是偶然,在程 ...
- “想象之中”,【玉石雕刻刀】的神奇之处
"想象之中"[玉石雕刻刀]的神奇之处 玉石雕刻刀雕刻深度的问题 浮动刀头顾名思义是在雕刻平面上,可在一定的范围内上上下浮动.主轴在Z轴方向上是可上下滑动的,当使用浮动刀头时注重于 ...
- 单管发报机的神奇之处-身兼两职
➤01 简易无线发报机 1.发报机演示 在头条上有一个视频,介绍了一款 简易无线发报机 ,给了一款仅仅使用一个高频硅三极管( 9018 )构成的调幅无线发报机.虽然是一个高频电路,为了说明电路的构造原 ...
- 单元测试框架怎么搭?快来看看新版Junit5的这些神奇之处吧!
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 为什么使用JUnit5 JUnit4被广泛使用,但是许多场 ...
- 竟然在GitHub标星27k+阿里大牛肝出的443页TCP/IP协议趣谈笔记,有何神奇之处?
前言: 十个人程序员里面,有十个都会说自己学过网络协议,九个人都会说自己懂网络协议.但是面试的时候,问几个问题,能回答的可能只有两三个.不信?来,我问你几道. 1.TCP 协议跟 UDP 协议有什么区 ...
- 微型计算机上面的Tab键,电脑键盘上Tab 键的神奇之处!(用途详解)
下面通过实例来详细解释下: 假设"D:\cfan"路径下,有文件夹: a. ab ,有文件: abc.txt , ac.txt .依次点击"开始→运行"输入&q ...
- 三分钟创建一个新应用,ivx的神奇之处【PPT式程序开发】
像做PPT一样的可视化编程语言你想拥有吗,可以自己尝试一下.像PPT一样的编程语言 文章目录
最新文章
- main方法_你知道为什么Java的main方法必须是public static void?
- 需要监控JanusGraph的一些指标
- 【netty】netty HashedWheelTimer 延时队列
- 【工程项目经验】多个静态库打包成一个静态库
- C语言读取图像像素坐标,OpenCL中读取image时的坐标
- 从零开始,我用了两年半逆袭秋招!
- (day 19 - 动态规划)剑指 Offer 42. 连续子数组的最大和
- 制作OpenStack xpsp3镜像
- python读书心得体会范文_读书心得体会范文6篇
- 文本相似度计算(中英文)详解实战
- [编译原理随记]正则表达式转为NFA状态图(Thompsion构造法)
- pc模拟器运行多个Android,低配电脑如何强制开50个安卓模拟器挂机
- 浅谈public static void main(String[] args)
- 西电工作笔记(部分)【10000字】【原创】
- vue实现 导出为word模板
- 2023年Java面试题大全(最新版版)面试题附答案详解,看完BTA可进
- [激光原理与应用-41]:《光电检测技术-8》- 白光干涉仪
- 实现一个 柯里化函数
- 只需+1s,GitHub代码一键转成VS Code
- 小程序实现图片放大预览功能
热门文章
- ae合成设置快捷键_AE脚本使用快捷键控制关键帧操作 Keyboard v1.2.1 + 使用教程【资源分享1081】...
- maven [INFO] No proxies configured [INFO] No proxy was configured, downloading directly
- 什么是Web前端工程师?为什么Web前端工资如此之高呢?
- 虚拟机安装CentOS6.5分配内存一般20G,之后如何扩展内存,扩充磁盘!
- 如何实现网易公开课的倍速播放?
- 数据智能,慧眼识“真”——个推大数据风控产品亮相
- 文本信息过滤中的变体词识别(一)
- 【non-coding RNA】 非编码RNA有哪些?
- 怎么把系统桌面设置到D盘
- 专转本-矩阵的初等变换与线性方程组