“替你”總結(jié)的Gradle配置

閱讀說(shuō)明

參考鏈接:https://developer.android.com/studio/build/index.html
本片文章的內(nèi)容全部參考自上面的鏈接,其中有些內(nèi)容是直接翻譯的,有些內(nèi)容是結(jié)合自己的經(jīng)驗(yàn)總結(jié)的,可能有理解錯(cuò)誤的地方治泥,非常希望大家能指正出來(lái)赐纱,在交流中進(jìn)步。

Gradle 編譯過(guò)程

編譯流程圖

上圖展示了一個(gè)典型的 App 編譯過(guò)程徘意,主要分為以幾步:

  1. 編譯器將源代碼(包括依賴(lài)庫(kù))轉(zhuǎn)化為 DEX 文件,編譯資源文件(res 以及 assets 文件下的資源)轩褐。
  2. APK Packager 整合所有的 DEX 文件和編譯過(guò)的資源文件椎咧,并且對(duì) APK 進(jìn)行簽名。
  3. 簽名文件必須使用 Debug 版或者 Release 版把介,使用 Debug Keystore 生成的 app 被用來(lái)測(cè)試和分析勤讽,使用 Release Keystore 生成的 app 可以進(jìn)行發(fā)布供其他用戶(hù)使用。
  4. 在生成最終的 APK 之前拗踢,APK Packager 會(huì)使用 zipalign 工具優(yōu)化整個(gè) app 脚牍,以便 app 在使用的過(guò)程中更加節(jié)省內(nèi)存巢墅。

自定義編譯配置

Android Studio 的 gradle 插件方便我們?cè)谝韵聨讉€(gè)方面配置我們的編譯選項(xiàng):

Build Types - 編譯類(lèi)型


編譯類(lèi)型,包括我們最熟悉的 release 和 debug 兩種類(lèi)型君纫,我們可以根據(jù)這兩種類(lèi)型定義出更多的類(lèi)型。配置對(duì)應(yīng)的 build.gradle 文件在 moudle 下蓄髓,需要添加新的或者修改 Build Type ,只需要在 android{ ... }里面操作会喝。一個(gè)示例如下:

android {
    ...
    defaultConfig {...}
    buildTypes {
        release {
            //開(kāi)啟混淆
            minifyEnabled true
            //混淆規(guī)則文件
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        debug {
            //apk的后綴
            applicationIdSuffix ".debug"
        }
        
        //debug的一個(gè)擴(kuò)展
        jnidebug {
            // 復(fù)制debug的屬性和簽名配置
            initWith debug
            applicationIdSuffix ".jnidebug"
            //開(kāi)啟Jni調(diào)試
            jniDebuggable true
        }
    }
}

其中 initWith 可以方便我們繼承其他的配置玩郊,只需要添加需要的部分枉阵。

Product Flavors - 構(gòu)建不同版本


配置 apk 的版本信息译红,可以為每一個(gè)版本指定不同的 applicationId 和版本名稱(chēng)。關(guān)于 applicationId 兴溜,可以把它也理解為包名临庇,不過(guò)和 Manifest 文件中的包名作用不同,它是用來(lái)給應(yīng)用商店和設(shè)備區(qū)分不同的 app 昵慌,而 Manifest 中的 pakage 屬性用來(lái)在源代碼中引用 R 類(lèi)和其他類(lèi)。即同一份代碼 applicationId 可以讓它變成不同的 app 淮蜈。示例配置如下:

android {
    ...
    defaultConfig {...}
    buildTypes {...}
    productFlavors {
        demo {
            applicationId "com.example.myapp.demo"
            versionName "1.0-demo"
        }
        full {
            applicationId "com.example.myapp.full"
            versionName "1.0-full"
        }
    }
}

通過(guò)上面的配置之后斋攀,如果 buildTypes 里面配置了兩個(gè)編譯類(lèi)型,假如是 debug 和 release 梧田,將會(huì)產(chǎn)生四個(gè) apk 文件淳蔼,每一種 buildType 都會(huì)和每種 flavor 進(jìn)行組合拼接,進(jìn)而產(chǎn)生不同的變種版本(Build Variant)裁眯,上面對(duì)應(yīng)的四個(gè)不同的變種版本分別是:demoDebug鹉梨、demoRelease、fullDebug穿稳、fullRelease存皂。

Mutiple Manifest Files - 合并多個(gè)清單文件


配置多個(gè) Manifest 文件。經(jīng)常會(huì)在項(xiàng)目中依賴(lài)其他項(xiàng)目逢艘,這個(gè)時(shí)候就會(huì)有多個(gè) Manifest 文件旦袋,那在編譯的時(shí)候該如何處理呢?這個(gè)時(shí)候需要進(jìn)行合并它改,而且還必須有一套相應(yīng)的合并規(guī)則解決和避免合并沖突疤孕。對(duì)于不同的 Manifest 文件中同一個(gè)屬性的不同值,在合并的時(shí)候還需要優(yōu)先級(jí)來(lái)進(jìn)行判斷央拖,用高優(yōu)先級(jí)的去覆蓋低優(yōu)先級(jí)的祭阀。關(guān)于優(yōu)先級(jí)定義如下:

  • 最高優(yōu)先級(jí):buildType 的設(shè)置
  • 次高優(yōu)先級(jí):productFlavor 的設(shè)置
  • 中等優(yōu)先級(jí):在 src/main 目錄下的 Manifest 文件
  • 最低優(yōu)先級(jí):各種依賴(lài)和第三方庫(kù)的設(shè)置

合并規(guī)則:概括來(lái)說(shuō)是這樣:

  1. 合并之前,先將每個(gè) module 里面的 buildType 內(nèi)容寫(xiě)到 Manifest 里面去鲜戒,比如你在 buildType 里面的 minSdkVersion 和targetSdkVersion 以及 versionCode 和 VersionName 等等(此時(shí)合并后的 Manifest 文件可以在 app/intermediates/manifests/* 目錄下查看)专控。
  2. 對(duì)于同一個(gè)屬性,當(dāng)高優(yōu)先級(jí)和低優(yōu)先級(jí)都為非默認(rèn)值時(shí)袍啡,如果可以匹配踩官,那直接合并,不能匹配境输,就會(huì)產(chǎn)生沖突(這種是針對(duì)兩個(gè)不同的 module 來(lái)說(shuō))蔗牡,下面會(huì)專(zhuān)門(mén)給出例子颖系。
  3. 不管高優(yōu)先級(jí)還是低優(yōu)先級(jí),如果其中一個(gè)沒(méi)有設(shè)置該屬性或者設(shè)置為默認(rèn)的屬性值嘁扼,而另外一個(gè)設(shè)置了非默認(rèn)的屬性值黔攒,則合并的結(jié)果就是非默認(rèn)的屬性值,在項(xiàng)目編譯后不傅,可以查看 Manifest 的合并記錄访娶,該文件目錄為:app/intermediates/outputs/logs/manifest*.txt觉阅。

示例:現(xiàn)在給出一些例子說(shuō)明上述規(guī)則,我的主 module 名為 app 劫哼,新建一個(gè)依賴(lài)的 module 叫 uisdk 权烧,現(xiàn)在分別給出兩個(gè) module 的 build.gradle 文件:
app/build.gradle

apply plugin: 'com.android.application'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.0"

    defaultConfig {
        applicationId "com.example.rth.study"
        minSdkVersion 15
        targetSdkVersion 24
        versionCode 1
        versionName "1.0"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    productFlavors {
        demo {
            minSdkVersion 7
            applicationId "com.rth.app"
        }
    }
}

dependencies {
    compile fileTree(include: ['*.jar'], dir: 'libs')
    testCompile 'junit:junit:4.12'
    compile 'com.android.support:appcompat-v7:24.0.0'
    compile project(':uisdk')
}

uisdk/build.gradle

apply plugin: 'com.android.library'

android {
    compileSdkVersion 24
    buildToolsVersion "24.0.0"

    defaultConfig {
        minSdkVersion 8
        targetSdkVersion 24
        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:24.0.0'
}

在 app/build.gradle 里面豪嚎,defaultConfig 的 minSdkVersion 為15侈询,但我在變種版本(productFlavors 里的 demo)里設(shè)置的 minSdkVersion 為7糯耍,最終 app 的 Manifest 的 minSdkVersion 就為7,再看 uisdk 里面的 build.gradle 革为,minSdkVersion 為8震檩,就是說(shuō) app 這個(gè) module 和 uisdk 這個(gè) module library 在同一個(gè)屬性上使用了不同的非默認(rèn)值,而且 library 的 Manifest 屬于最低優(yōu)先級(jí)博其,它設(shè)置的值又比優(yōu)先級(jí)比它高的值還要高迂猴,就會(huì)出錯(cuò),出錯(cuò)信息的描述也很清晰:

Error:Execution failed for task ':app:processDemoDebugManifest'.
Manifest merger failed : uses-sdk:minSdkVersion 7 cannot be smaller than version 8 declared in library 
...
Suggestion: use tools:overrideLibrary="com.example.uisdk" to force usage

根據(jù)錯(cuò)誤信息峰髓,我們有兩種方式解決這個(gè)問(wèn)題:

  1. 把 app 里面的值調(diào)高携兵,或者把 uisdk 里面的值調(diào)低搂誉。
  2. 就像上面建議的那樣,使用 overrideLibrary 這個(gè)標(biāo)簽。該標(biāo)簽的作用在名字上已經(jīng)體現(xiàn)出來(lái)了凛虽,就是直接覆蓋 library 里面的設(shè)置广恢,現(xiàn)在我們?cè)?app/src/main/Manifest 里面加上這么一句:
<uses-sdk tools:overrideLibrary="com.example.uisdk"/>

就能編譯通過(guò)了,這適用于比較特殊的情況至非,就是在依賴(lài)庫(kù)里可能要適用一些新特性荒椭,這些特性在 app 的 minSdkVersion 下不能使用舰蟆,而且 app 的 minSdkVersion 已經(jīng)不能更改了。

標(biāo)記選擇器(Marker Selectors) :選擇器的功能可以讓一些屬性在某些 libary 里面無(wú)效味悄,比如就拿上面的例子來(lái)說(shuō)塌鸯,我想讓 uisdk 只處理 ui 上的東西丙猬,不想讓他具有網(wǎng)絡(luò)訪(fǎng)問(wèn)的功能费韭,那么我可以這么設(shè)置:

<uses-permission android:name="android.permission.INTERNET"
    tools:node="remove"
    tools:selector="com.example.uisdk"
    />

其中 tools:node 標(biāo)簽表示刪除該權(quán)限揽思,tools:selector 標(biāo)簽選擇在哪個(gè)依賴(lài)庫(kù)里執(zhí)行 tools:node 表示的動(dòng)作钉汗。

可以看出這些配置還是挺靈活的鲤屡。

Configure dependencies - 配置依賴(lài)


這個(gè)應(yīng)該是最熟悉的了,項(xiàng)目中經(jīng)常要依賴(lài)第三方庫(kù)卢未,一個(gè)典型了例子如下:


android {...}
...
dependencies {
    //將本地 module library 編譯到項(xiàng)目中
    compile project(":mylibrary")
    //編譯遠(yuǎn)程依賴(lài)
    compile 'com.android.support:appcompat-v7:23.4.0'
    //編譯本地 jar 包
    compile fileTree(dir: 'libs', include: ['*.jar'])
}

上面主要用到的方式是 compile 辽社,gradle 支持6種編譯方式:

  • compile:對(duì)所有 buildType 以及 flavors 進(jìn)行編譯并打包到 apk 翘鸭。
  • provided:和 compile 相似,但只在編譯時(shí)使用汉匙,幾只參與編譯生蚁,不打包到最終 apk 邦投。
  • apk:只會(huì)打包到 apk 中,不參與編譯见芹,所以不能在項(xiàng)目代碼中使用相應(yīng)庫(kù)中的方法蠢涝。
  • test compile:相比于 compile ,僅僅針對(duì)單元測(cè)試的代碼編譯打包和二。
  • debug compile:僅針對(duì) debug 模式編譯打包。
  • release compile:僅針對(duì) release 模式編譯打包怕午。

另外在進(jìn)行 sdk 開(kāi)發(fā)時(shí)淹魄,一般為了減小 sdk 體積,一些依賴(lài)庫(kù)會(huì)用 provided 的方式兆蕉,同時(shí)需要注意的是虎韵,對(duì)于遠(yuǎn)程依賴(lài)缸废,compile 和 provided 的效果一樣,都不會(huì)打包到 jar 包或者 arr 包中测萎,但對(duì)于本地的 jar 包或者 arr 包的依賴(lài)届巩,compile 和 provided 就有區(qū)別了。

Configure Sigining - 配置簽名


在用 gradle 配置 release 版本的簽名信息時(shí),需要下面三個(gè)步驟:

  1. 生成一個(gè) keystore 拇勃,一個(gè)二進(jìn)制文件保存一些私鑰孝凌,這個(gè)必須好好保存。
  2. 生成一個(gè)私鑰瓣赂,用于開(kāi)發(fā)者或者公司與這個(gè) app 建立對(duì)應(yīng)關(guān)系片拍。
  3. 將生成的信息配置到 moudle 層的 build.gradle 里捌省。
    示例如下:
android {
    ...
    defaultConfig {...}
    signingConfigs {
        release {
            storeFile file("myreleasekey.keystore")
            storePassword "password"
            keyAlias "MyReleaseKey"
            keyPassword "password"
        }
    }
    buildTypes {
        release {
            ...
            signingConfig signingConfigs.release
        }
    }
}

上面的配置中直接顯示了一些敏感信息,比如各種密碼卷拘,一種更加安全的方式是通過(guò)環(huán)境變量的方式獲壤醯堋:

storePassword System.getenv("KSTOREWD");
keyPassword System.getenv("KEYPWD");

或者如果使用命令行的方式編譯,還可以讓用戶(hù)在命令行輸入密碼:

storePassword System.console().readLine("\nKeystore password: ")
keyPassword System.console().readLine("\nKey password: ")

暫時(shí)就總結(jié)到這么多了瓣蛀,再次說(shuō)明耿焊,如果發(fā)現(xiàn)理解錯(cuò)的地方歡迎指正!F饕浮纫塌!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末措左,一起剝皮案震驚了整個(gè)濱河市避除,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凉逛,老刑警劉巖群井,帶你破解...
    沈念sama閱讀 219,539評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件书斜,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡焙糟,警方通過(guò)查閱死者的電腦和手機(jī)析显,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)枪向,“玉大人咧党,你說(shuō)我怎么就攤上這事∩钤保” “怎么了蛙埂?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,871評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵绣的,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我芭概,道長(zhǎng)惩嘉,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,963評(píng)論 1 295
  • 正文 為了忘掉前任惹苗,我火速辦了婚禮桩蓉,結(jié)果婚禮上抓艳,老公的妹妹穿的比我還像新娘帚戳。我一直安慰自己片任,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布位他。 她就那樣靜靜地躺著,像睡著了一般鹅髓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窿冯,一...
    開(kāi)封第一講書(shū)人閱讀 51,763評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音执桌,去河邊找鬼。 笑死芜赌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缠沈。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼博烂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了禽篱?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤躺率,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后悼吱,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡后添,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了馅精。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洲敢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出压彭,到底是詐尸還是另有隱情睦优,我是刑警寧澤壮不,帶...
    沈念sama閱讀 35,823評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站询一,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏家凯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評(píng)論 3 331
  • 文/蒙蒙 一绊诲、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧抗俄,春花似錦世舰、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,026評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至钾虐,卻和暖如春笋庄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背直砂。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,150評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工哆键, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘦锹,地道東北人闪盔。 一個(gè)月前我還...
    沈念sama閱讀 48,415評(píng)論 3 373
  • 正文 我出身青樓辱士,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親异赫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子头岔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評(píng)論 2 355

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

  • 1.介紹 如果你正在查閱build.gradle文件的所有可選項(xiàng)靠抑,請(qǐng)點(diǎn)擊這里進(jìn)行查閱:DSL參考 1.1新構(gòu)建系統(tǒng)...
    Chuckiefan閱讀 12,138評(píng)論 8 72
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理适掰,服務(wù)發(fā)現(xiàn),斷路器载城,智...
    卡卡羅2017閱讀 134,672評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,190評(píng)論 25 707
  • 轉(zhuǎn)載注明出處:http://www.reibang.com/p/5255b100930e 0. 前言 完全由個(gè)人翻...
    王三的貓阿德閱讀 2,520評(píng)論 0 4
  • 記憶中的父親用“吝嗇”“懶”形容不為過(guò)诉瓦,在上小學(xué)的年代垦搬,我問(wèn)父親要一毛錢(qián)買(mǎi)8分錢(qián)的寫(xiě)字薄艳汽,剩下的2分錢(qián)必須上交,我...
    綠洲家園閱讀 202評(píng)論 0 3