Gradle學(xué)習(xí)筆記

gradle學(xué)習(xí)筆記(一)

概念

Gradle本身是基于Groovy腳本語言進(jìn)行構(gòu)建的,并通過Domain Specific Language(DSL語言)進(jìn)行描述和控制構(gòu)建邏輯的。
參考的文檔:

  1. 官方文檔
  2. 中文翻譯文檔
  3. Gradle用戶指南
  4. Android Studio構(gòu)建指南
  5. Android Studio Gradle,插件使用指南
  6. Gradle DSL語言API

gradle初探

項目全局build.gradle

文件中最重要的就是buildscript的部分代碼。在buildscript中,Gradle制定了使用jcenter代碼倉庫,同事聲明了依賴的Android Gradle插件版本。
allprojects領(lǐng)域中,開發(fā)者可以為項目整體配置一些屬性。

Module build.gradle

Gradle使用的是DSL語言,它是針對某個領(lǐng)域所設(shè)計出來的特定的語言,因?yàn)橛辛祟I(lǐng)域的限制,要解決的問題就被劃定了范圍。因此要針對每個特定的領(lǐng)域進(jìn)行分析即可。

  • apply plugin 領(lǐng)域
    apply plugin 這塊領(lǐng)域描述了Gradle所引入的插件。
    apply plugin:'com.android.application'表示該module是一個Android Application。這個插件包含了Android項目相關(guān)的所有工具。

  • android 領(lǐng)域
    android{...}這塊領(lǐng)域描述了該Android module構(gòu)建過程中所用到的所有參數(shù)。默認(rèn)情況下,IDE自動創(chuàng)建了compileSdkVersion、buildToolsVersion這兩個參數(shù),分別對應(yīng)變異的SDK版本和ANDROID build tools版本。而在android領(lǐng)域內(nèi),系統(tǒng)還默認(rèn)創(chuàng)建了兩個領(lǐng)域---defaultConfig和buildTypes,這兩個領(lǐng)域。

  • dependencies 領(lǐng)域
    dependencies{...}這塊領(lǐng)域描述了該Android module構(gòu)建過程中所依賴的所有庫,庫可以是以jar的形式進(jìn)行以來,或者是使用Android推薦的aar形式進(jìn)行依賴。aar相對于jar具有不可比擬的優(yōu)勢,不僅配置以來更加簡單,而且可以將圖片的資源文件放入aar中供主項目依賴,幾乎等同于依賴源碼。

Gradle Task

  1. 查看工程有哪些Task:./gradlew task
  2. 各個Task的具體作用與各個Task之間的相互調(diào)用關(guān)系:./gradlew task -all
  3. assemble task用于組合項目的所有輸出,包含了assembleDebugassembleRelease兩個Task
  4. check task 用于執(zhí)行檢查任務(wù)
  5. build Task 類似一個組合指令,執(zhí)行了check和assemble的所有工作
  6. clean task 用于清理所有中間編譯結(jié)果,這個指令使用的非常廣泛。

Gradle進(jìn)階

構(gòu)建全局配置

  • 全局參數(shù)
    在項目根目錄下的build.gradle中,通過ext領(lǐng)域可以指定全局的配置信息,代碼如下所示:
ext{
    compileSdkVersion = 23
    buildToolsVersion = "23.0.2"
    minSdkVersion = 14
    targetSdkVersion = 23
    versionCode = 3
    versionName = "1.0.1"
}
  • 引用配置
    在配置好全局參數(shù)后,就可以在每個module中使用這些配置了,例如

compileSdkVersion rootProject.ext.compileSdkVersion

方法非常簡單,通過rootProject.ext可以引用所有的全局參數(shù)。
另外,開發(fā)者也可以把ext全局配置卸載allprojects領(lǐng)域中,這樣在每個module中就可以直接引用申明的變量了。

allprojects{
    repositores{
        jecnter()
    }
    ext {
        COMPILE_SDK_VERSION = 22
    }
}

這樣寫的好處是可以將配置進(jìn)行統(tǒng)一管理。但壞處是如果這樣寫的話,Gradle的版本更新通知檢查機(jī)制就無限了。大部分時候,這種寫法是利大于弊的。

構(gòu)建defaultConfig

defaultConfig{
    applicationId "com.xxx.xxx"
    minSdkVersion 14
    targetSdkVersion 23
    versionCode 1
    versionName "1.0"
}

這些設(shè)置替換了AndroidMainifest文件中的屬性。除此之外可以動態(tài)控制VersionName的生成。

defaultConfig{
    applicationId "com.xxx.xxx"
    minSdkVersion 14
    targetSdkVersion 23
    versionCode 1
    versionName getCustomVersionName()
}

def getCustomVersionName(){
    ...
}

構(gòu)建buildTypes

通過創(chuàng)建不同的構(gòu)建類型,從而生成不同類型的apk,可以幫助開發(fā)者完成很多事情。例如實(shí)現(xiàn)只有在debug類型下才開啟的功能,如調(diào)試、Log等功能,以及為不同構(gòu)建類型實(shí)現(xiàn)不同的參數(shù)配置,等等。

  • 構(gòu)建類型基礎(chǔ)
buildTypes{
    release{
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'),`proguard-rules.pro`
    }
}

除了系統(tǒng)默認(rèn)的構(gòu)建type--debug和release之外,gradle同樣支持自定義創(chuàng)建新的構(gòu)建類型。例如,在腳本中添加一個xys類型,同時設(shè)置該類型的applicationIdSuffix的參數(shù)為".xxx",代碼如下:

buildTypes{
    release{
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'),`proguard-rules.pro`
    }
    xxx{
        applicationIdSuffix ".xys"
    }
}

執(zhí)行./gradlew build之后再build目錄中多生成了一個app-xxx-unsigned.apk,這個就是自定義的新的buildType-xys類型。那么applicationIdSuffix參數(shù)的作用是什么呢?在Android系統(tǒng)中,系統(tǒng)是通過包名來區(qū)分應(yīng)用的。如果應(yīng)用的包名相同,那么就意味著這是一個應(yīng)用。因此在構(gòu)建類型的時候,可以指定applicationIdSuffix參數(shù)為默認(rèn)的包名增加一個后綴。例如前面例子中的”.xxx“,以此區(qū)分不同的構(gòu)建類型。類似的方式,還可以給debug版本增加”.debug“的后綴,給release版本增加".release"的后綴。

  • 構(gòu)建類型buildTypes的繼承
buildTypes{
    release{
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'),`proguard-rules.pro`
    }
    xxx.initWith(buildTypes.debug)
    xxx{
        applicationIdSuffix ".xxx"
    }
}

構(gòu)建signingConfigs

Android Apk使用簽名來保證App的合法性。android系統(tǒng)有一個默認(rèn)的debug簽名,debug包會默認(rèn)使用這個debug簽名進(jìn)行簽名。那么當(dāng)你需要給其他版本設(shè)置簽名的時候,就需要自己來配置signingConfigs領(lǐng)域

生成簽名

生成簽名有兩種:

  1. 命令
  2. android studio

生成的簽名文件是xxx.jks文件。對于企業(yè)項目來說,這個key通常是存放在打包服務(wù)器上的,那么在gradle腳本中,就需要通過具體的路徑來訪問。這一點(diǎn)與訪問各種配置文件的方式是一樣的。

  • 配置簽名
    生成了簽名文件后,就可以在build.gradle腳本的android領(lǐng)域中配置簽名的相關(guān)參數(shù)
signingConfigs{
    xxx{
        storeFile file("xxx_key.jsk")
        storePassword "12344567"
        keyAlias "xxx"
        keyPassword "1234567"
    }
}

配置的信息就是前面在創(chuàng)建簽名時填寫的信息。需要注意的是,簽名信息一定要包含在一個領(lǐng)域中,你可以給這個領(lǐng)域起一個名字,例如在這里的”xxx“(通常情況下,會使用debug,release這樣的簽名)。

  • 使用簽名
    配置好相關(guān)的簽名信息后,就可以在構(gòu)建類型的時候加入簽名的設(shè)置。這樣生成的apk就會包含簽名版和未簽名版兩種,完整的配置如下所示。
signingConfigs{
    xxx{
        storeFile file("xxx_key.jsk")
        storePassword "12344567"
        keyAlias "xxx"
        keyPassword "1234567"
    }
}

buildTypes{
    release{
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android.txt'),`proguard-rules.pro`
    }

    xxx{
        signingConfig signingConfigs.xxx
        applicationIdSuffix ".xxx"
    }
}

Anroid領(lǐng)域中的可選配置

在Android領(lǐng)域中,還有一些可選的配置。在具體的開發(fā)場景中,開發(fā)者可以根據(jù)自己的需要進(jìn)行配置。

  • compileOptions
    配置編譯的選項,類似于compileSdkVersion。不是設(shè)置Android SDK的選項,而是設(shè)置Java的編譯選項,通常可以在這里指定Java的編譯版本。
compileOptions{
    sourceCompatibility Java Version.VERSION_1_8
    targetCompatibility Java Version.VERSION_1_8
}

指定編譯版本,通常是為了使用某些版本中的一些語言新特性。

  • lintOptions

Lint代碼檢查,這個選項打開,在編譯的時候,會因?yàn)長int的error而終止。

構(gòu)建Proguard

Proguard配置是Android的apk混淆文件配置,但它的作用絕對不僅僅是混淆代碼。他同樣可以精簡代碼、資源,優(yōu)化代碼結(jié)構(gòu)。

buildTypes{
    release{
        minifyEnabled true
        proguardFiles getDefaultProguardFile('proguard-android.txt'),`proguard-rules.pro`
    }
    xxx{
        signingConfig signingConfigs.xxx
        applicationIdSuffix ".xxx"
    }
}

Gradle動態(tài)參數(shù)配置

Gradle既然是一種腳本配置語言,那么它一定可以通過配置文件動態(tài)配置其編譯腳本,列入前面在配置簽名腳本時,使用的代碼如下所示。

signingConfigs{
    xxx {
        storeFile file("xxx_key.jsk")
        storePassword "12344567"
        keyAlias "xxx"
        keyPassword "1234567"
    }
}

使用gradle.properties文件來配置腳本的動態(tài)參數(shù)。

System.properties方式

在gradle.properties文件中添加以下配置

systemProp.keyAliasPassword=1234567
systemProp.keyAlias=xxx
systemProp.keyStorePassword=1234567
systemProp.keyStore=xxx_key.jks

這些配置實(shí)際上就是之前寫死的配置參數(shù),只不過這里把它們配置到了systemProp中,那么在build.gradle腳本進(jìn)行引用的時候,就可以通過System.properties[KEY]獲取這些參數(shù)。

signingConfigs{
    xxx {
        storeFile file(System.properties['keyStore'])
        storePassword System.properties['keyStorePassword']
        keyAlias System.properties['xxx.keyAlias']
        keyPassword System.properties['xxx.keyAliasPassword']
    }
}

通過project.property(Key)方法,就可以去除對應(yīng)的Value。這種方式與使用System.properties的方式基本一樣。

多渠道打包

所謂多渠道打包,實(shí)際上就是在代碼層面上標(biāo)記不同的渠道名,從而便于統(tǒng)計不同的應(yīng)用市場該apk的下載量。而且有些時候有些暴還可以以從網(wǎng)頁的外鏈接或者一些非市場的渠道進(jìn)行下載。這些都需要進(jìn)行統(tǒng)計,因此多渠道打包,變成了打包任務(wù)的重中之重。
利用Gradle進(jìn)行多渠道打包,將開發(fā)者從之前繁雜的ant打包中解放出來。Gradle的強(qiáng)大功能,將多渠道打包變得異常簡單,只需要在Gradle腳本中進(jìn)行簡單配置,即可完成多渠道打包。

  • 創(chuàng)建渠道占位符
    首先AndroidMainifest文件的Application節(jié)點(diǎn)下,創(chuàng)建如下所示的meta-data節(jié)點(diǎn)
<meta-data
    android:name="PRODUCT"
    android:value="${CHANNEL_VALUE}"/>

其中”${CHANNEL_VALUE}“就是要進(jìn)行替換的渠道占位符。

  • 配置Gradle腳本
    在項目的Gradle腳本的android領(lǐng)域中,添加productFlavors領(lǐng)域,并添加定義的渠道名。同時,使用manifestPlaceholders指定要替換渠道占位符的值。
productFlavors{
    product1{
        manifestPlaceholders=[CHANNEL_VALUE:"PRODUCT1"]
    }
    product2{
        manifestPlaceholders=[CHANNEL_VALUE:"PRODUCT2"]
    }
    product3{
        manifestPlaceholders=[CHANNEL_VALUE:"PRODUCT3"]
    }
}

實(shí)際上除了渠道名,AndroidMainifest文件中的其他設(shè)置,同樣可以使用占位符進(jìn)行配置。只要利用manifestPlaceholders進(jìn)行替換即可,原理與多渠道類似。這一個技巧可以讓項目能夠直接在編譯腳本--build.gradle中進(jìn)行動態(tài)參數(shù)控制,便于統(tǒng)一管理。更進(jìn)一步,在Module中同樣可以進(jìn)行這些動態(tài)參數(shù)的控制。例如某些Module的封裝,需要配置一些炎癥Key作為參數(shù),如果這些Key卸載Module中,Module就是去了通用性。因此借助manifestPlaceholders,開發(fā)者可以將動態(tài)參數(shù)配置到Module中,通過主項目的manifestPlaceholders。可以參考博客

腳本優(yōu)化

productFlavors{
    product1{
        manifestPlaceholders=[CHANNEL_VALUE:"PRODUCT1"]
    }
    product2{
        manifestPlaceholders=[CHANNEL_VALUE:"PRODUCT2"]
    }
    product3{
        manifestPlaceholders=[CHANNEL_VALUE:"PRODUCT3"]
    }
}
productFlavors.all{flavor->
    flavor.manifestPlaceholders=[CHANNEL_VALUE:name]        
}

增加的productFlavors.all領(lǐng)域?qū)λ械膒roductFlavors進(jìn)行遍歷,并使用其name作為渠道名。這些name實(shí)際上就是produce1,Produce2,produce3

生成重命名包

在生成渠道包后,包的明明通常是默認(rèn)命名,即app-渠道名-buildType.apk。但是通常情況下,項目經(jīng)理都會要求對報名進(jìn)行重命名,以滿足市場部的需求。那么這時候就可以通過Gradle腳本進(jìn)行快速重命名,而不需要再使用rename指令或者Python指令或者Python腳本進(jìn)行修改

application Variants.all{variant ->
    variant.outputs.each{ output ->
        if(output.outputFile != null &&
                        output.outputFile.name.endsWith('.apk') &&
                        'release'.equals(variant.buildType.name)){
                            def apkFile = new File(output.outputFile.getParent(),
                                "XXXApp_${variant.flavorName}_ver${variant.versionName}.apk")
                            output.outputFile = apkFile
                        }
    }

}

將這段腳本放到android領(lǐng)域中即可,當(dāng)執(zhí)行g(shù)radle build指令時該task也會執(zhí)行,與多渠道優(yōu)化的那段代碼非常類似,它去除了所有的生成的apk包,并判斷其文件是否是apk、是否是release版本。如果是,則重新將其命名為”XXXApp_渠道名_ver版本號.apk“。代碼其實(shí)非常簡單,但難就難在對groovy語言的理解和gradle android插件的熟悉度上。很多系統(tǒng)變量和內(nèi)置變量。

為不同版本添加不同代碼

在開發(fā)中,不同的版本通常有不同的代碼功能。例如最常用的Log開關(guān),在debug版本中會打印開發(fā)日志,而在release版本中需要關(guān)閉的。因此,一般會有一個全局的變量開關(guān),根據(jù)不同的版本設(shè)置不同的值。這一切在gradle腳本的支持下,僅僅變成了一句配置。

buildTypes{
    rlease{
        buildConfigField "boolean","testFlag","true"
        minifyEnabled true
        shrinkResources ture
        proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro'
    }
    xxx{
        buildConfigFiles "boolean","testFlag","false"
        signingConfig signingConfigs.xxx
        applicationIdSuffix ".xxx"
    }
}

通過制定buildConfigField的三個參數(shù)--類型、名稱、值,就可以將一個變量設(shè)置到不同的buildType中去。打開系統(tǒng)的BuildConfig類,可以看到不同buildType下對應(yīng)的testFlag的值。該文件對應(yīng)的路徑為/項目/app/build/generated/source/buildConfig/(你也可以通過雙擊Shift進(jìn)行快速查找)
直接通過BuildConfig類,就可以獲取到不同buildType所對應(yīng)的值了。如果是String類型的變量,在寫入字符串的時候,需要加入轉(zhuǎn)義字符。

buildConfigField "String","myname","\"abs\""

除了Java代碼可以使用這種方式進(jìn)行添加之外,資源文件同樣可以進(jìn)行分版本設(shè)置屬性值。例如要給不同的版本設(shè)置不同的AppName

defaultConfig{
    ....
    resVaule("string","app_name","XXXApp")
}
buildTypes{
    release{
        ...
        resVaule("string","app_name","XXXAppRelease")
    }
    debug{
        ...
        resVaule("string","app_name","XXXAppDebug")
    }
}
defbuildTime(){
    return new Date().format("yyyy-MM-dd HH:mm:ss")
}
defaultConfig{
    resValue "String","build_time",buildTime()
}

在上面的代碼中,定義了一個buildTime方法,并賦值給自定義的build_time變量。這時候不需要在Java代碼中增加變量,即可直接引用已經(jīng)編譯到R文件中的變量build_time,代碼如下:

Log.d("test",getString(R.string.build_time))

Gradle多項目依賴

  • build.gradle:控制每個module的編譯過程。
  • gradle.properties:設(shè)置Gradle腳本中的參數(shù)。
  • local.properties:Gradle的SDK相關(guān)環(huán)境變量配置。
  • settings.gradle:配置Gradle的多項目管理。

使用Gradle上傳aar到Maven庫

開發(fā)者可以將自己開發(fā)的庫項目上傳到Maven庫,供其他程序調(diào)用。上傳的方式為通過腳本進(jìn)行提交

uploadArchives{
    repositories{
        mavenDeployer{
            pom.groupId = GROUPID
            pom.artifactId = ARTIFACTID
            if(System.properties['isRelease'].toBooleans()){
                pom.version = VERSION
                repository(url: nexusReleases){
                    authentication(userName:nexusUsername,password:nexusPassword)
                }
            }else{
                pom.version = "${VERSION}-SNAPSHOT"
                repository(url:nexusSnapshots){
                    authentication(userName:nexusUsername,password:nexusPassword)
                }
            }
            pom.project{
                descriptoin 'xxxx'
            }
        }
    }
}

同時,還需要在gradle.properties文件中進(jìn)行參數(shù)的配置

GROUP_ID = com.xxxx.cccc
ARTIFACT_ID = aaaa
VERSION = 1.x.xxx
RELEASE_REPOSITORY_URL = maven url
nexusUsername = username
nexusPassword = password
systemProp.isRelease = true

Gradle 依賴管理

  • 強(qiáng)制刷新配置
compile('com.xxx.xxx:3.0.1-SNAPSHOT@aar'){
    transitive = true
}

如果增加一個屬性transitive并讓其值為true,則代表會強(qiáng)制刷新遠(yuǎn)程庫,避免遠(yuǎn)程庫更新后本地未刷新的問題。

Gradle依賴傳遞

在使用Gradle aar文件時,京城會發(fā)生這樣的情況,主項目A依賴庫項目B,庫項目B依賴庫項目C和jar包D。這時候主項目在引用庫項目B時,寫成如下所示的方式。

compile 'com.xxx.xxxx:xxxx:1.0.0-SNAPSHOT'

這樣的寫法也是一般引用庫項目的標(biāo)準(zhǔn)寫法,其表示B項目及其依賴的所有項目,即C和D。那么如果C或者D出現(xiàn)重復(fù)依賴的問題,或者主項目只想依賴庫項目B而不像依賴庫項目B所以來的項目,則可以使用@aar關(guān)鍵字關(guān)閉依賴傳遞,使用方法如下所示。

compile 'com.xxx.xxxx:xxxx:1.0.0-SNAPSHOT@aar'

如果這樣引用庫項目B,則不會進(jìn)行依賴傳遞。但要注意的是,libs目錄下的jar文件時不受影響的,開發(fā)者在使用過程中需要非常注意。
另外,還可以使用exclude module排除一個庫中引用的其他庫,例如aar庫A依賴了B和C,此時可以通過以下的方式進(jìn)行依賴。

compile('com.xxx.yyy:aaa:1.1.1'){
    exclude module:'com.xxx.yyy.bbb:1.1.2'
}

傳遞依賴問題是使用Gradle時一定會遇到的問題,不僅僅是依賴傳遞的庫會沖突,而且也會發(fā)生資源沖突的問題。因此遇到Gradle編譯錯誤的時候,一定要仔細(xì)分析錯誤的原因,找到?jīng)_突的根本原因從而去解決問題

Gradle依賴統(tǒng)一管理

Gradle引用依賴非常簡單,但一旦涉及多module,每個module的依賴管理就變得非常麻煩。這就和編程中使用的變量一樣,每個module中都引用自己的依賴-局部變量,這樣就造成多個module有多個局部變量,不利于項目管理。因此,最好是使用類似全局變量的方式來進(jìn)行統(tǒng)一的管理。
在根目錄的build.gralde腳本中配置如下所示的代碼。

ext{
    android=[compileSdkVersion:23,
            buildToolsVersion:'23.0.2']

    dependencies = [supportv7:'com.android.support:appcompat-v7:23.2.0']
}

在全局Gradle腳本中,指定了android和dependencies兩個列表,并在其中配置了統(tǒng)一的參數(shù)和對應(yīng)的值。這樣在每個module中,一顆通過代碼使用全局的依賴配置。

android{
    compileSdkVersion rootProject.ext.android.compileSdkVersion
    buildToolsVersion rootProject.ext.android.buildToolsVersion
}
dependencies{
    compile rootProject.ext.dependencies.supportv7
}

更進(jìn)一步,開發(fā)者還可以把這些全局參數(shù)抽取出來,寫到一個單獨(dú)的配置文件中。例如,比這在項目根目錄下創(chuàng)建一個config.gradle文件,并寫入如下所示的代碼

ext{
    android = [compileSdkVersin:23,
                buildToolsVersion:'23.0.2']
    dependencies=[supportv7:'com:android.support:appcompat-v7:23.2.0']
}

這里就要把ext全局參數(shù)抽取出來了。下一步,在根目錄下的build.grdle文件中,使用代碼加載這個配置文件,代碼如下所示。

apply from:'config.gradle'

這樣就可以在所有的子module中使用這些參數(shù)了,通過這種統(tǒng)一的依賴管理方式,可以統(tǒng)一所有module的依賴配置,避免使用不同版本的依賴庫而導(dǎo)致的沖入,而且也利于項目的管理。

Gradle使用技巧

  • Debug模式禁用掉Lint./gradlew build -x lint,其中-x參數(shù)表示排除掉一個Task,即Lint。通過這種方式可以實(shí)現(xiàn)禁止Lint的執(zhí)行。
  • Debug模式禁用AAPTaaptOptions.cruncherEnabled = false
  • 官方文檔

Gradle加速

Gradle在編譯時會執(zhí)行大量的Task,同時生成很多中間文件。因此磁盤IO會造成編譯速度緩慢。解決該問題的最好辦法就是為電腦更換固態(tài)硬盤,增加磁盤的IO速度。同時盡量減少本地庫項目的依賴,多實(shí)用aar進(jìn)行依賴。
在gradle.properties文件中增加如下代碼

org.gradle.daemon=true
org.gradle.parallel=true
org.gradle.configureondemand=true

同時,在build.gradle中增加如下代碼

dexOptions{
    incremental true
        javaMaxHeapSize "4g"
}

gradle.properties文件中的代碼,表示開啟Gradle的多線程和多核心支持。而build.gradle中的代碼,表示開啟Gradle的增量編譯,增加編譯的內(nèi)存資源的4G。

Gradle自定義插件

Gradle提供了強(qiáng)大的插件自定義功能,可以在某些情況下通過自定義插件實(shí)現(xiàn)自己的一些功能。官方文檔

在Gradle中創(chuàng)建自定義插件,Gradle提供了以下三種方式。

  • 在build.gradle腳本中直接使用
  • 在buildSrc中使用
  • 在獨(dú)立Module中使用

Gradle插件可以在IDEA中進(jìn)行開發(fā),也開一在Android Studio中進(jìn)行研發(fā)。他們唯一不同就是IDEA提供了Gradle開發(fā)的插件,比較方便創(chuàng)建文件和目錄。而在Android studio中,開發(fā)者需要手動創(chuàng)建。

Gradle 打包配置

編譯時報重復(fù)文件的錯誤

// 1. pickFirsts:當(dāng)出現(xiàn)重復(fù)文件,會使用第一個匹配的文件打包進(jìn)入。
// 2. merges:當(dāng)出現(xiàn)重復(fù)文件,合并重復(fù)的文件打入APK,兩個文件會進(jìn)行拼接
// 3. excludes:打包的時候排除匹配的文件

packagingOptions {
    pickFirst 'lib/armeabi-v7a/libyuv.so'
    merge 'lib/armeabi-v7a/libyuv.so'
    exclude 'lib/armeabi-v7a/libyuv.so'
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,619評論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,155評論 3 425
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,635評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,539評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,255評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,646評論 1 326
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,655評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,838評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,399評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,146評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,338評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,893評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,565評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,983評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,257評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,059評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,296評論 2 376

推薦閱讀更多精彩內(nèi)容