您好,登錄后才能下訂單哦!
這篇文章主要介紹android中Gradle配置知識有哪些,文中介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們一定要看完!
Gradle 編譯過程
編譯流程圖
上圖展示了一個典型的 App 編譯過程,主要分為以幾步:
編譯器將源代碼(包括依賴庫)轉化為 DEX 文件,編譯資源文件(res 以及 assets 文件下的資源)。
APK Packager 整合所有的 DEX 文件和編譯過的資源文件,并且對 APK 進行簽名。
簽名文件必須使用 Debug 版或者 Release 版,使用 Debug Keystore 生成的 app 被用來測試和分析,使用 Release Keystore 生成的 app 可以進行發布供其他用戶使用。
在生成最終的 APK 之前,APK Packager 會使用 zipalign 工具優化整個 app ,以便 app 在使用的過程中更加節省內存。
自定義編譯配置
Android Studio 的 gradle 插件方便我們在以下幾個方面配置我們的編譯選項:
Build Types - 編譯類型
編譯類型,包括我們最熟悉的 release 和 debug 兩種類型,我們可以根據這兩種類型定義出更多的類型。配置對應的 build.gradle 文件在 moudle 下,需要添加新的或者修改 Build Type ,只需要在 android{ ... }里面操作。
一個示例如下:
android { ... defaultConfig {...} buildTypes { release { //開啟混淆 minifyEnabled true //混淆規則文件 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } debug { //apk的后綴 applicationIdSuffix ".debug" } //debug的一個擴展 jnidebug { // 復制debug的屬性和簽名配置 initWith debug applicationIdSuffix ".jnidebug" //開啟Jni調試 jniDebuggable true } } }
其中 initWith 可以方便我們繼承其他的配置,只需要添加需要的部分。
Product Flavors - 構建不同版本
配置 apk 的版本信息,可以為每一個版本指定不同的 applicationId 和版本名稱。關于 applicationId ,可以把它也理解為包名,不過和 Manifest 文件中的包名作用不同,它是用來給應用商店和設備區分不同的 app ,而 Manifest 中的 pakage 屬性用來在源代碼中引用 R 類和其他類。即同一份代碼 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" } } }
通過上面的配置之后,如果 buildTypes 里面配置了兩個編譯類型,假如是 debug 和 release ,將會產生四個 apk 文件,每一種 buildType 都會和每種 flavor 進行組合拼接,進而產生不同的變種版本(Build Variant),上面對應的四個不同的變種版本分別是:demoDebug、demoRelease、fullDebug、fullRelease。
Mutiple Manifest Files - 合并多個清單文件
配置多個 Manifest 文件。經常會在項目中依賴其他項目,這個時候就會有多個 Manifest 文件,那在編譯的時候該如何處理呢?這個時候需要進行合并,而且還必須有一套相應的合并規則解決和避免合并沖突。對于不同的 Manifest 文件中同一個屬性的不同值,在合并的時候還需要優先級來進行判斷,用高優先級的去覆蓋低優先級的。
關于優先級定義如下:
最高優先級:buildType 的設置
次高優先級:productFlavor 的設置
中等優先級:在 src/main 目錄下的 Manifest 文件
最低優先級:各種依賴和第三方庫的設置
合并規則:概括來說是這樣:
合并之前,先將每個 module 里面的 buildType 內容寫到 Manifest 里面去,比如你在 buildType 里面的 minSdkVersion 和targetSdkVersion 以及 versionCode 和 VersionName 等等(此時合并后的 Manifest 文件可以在 app/intermediates/manifests/* 目錄下查看)。
對于同一個屬性,當高優先級和低優先級都為非默認值時,如果可以匹配,那直接合并,不能匹配,就會產生沖突(這種是針對兩個不同的 module 來說),下面會專門給出例子。
不管高優先級還是低優先級,如果其中一個沒有設置該屬性或者設置為默認的屬性值,而另外一個設置了非默認的屬性值,則合并的結果就是非默認的屬性值,在項目編譯后,可以查看 Manifest 的合并記錄,該文件目錄為:app/intermediates/outputs/logs/manifest*.txt。
示例:現在給出一些例子說明上述規則,我的主 module 名為 app ,新建一個依賴的 module 叫 uisdk ,現在分別給出兩個 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)里設置的 minSdkVersion 為7,最終 app 的 Manifest 的 minSdkVersion 就為7,再看 uisdk 里面的 build.gradle ,minSdkVersion 為8,就是說 app 這個 module 和 uisdk 這個 module library 在同一個屬性上使用了不同的非默認值,而且 library 的 Manifest 屬于最低優先級,它設置的值又比優先級比它高的值還要高,就會出錯,出錯信息的描述也很清晰:
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
根據錯誤信息,我們有兩種方式解決這個問題:
把 app 里面的值調高,或者把 uisdk 里面的值調低。
就像上面建議的那樣,使用 overrideLibrary 這個標簽。該標簽的作用在名字上已經體現出來了,就是直接覆蓋 library 里面的設置,現在我們在 app/src/main/Manifest 里面加上這么一句:
<uses-sdk tools:overrideLibrary="com.example.uisdk"/>
就能編譯通過了,這適用于比較特殊的情況,就是在依賴庫里可能要適用一些新特性,這些特性在 app 的 minSdkVersion 下不能使用,而且 app 的 minSdkVersion 已經不能更改了。
標記選擇器(Marker Selectors) :選擇器的功能可以讓一些屬性在某些 libary 里面無效,比如就拿上面的例子來說,我想讓 uisdk 只處理 ui 上的東西,不想讓他具有網絡訪問的功能,那么我可以這么設置:
<uses-permission android:name="android.permission.INTERNET" tools:node="remove" tools:selector="com.example.uisdk" />
其中 tools:node 標簽表示刪除該權限,tools:selector 標簽選擇在哪個依賴庫里執行 tools:node 表示的動作。
可以看出這些配置還是挺靈活的。
Configure dependencies - 配置依賴
這個應該是最熟悉的了,項目中經常要依賴第三方庫,一個典型了例子如下:
android {...} ... dependencies { //將本地 module library 編譯到項目中 compile project(":mylibrary") //編譯遠程依賴 compile 'com.android.support:appcompat-v7:23.4.0' //編譯本地 jar 包 compile fileTree(dir: 'libs', include: ['*.jar']) }
上面主要用到的方式是 compile ,gradle 支持6種編譯方式:
compile:對所有 buildType 以及 flavors 進行編譯并打包到 apk 。
provided:和 compile 相似,但只在編譯時使用,幾只參與編譯,不打包到最終 apk 。
apk:只會打包到 apk 中,不參與編譯,所以不能在項目代碼中使用相應庫中的方法。
test compile:相比于 compile ,僅僅針對單元測試的代碼編譯打包。
debug compile:僅針對 debug 模式編譯打包。
release compile:僅針對 release 模式編譯打包。
另外在進行 sdk 開發時,一般為了減小 sdk 體積,一些依賴庫會用 provided 的方式,同時需要注意的是,對于遠程依賴,compile 和 provided 的效果一樣,都不會打包到 jar 包或者 arr 包中,但對于本地的 jar 包或者 arr 包的依賴,compile 和 provided 就有區別了。
Configure Sigining - 配置簽名
在用 gradle 配置 release 版本的簽名信息時,需要下面三個步驟:
生成一個 keystore ,一個二進制文件保存一些私鑰,這個必須好好保存。
生成一個私鑰,用于開發者或者公司與這個 app 建立對應關系。
將生成的信息配置到 moudle 層的 build.gradle 里。
示例如下:
android { ... defaultConfig {...} signingConfigs { release { storeFile file("myreleasekey.keystore") storePassword "password" keyAlias "MyReleaseKey" keyPassword "password" } } buildTypes { release { ... signingConfig signingConfigs.release } } }
上面的配置中直接顯示了一些敏感信息,比如各種密碼,一種更加安全的方式是通過環境變量的方式獲取:
storePassword System.getenv("KSTOREWD"); keyPassword System.getenv("KEYPWD");
或者如果使用命令行的方式編譯,還可以讓用戶在命令行輸入密碼:
storePassword System.console().readLine("\nKeystore password: ") keyPassword System.console().readLine("\nKey password: ")
以上是“android中Gradle配置知識有哪些”這篇文章的所有內容,感謝各位的閱讀!希望分享的內容對大家有幫助,更多相關知識,歡迎關注億速云行業資訊頻道!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。