| 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx
mkk93qit
8年前发布

Android工程gradle详解

   <h2>版本的统一管理</h2>    <p>当我们的工程中有许多module的时候,分开管理编译版本,minsdk将会是一件很麻烦的事,因为一个library的改动,可能会影响到其他module。这时我们就需要对所有的版本进行统一的管理,管理的方式有两种:</p>    <h2>rootProject</h2>    <p>我们可以把一些需要用的字段都放在project的build.gradle(注意是project的不是module的)中:</p>    <pre>  <code class="language-groovy">ext {      compileSdk = 21      minSdk = 11      targetSdk = 23      support = "23.1.1"     buildTools = "21.0.1"      buildstyle ="debug"  }</code></pre>    <p>这样,在module的build.gradle中可以进行读取:</p>    <pre>  <code class="language-groovy">defaultConfig {      applicationId "android.com.testgradle"      minSdkVersion rootProject.ext.minSdk      targetSdkVersion rootProject.ext.targetSdk      versionCode 1      versionName "1.0"  }</code></pre>    <h2>gradle.properties</h2>    <p>找到工程目录下的gradle.properties文件,如果没有也可以自己创建:</p>    <pre>  <code class="language-groovy">ANDROID_COMPLILE_SDK_VERSION=21  ANDROID_BUILD_SDK_VERSION=21.0.1  ANDROID_TEXT=test</code></pre>    <p>然后在各个module的build.gradle中可以引用:</p>    <pre>  <code class="language-groovy">compileSdkVersion ANDROID_COMPLILE_SDK_VERSION as int  buildToolsVersion ANDROID_BUILD_SDK_VERSION</code></pre>    <p>需要注意的是在gradle.properties中声明的格式都是string类型,如果如要转化成int类型,可以用as int 进行强制转化。</p>    <h2>程序中对buildTypes的区分</h2>    <h2>buildTypes是对不同build类型的处理</h2>    <p>当你点击运行按钮的时候会根据build Variant进行对应的方式编译。</p>    <p>build Variant可以在这里进行选择:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/2ed3778991854194c8ec5b682c8414f8.png"></p>    <h2>library的buildTypes</h2>    <p>默认情况下被依赖工程会使用release模式,与上层依赖的app工程选择的模式无关</p>    <p>需要在build.gradle中进行设置:</p>    <pre>  <code class="language-groovy">defaultPublishConfig "debug"</code></pre>    <h2>新增buildTypes</h2>    <p>你可以在buildTypes,根据需要新增一个类型,如下代码所示:</p>    <pre>  <code class="language-groovy">buildTypes {      debug {          buildConfigField("String","TEXT","\"这个字符串来自debug模式\"")          minifyEnabled false          proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'      }      stag {          buildConfigField("String","TEXT","\"这个字符串来自test模式\"")          minifyEnabled false          signingConfig signingConfigs.debug         proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'      }      release {         buildConfigField("String","TEXT","\"这个字符串来自release模式\"")          minifyEnabled false          signingConfig signingConfigs.debug          proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'      }  }</code></pre>    <h2>不同模式字符不同</h2>    <p>根据上面的代码,在不同的buildTypes中,TEXT这个变量是不一样的,而且根据代码可以看出,这个变量是一个String类型,那么我们在程序文件中可以这样通过BuildConfig引用:</p>    <pre>  <code class="language-groovy">t2.setText(BuildConfig.TEXT);</code></pre>    <h2>Variant</h2>    <p>gradle插件允许最终生成的包以多个维度进行组合</p>    <p>例如我们可以设定一下几个维度:</p>    <pre>  <code class="language-groovy">productFlavors {      red {          applicationId 'android.com.red'       versionCode 1  minSdkVersion 21  targetSdkVersion 22  }      blue {          applicationId 'android.com.blue'      }      yellow {          applicationId 'android.com.yellow'      }      }</code></pre>    <p>每个维度中可以设置这个版本的最小sdk限制,以及targetsdkversion</p>    <p>假设我们设置的维度有red blue yellow但是结合之前讲过的buildType(假设只有debug和release)</p>    <p>那么将会出现以下构建:</p>    <p>blueDebug和blueRelease</p>    <p>yellowDebug和yellowRelease</p>    <p>redDebug和redRelease</p>    <p>Gradle会为每一个Variant创建一个任务</p>    <p>对应如下:</p>    <p>gradle assembleBlue 会生成debug和release两个版本</p>    <p>gradle assembleDebug 会生成blue yellow red三个版本</p>    <p>gradle assembleBlueDebug 会生成bluedebug一个版本</p>    <p>这里还有一个用处需要提一下:</p>    <p>Gradle在打包android应用之前会将所有的代码,资源文件,包括manifest进行结合,当然library也会提供额外的资源,这些也会进行合并。</p>    <h2>字符串读取</h2>    <p>如果我们在创建一些设置时,需要动态的去更改内容,可以设置一个变量,然后从本地文件或者打包的命令行读取,我们这里就拿上面提到过的BuildConfig做例子,希望程序中引用的字符串是从本地读取的或从命令行读取的</p>    <h2>从本地文件中读取</h2>    <p>首先需要在最开始的地方设置一个变量aaa:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/5b546e66de7fb0b536397e1f12335237.png"></p>    <p>然后在buildTypes的debug模式中修改对应的代码:</p>    <pre>  <code class="language-groovy">debug {      buildConfigField("String","TEXT","\""+aaa+"\"")      minifyEnabled false      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  }</code></pre>    <p>然后在工程目录下创建一个本地文件test.properties,并添加内容:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/f6c40b6caf9c63aaf82097a5eb9a1aa0.png"></p>    <p>然后回到你刚才定义字符串的build.gradle中,添加:</p>    <pre>  <code class="language-groovy">if(rootProject.file('test.properties').exists()){    java.util.Properties properties = new Properties()     properties.load(rootProject.file('test.properties').newDataInputStream())     aaa = properties.getProperty('debug.text')      println("!!!!!"+aaa)  }else {      aaa = "文件没找到"  }</code></pre>    <p>即可读取到你本地文件的字符串</p>    <h2>从命令行读取</h2>    <p>如果是从命令行读入就更加简单,只需要将上面读取文件的代码改为:</p>    <pre>  <code class="language-groovy">aaa = new String(System.console().readLine("请输入字符串:"))</code></pre>    <h2>编译命令</h2>    <p>首先想看一个工程包含了多少task,需要切到这个工程目录下:</p>    <pre>  <code class="language-groovy">gradle tasks</code></pre>    <p>会列出所有的tasks:</p>    <p><img src="https://simg.open-open.com/show/181df86ca5556de6a01b2b3ff89360bc.png"></p>    <p>当然篇幅有限,这里不贴出所有的任务了,我们只需要知道编译命令即可,如图可以看到,如果想编译debug版本,使用:</p>    <pre>  <code class="language-groovy">assembleDebug</code></pre>    <p>其它同理即可。</p>    <p>如果使用build则回编译出所有的版本</p>    <h2>冲突问题</h2>    <p><img src="https://simg.open-open.com/show/8f6296f45b25dedf48417c610c6fb7a4.png"></p>    <p>在执行打包的时候很有可能会出现如上问题,这是由于依赖的jar冲突问题,我们可以分析一下工程结构。</p>    <p>我现在的结构是:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/f49105b6cba5786526581ea42e158747.png"></p>    <p>现在调整一下结构:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/aee09578520cb6345ba6f60236f21b1c.png"></p>    <p>把jar以module的形式提供就不会出现冲突。</p>    <h2>编译流程</h2>    <p style="text-align:center"><img src="https://simg.open-open.com/show/de188aa312504cb946034b4a25e2dcd2.png"></p>    <p style="text-align:center"> </p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/35ef3229e9393bfe12d423839fcdc181.png"></p>    <p style="text-align:center"> </p>    <h2>Task任务</h2>    <h2>执行顺序</h2>    <p>例如我们新建一个任务:</p>    <pre>  <code class="language-groovy">task umengtest{      println("aaaaaaaaa")      println("bbbbbb")  }</code></pre>    <p>他的执行如下:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/215352d1d98b62c7b581b5dfe2a73c1f.png"></p>    <p>它并不是在执行任务的时候执行的,而是在执行任务之前就打印了。</p>    <p>这是由于gradle构建有三个阶段:</p>    <p>初始化阶段,配置阶段,执行阶段。</p>    <p>上面的例子实际是打印在了配置阶段,换句话说,你不执行这个任务,执行这个工程别的任务也会打印。</p>    <p>例如我再写一个任务:</p>    <pre>  <code class="language-groovy">task umengtestaa<<{      println("ccc")      println("dddd")  }</code></pre>    <p>这次执行这个任务:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/13babfbc0e77a8be837fe564c5d391e5.png"></p>    <p style="text-align:center">你会发现也打印aaaa这说明这不是在真正的执行阶段执行的,为了保证任务的可控性,可以像上面umengtestaa那样写加一个<<符号</p>    <p>这样就可以保证了任务的可控性:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/1aea2da9798bba45268f87789a7f8479.png"></p>    <p>或者使用:</p>    <pre>  <code class="language-groovy">task umengtest{      doLast{          println("aaaaaaaaa")          println("bbbbbb")      }  }</code></pre>    <h2>打包任务</h2>    <p>有了上面的基础,下面就可以说一下打包的任务了,根据我们之前的工程,我们有一个app的module和四个library module,我需要打印出一个apk和四个jar,明确了任务,现在可以开始实施了。</p>    <p>打开工程的build.gradle</p>    <pre>  <code class="language-groovy">def sdk = [          root : 'build/sdk/',  ]task dabao( type:Zip) {      dependsOn('cp_main')      def name = 'umeng_test'  ;      destinationDir = file('build')      archiveName = name + '.zip'      from('build/sdk') {          into( name )      }  }  task cp_main(type: Copy, dependsOn: ['app:assembleRelease'] ) {      destinationDir = file( sdk.root )      from('app/build/outputs/apk') {          include('app-release.apk')          rename ('app-release.apk','test.apk' )          into('.')      }      from('mylibrary1/build/intermediates/bundles/release') {          include('classes.jar')          rename ('classes.jar','library1.jar' )          into('.')      }      from('mylibrary2/build/intermediates/bundles/release') {          include('classes.jar')          rename ('classes.jar','library2.jar' )          into('.')      }      from('mylibrary3/build/intermediates/bundles/release') {          include('classes.jar')          rename ('classes.jar','library3.jar' )          into('.')      }      from('mylibrary4/build/intermediates/bundles/release') {          include('classes.jar')          rename ('classes.jar','library4.jar' )          into('.')    }  }</code></pre>    <p>这时,我们再去找一下工程的build文件夹下可以发现:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e7786cd2143478b617628a38bf969541.png"></p>    <h2>打包不同内容的module</h2>    <p>打包不同内容的module可以利用之前讲过的variant或这个buildtypes来控制,这里就不说了,不明白的,可以回头再去看一下结合上面的打包脚本没有什么难度,然而还有一种需求,不是某个变量或者包名的更改,而是两个版本中两个文件的不同,我们可以试一下修改variant的方式来实现,在app的build.gradle中:</p>    <pre>  <code class="language-groovy">productFlavors {            pay {                }          free {            }        }</code></pre>    <p>修改结构目录:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/c964b1765532894565bf6a50bd60372f.png"></p>    <p>这样编译出来就会有两个不同类型的apk了</p>    <h2>防止打包错误</h2>    <p>在这里已经说完了所有与打包相关的东西了,在最后仍然加这一个标题是交给大家如何防止项目开发者打包出错,或者上传包出错后定位问题。</p>    <p>方法就是在打包的时候,生成一个记录文件,在这个包中记录打包时间,和当前git的版本号:</p>    <pre>  <code class="language-groovy">def releaseTime() {      return new Date().format("yyyyMMddHHmmss", TimeZone.getTimeZone("GMT+8"))  }  def getGitVersion() {      return 'git rev-parse --short HEAD'.execute().text.trim()  }  task writefile( ){      File configFile = new File('config.xml');      if (!configFile.exists()){          configFile.createNewFile()      }      FileOutputStream out =new FileOutputStream(configFile)      def result ="编译时间:"+"${releaseTime()}\n"+"commitid:"+"${getGitVersion()}\n"    out.write(result.getBytes())      out.close();  }  task cp_config(type: Copy, dependsOn: ['writefile'] ) {      destinationDir = file( sdk.root )      duplicatesStrategy = 'exclude'      includeEmptyDirs = false      from('.') {          include('config.xml')          into('.')      }  }</code></pre>    <p> </p>    <p>来自:http://www.jianshu.com/p/3e66d36455f4</p>    <p> </p>    
 本文由用户 mkk93qit 自行上传分享,仅供网友学习交流。所有权归原作者,若您的权利被侵害,请联系管理员。
 转载本站原创文章,请注明出处,并保留原始链接、图片水印。
 本站是一个以用户分享为主的开源技术平台,欢迎各类分享!
 本文地址:https://www.open-open.com/lib/view/open1482827153584.html
Gradle 安卓开发 Android开发 移动开发