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的基本配置
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.jacksen.multichannel"
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles 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 false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
shrinkResources true //移除无效的resource文件,必须同意ProGuard才干生效
zipAlignEnabled true
buildConfigField "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_release
minSdkVersion 9
targetSdkVersion 15
versionCode 2
versionName '2.0.1'
}
flavor_debug {
minSdkVersion 10
applicationId 'com.jacksen.multichannel.debug'
signingConfig signingConfigs.config_debug
versionCode 5
versionName '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中替换占位符即可了。
首先定义占位符:
application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="${APP_NAME}"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android: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.outputFile
if (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.outputFile
if (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的奇妙之处的更多相关文章
- [Gradle] 在 Eclipse 下利用 gradle 构建系统
转载自:http://www.ibm.com/developerworks/cn/opensource/os-cn-gradle/ 构建系统时候常常要用到 Ant, Maven 等工具,对于初学者 ...
- Java序列化流的奇妙之旅
Java序列化流有何奇妙之处呢?通过一个个案例逐一感受序列化流. !!!好戏在后头!!! 1.IO流读写文件 先从一个普通文件读写字符串开始讲起. 例子:输出字符串到文件,再从文件中读取字符串 在某一 ...
- Android 自己实现 NavigationView [Design Support Library(1)]
转载请标明出处: http://blog.csdn.net/lmj623565791/article/details/46405409: 本文出自:[张鸿洋的博客] 一.概述 Google I/O 2 ...
- 探寻 JavaScript 逻辑运算符(与、或)的真谛
十二月已经过半,冬季是一个美妙的季节,寒冷的空气逼得人们不得不躲在安逸舒适的环境里生活.冬季会给人一种安静祥和的氛围,让人沉浸在其中,仿佛是一个旧的阶段的结束,同时也是一个新的阶段的开始.这么说来,西 ...
- linux内核分析作业8:理解进程调度时机跟踪分析进程调度与进程切换的过程
1. 实验目的 选择一个系统调用(13号系统调用time除外),系统调用列表,使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用 分析汇编代码调用系统调用的工作过程,特别是参数的传递的方 ...
- 一行python代码实现树结构
树结构是一种抽象数据类型,在计算机科学领域有着非常广泛的应用.一颗树可以简单的表示为根, 左子树, 右子树. 而左子树和右子树又可以有自己的子树.这似乎是一种比较复杂的数据结构,那么真的能像我们在标题 ...
- Linux C 中 fork() 函数详解
一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork() 函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同 ...
- [Linux]系统调用理解(2)
本文介绍了Linux下的进程概念,并着重讲解了与Linux进程管理相关的4个重要系统调用getpid,fork,exit和_exit,辅助一些例程说明了它们的特点和使用方法. 关于进程的一些必要知识 ...
- dmidecode常用参数
dmidecode常用参数详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. dmidecode这个命令真是神器啊,他能快速的获取服务器的硬件信息,而且这个命令有很多的花式玩法,今 ...
随机推荐
- How do you install Google Chrome on Ubuntu?
https://askubuntu.com/questions/510056/how-to-install-google-chrome sudo apt-get install chromium-br ...
- Android代码宏控制方案 【转】
本文转载自:http://blog.sina.com.cn/s/blog_769500f001017ro6.html 目前107分支上,在各项目projectConfig.mk中已添加项目宏以及客户宏 ...
- python 数据的基本类型(字符串)
python 基础 ascii:字母,数字,特殊字符:1个字节(byte) 8个字位(bit)unicode: 16位两个字节,升级32个字节 4个字位utf-8:最少一个字节 8个表示. 英文 8字 ...
- 线上出bug了?别怕,这么定位!
摘要: Source Map还是很神奇的. 原文:线上出bug了?别怕,这么定位! 公众号:前端小苑 Fundebug经授权转载并修改,版权归原作者所有. 工作中,生产环境代码是编译后代码,搜集到报错 ...
- C++中值传递(pass-by-value)和引用传递(pass-by-reference)
1.pass-by-value的情况: 缺省情况C++以pass-by-value(继承C的方式)传递对象至(或来自)函数.函数参数都是以实际参数的复件为初值,调用端所获得的也是函数返回值的一个复件, ...
- golang互斥锁和读写锁
一.互斥锁 互斥锁是传统的并发程序对共享资源进行访问控制的主要手段.它由标准库代码包sync中的Mutex结构体类型代表.sync.Mutex类型(确切地说,是*sync.Mutex类型)只有两个公开 ...
- NOIP2014 day2 t2 寻找道路
寻找道路 NOIP2014 day2 t2 描述 在有向图 G 中,每条边的长度均为 1,现给定起点和终点,请你在图中找一条从起点到 终点的路径,该路径满足以下条件: 1.路径上的所有点的出边所指向的 ...
- idea的环境变量设置(Enviroment variables)
- window下安装svn
下载 http://subversion.apache.org/ 注意:上边的黑窗口不要关闭! 如何校验svn服务有运行
- VS2015启动显示ID为XXXX的进程当前未运行
解决办法:在启动项目根目录下用文本编辑器打开Web项目下的{X}.csproj文件,然后查找 <WebProjectProperties>,将这一对标签之间的内容全部删除,然后再打开项目就 ...