国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Android > 正文

Gradle編譯打包Android apk詳細介紹

2019-12-12 04:22:48
字體:
來源:轉載
供稿:網友

Gradle編譯打包Android apk詳細介紹

理解Gradle構建過程,解讀Android Gradle插件的配置

閱讀本文一定是要使用過Gradle生成apk,文中不會講如何安裝運行Gradle,如有需要可先看文末的參考文章。

APK包是一個ZIP壓縮包,從Java源代碼、資源文件到生成這個APK,經過了編譯打包一系列特定的過程,SDK文檔(/docs/tools/building/index.html)中找到。而這一系列特定的過程,重復繁瑣,構建工具(build tool)就是來流程化這些過程,解放你的雙手。Ant作為apk早期的構建工具,構建過程顯得很直觀,像配置;Gradle可以方便地配置,但更像腳本,可以編程。

理解Gradle構建

1.簡單理解構建工具

從一個程序員的角度,你該如何編寫代碼來自動化你的apk生成過程呢?首先得知道你需要的SDK、NDK在什么位置,Android工程有幾個庫工程,它們的Java源代碼、資源文件分別有哪些?命令行的輸入參數肯定無法滿足需求,那自然而然想到配置文件。因此你的自動化工具就是解析這些配置文件,按照生成apk文件要求執行的程序。Gradle就是這樣的工具程序,配置文件就是你常見的settings.gradle,build.gradle,不過他還提供了更多的功能,如依賴管理,流程控制,還有插件機制來定制你的生成過程。

Gradle的編程語言是Groovy,其需要的配置文件支持Groovy。Groovy語言像Java一樣是基于JVM的,而且能夠很好的支持Java,因此可以用Java代碼編寫擴展插件,像普通編程一樣來寫配置文件,而不用像Ant一樣用xml來編寫配置邏輯。

2.Groovy

Groovy的語法,把自己的代碼縮略的看上去像腳本,本人也只是看了一點點文檔,列出我們常用的介紹一下:
首先Groovy是面向對象的動態語言
(1)語句的末尾可省略分號
(2)變量定義可以用def,也可以直接使用
(3)函數定義可以用def,也可以不用(有返回值聲明也可)

  函數可省略參數類型
  函數調用可省略括號

來看個例子:

println 'Hello'                   int power(int n) { 2**n }              println "2^6==${power(6)}" 

第一行輸出字符串Hello,第二行定義一個函數,第三行輸出函數調用值,雙引號中間的${}可被解析成表達式運行。

(4)List和Map類型

List實現就是Java的java.util.ArrayList,變量由[]包圍,用逗號分隔,比如

def heterogeneous = [1, "a", true] //其元素可以是任何對象 

Map的實現是java.util.LinkedHashMap,也是由[]包圍,用逗號分隔,其中的鍵值對是key:value形式,如:

def colors = [red: '#FF0000', green: '#00FF00', blue: '#0000FF']    assert colors['red'] == '#FF0000' //取值可以[key]或者.key的形式 assert colors.green == '#00FF00'  

(5)閉包(Closures)

閉包我的理解類似C里的函數指針,或者說函數對象,可以像函數一樣調用的對象
{ [closureParameters -> ] statements }
例子

def testClosure = {int arg1, String arg2 ->//def可省略,參數可省略,默認有it,當只有->表示沒有參數  println "arg2:${arg2}" //執行的代碼,返回值是最后一句,也可以用return }  調用: testClosure(1,'2') testClosure.call(1,'2') 

3.Gradle

接著說自動化工具,編程語言有了,那實現一系列特定過程生成apk,就看如何實現了。Gradle里有Project,表示一個待編譯打包處理的工程,可以生成apk,可以生成Jar,Project中可以包含多個Project;每個Project由很多的Task構成,可以理解為不同的過程;每個Task里又是有不同的Action,和一系列要執行的操作(或者說你寫的要執行的語句)。Project中的Task的執行順序,則是由其dependsOn來控制的。
Gradle執行時是以task為單位執行,在命令行中以gradle task來執行,這一過程的生命周期分為三個階段(官方使用手冊中也有詳細介紹The Build Lifecycle):

(1)初始化階段

判斷包含哪些工程,創建對應的Project實例,可以看到最新執行的是在settings.gradle中的語句

(2)配置階段

創建不同的Task(Task可以動態生成),并根據Task之間的dependsOn,確定Task的執行順序,或者禁用某些Task。此階段完成后,Task之間的依賴關系也就確定下來。

(3)執行階段

在配置完成后,按照依賴關系,按順序執行。

需要注意的是通常在Task中的語句,都是在配置階段執行的,而doFirst,doLast這類Action是在執行階段中的。因此會出現你的依賴關系中沒有的Task中語句也被執行了的問題

如下例子,打印出的task內容是不一樣的

task printTasksName {  tasks.all {//all是一個方法,參數可以是閉包,函數的元括號可以省略  println "show tasks in Configuration:${it.name}" //it是閉包的默認參數  }  doFirst {  tasks.all {  println "show tasks in Execution:${it.name}"  }  } } 

4.Gradle插件和Androd插件
在提供了基本的流程控制之后,接下來是具體的要做什么,構建什么。Gradle提供了針對語言的插件如java,groovy等負責編譯,集成插件如application,war等生成java可執行程序,web程序的WAR文件。Android根據APK生成的過程,編寫了自己的插件,其中也使用了java插件。

(1)自定義插件的插件名稱在resources/META-INF/gradle-plugins

在resources/META-INF/gradle-plugins目錄下有后綴為properties文件,該文件的命名就是你在build.gradle中使用插件的名字,里面聲明了該插件的實現類。在Android插件的源碼中可以看到android.properties和com.android.application.properties中兩個插件名稱,因此在build.gradle中,應用工程使用Android插件需要apply plugin: 'android'(已是deprecated)或者apply plugin: 'com.android.application'

(2)Android插件中application的實現類是AppPlugin,繼承自com.android.build.gradle.BasePlugin ,調用apply方法,相應的configureProject(),解析local.properties,獲得sdk位置,創建AndroidBuilder,應用JavaBasePlugin,而后createExtension() 關聯BuildType,ProductFlavor,SigningConfig,最后createTasks(),完成各個Task的創建

5.DSL(Domain Specific Language)

DSL我翻譯成領域專用語言,就是在這里預先規定好的規則,或者說是行話。在Gradle的DSL中一般常見的類型,一種是類型(Type)有Project、Task等,給他們定義了不同的操作和用法,一種是語句塊(build script block或configuration block)如build.gradle中常見的buildscript { },allprojects { }。Android中也定義了非常多語句塊,如buildTypes { },sourceSets { }。

Android Gradle插件配置

有了上述概念,再看android應用中的build.gradle,其實文中也只能講一些,但是更多的可以自己查看Android插件的DSL

apply plugin: 'com.android.application' // 使用Android插件,非庫工程,生成的是apk  dependencies {  compile 'com.android.support:multidex:1.0.1'  compile fileTree(dir: 'libs', include: '*.jar')  compile project(':庫工程1') // 代碼、資源包含在主程序apk中的  provided project(':庫工程1') // 只參與編譯,不輸出到目標apk中 }  // Android插件DSL中的AppExtension類型 android {  compileSdkVersion rootProject.ext.compileSdkVersion // 多工程時配置統一的屬性  buildToolsVersion rootProject.ext.buildToolsVersion   // lint檢查,避免lint檢測到不符合條件退出編譯  lintOptions {  abortOnError false  }   // gradle編譯會默認合并庫工程的manifest到主工程,如果主程序和庫工程的包名不一致會有問題  enforceUniquePackageName = false   // 所有的 product flavors繼承  defaultConfig {  applicationId "cn.arainfo"  minSdkVersion 14  targetSdkVersion 10 // multiDexEnabled true  dexOptions {  javaMaxHeapSize "2g"  jumboMode true  }   }   // 此處由于工程是從Eclipse導入,所有路徑都進行了聲明  sourceSets {  main {  manifest.srcFile 'AndroidManifest.xml'  java.srcDirs = ['src']  resources.srcDirs = ['src']  aidl.srcDirs = ['src']  renderscript.srcDirs = ['src']  res.srcDirs = ['res']  assets.srcDirs = ['assets']  }   debug.setRoot('build-types/debug')  release.setRoot('build-types/release')  }   // 編譯類型,指定release的proguard配置文件  buildTypes {  release {  minifyEnabled true  proguardFile 'proguard.flags'  }  } }     afterEvaluate {  println "afterEvaluate set project dependsOn..."  project(':主程序工程').tasks.getByName("assembleDebug").dependsOn ":子程序工程:assembleDebug"    if (project.hasProperty('TestRelease')) {  project(':主程序工程').tasks.getByName("assembleRelease").dependsOn ":子程序工程:assembleRelease"   } } 

說明幾處

(1)如在根目錄的build.gradle中聲明公用屬性

ext { compileSdkVersion = 21 buildToolsVersion = '25.0.0' isOnWindows = Os.isFamily(Os.FAMILY_WINDOWS)}

(2)buildTypes { },productFlavors{ },signingConfigs { }

上述三個語句塊,類型是NamedDomainObjectContainer<T>,其中T是BuildType ProductFlavor SigningConfig,而buildTypes { },productFlavors{ }中增加新的類型,會對應有新的Task生成,規則為assemble[flavor][buildType],因此當compileSdkVersion較低,又用了MultiDex時,還想用InstantRun,就可以創建一個新的buildType,只在測試時使用

(3)afterEvaluate語句塊

Android的Gradle插件版本在2.2.0時,Task的創建已經在afterEvaluate,因此,如果想繼續使用tasks.getByName("assembleDebug"),必須要將自己的語句寫到afterEvaluate { }語句塊中

總結:

越寫越心虛,零零碎碎的內容非常多,按照自己的理解貫穿下來,涵蓋了部分內容,基本可以理解build.gradle。但是語句塊如buildTypes { }和BuildType如何關聯起來(或者說如何解析出來并創建對象)的,并沒有很好的理解。
如果有時間可以好好看下《深入理解Android(一):Gradle詳解》,一般的問題,比如多渠道打包productFlavors怎么配置啊,自己通過查Android的DSL就能解決。

參考文檔:

1.Groovy官方文檔
2.Gradle用戶手冊
3.Gradle的DSL
4.Android插件的DSL
5.深入理解Android(一):Gradle詳解

感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 宁乡县| 潼关县| 武强县| 南涧| 休宁县| 新巴尔虎左旗| 庆城县| 怀远县| 卢氏县| 芦山县| 甘泉县| 西畴县| 钟山县| 铁岭县| 武川县| 南溪县| 葫芦岛市| 丹寨县| 凤阳县| 临朐县| 宾阳县| 高邑县| 淮南市| 桂平市| 赤壁市| 六枝特区| 安多县| 丰宁| 崇礼县| 永福县| 太湖县| 昌黎县| 连州市| 昌乐县| 城固县| 延安市| 牙克石市| 杭州市| 若羌县| 容城县| 阿巴嘎旗|