Gradle是一種依賴管理工具,基於Groovy語言,面向Java應用爲主,它拋棄了基於XML的各類繁瑣配置,取而代之的是一種基於Groovy的領域特定(DSL)語言。Android Studio中新建項目成功後自動下載Gradle。 Gradle有幾個基本組件:html
1.整個項目的gradle配置文件build.gradlejava
// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { jcenter() } dependencies { classpath 'com.android.tools.build:gradle:1.5.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } } allprojects { repositories { jcenter() } } task clean(type: Delete) { delete rootProject.buildDir }
內容主要包含了兩個方面:一個是聲明倉庫的源,我這裏用的是mavenCentral(), jcenter能夠理解成是一個新的中央遠程倉庫,兼容maven中心倉庫,並且性能更優。另外一個是聲明瞭android gradle plugin的版本,android studio 1.5.0正式版必需要求支持gradle plugin 1.5.0的版本。android
2.app文件夾下這個Module的gradle配置文件,也能夠算是整個項目最主要的gradle配置文件算法
apply plugin: 'com.android.application' buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:1.5.0' } } android { compileSdkVersion 23 buildToolsVersion "23.0.1" defaultConfig { applicationId "com.lippi.recorder" minSdkVersion 15 targetSdkVersion 17 versionCode 1 versionName '1.4' // dex突破65535的限制 multiDexEnabled true // AndroidManifest.xml 裏面UMENG_CHANNEL的value爲 ${UMENG_CHANNEL_VALUE} manifestPlaceholders = [UMENG_CHANNEL_VALUE: "channel_name"] } sourceSets { main { manifest.srcFile 'src/main/AndroidManifest.xml' java.srcDirs = ['src/main/java'] resources.srcDirs = ['src/main/resources'] aidl.srcDirs = ['src/main/aidl'] renderscript.srcDirs = ['src/maom'] res.srcDirs = ['src/main/res'] assets.srcDirs = ['src/main/assets'] jniLibs.srcDir 'src/main/jniLibs' } // Move the tests to tests/java, tests/res, etc... instrumentTest.setRoot('tests') // Move the build types to build-types/<type> // For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ... // This moves them out of them default location under src/<type>/... which would // conflict with src/ being used by the main source set. // Adding new build types or product flavors should be accompanied // by a similar customization. debug.setRoot('build-types/debug') release.setRoot('build-types/release') } //執行lint檢查,有任何的錯誤或者警告提示,都會終止構建,咱們能夠將其關掉。 lintOptions { abortOnError false } //簽名 signingConfigs { debug { storeFile file("/home/lippi/.android/debug.keystore") } relealse { //這樣寫就得把demo.jk文件放在項目目錄 storeFile file("recorder.jks") storePassword "recorder" keyAlias "recorder" keyPassword "recorder" } } buildTypes { debug { // 顯示Log buildConfigField "boolean", "LOG_DEBUG", "true" versionNameSuffix "-debug" minifyEnabled false zipAlignEnabled false shrinkResources false signingConfig signingConfigs.debug } release { // 不顯示Log buildConfigField "boolean", "LOG_DEBUG", "false" // 混淆 minifyEnabled true // Zipalign優化 zipAlignEnabled true // 移除無用的resource文件 shrinkResources true // 前一部分表明系統默認的android程序的混淆文件,該文件已經包含了基本的混淆聲明 proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg' // 簽名 signingConfig signingConfigs.relealse } } // 渠道Flavors,配置不一樣風格的app productFlavors { GooglePlay {} xiaomi {} umeng {} _360 {} baidu {} wandoujia {} } // 批量配置 productFlavors.all { flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] } compileOptions { sourceCompatibility JavaVersion.VERSION_1_7 targetCompatibility JavaVersion.VERSION_1_7 } applicationVariants.all { variant -> variant.outputs.each { output -> def outputFile = output.outputFile if (outputFile != null && outputFile.name.endsWith('.apk')) { def fileName = outputFile.name.replace(".apk", "-${defaultConfig.versionName}.apk") output.outputFile = new File(outputFile.parent, fileName) } } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') compile 'org.apache.commons:commons-math:2.1' compile 'org.slf4j:slf4j-log4j12:1.7.5' } }
文件開頭apply plugin是最新gradle版本的寫法,之前的寫法是apply plugin: ‘android’, 若是仍是之前的寫法,請改正過來。apache
buildToolsVersion這個須要你本地安裝該版本才行,不少人導入新的第三方庫,失敗的緣由之一是build version的版本不對,這個能夠手動更改爲你本地已有的版本或者打開 SDK Manager 去下載對應版本。app
applicationId表明應用的包名,也是最新的寫法,這裏就不在多說了。maven
minifyEnabled(混淆)也是最新的語法,很早以前是runProguard,這個也須要更新下。ide
compile project(‘:extras:ShimmerAndroid’)這一行是由於項目中存在其餘Module,你能夠理解成Android Library,因爲Gradle的普及以及遠程倉庫的完善,這種依賴漸漸的會變得很是不常見,可是你須要知道有這種依賴的。工具
3.gradle目錄下有個 wrapper 文件夾,裏面能夠看到有兩個文件,咱們主要看下 gradle-wrapper.properties 這個文件的內容:性能
#Wed Oct 21 11:34:03 PDT 2015 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip
能夠看到裏面聲明瞭gradle的目錄與下載路徑以及當前項目使用的gradle版本,這些默認的路徑咱們通常不會更改的,這個文件裏指明的gradle版本不對也是不少導包不成功的緣由之一
4.settings.gradle
這個文件是全局的項目配置文件,裏面主要聲明一些須要加入gradle的module
include ':app'
文件中app是項目的module,若是還有其餘module按照相同的格式加上去。
因爲國內Android市場衆多渠道,爲了統計每一個渠道的下載及其它數據統計,就須要咱們針對每一個渠道單獨打包,若是讓你打幾十個市場的包豈不煩死了,不過有了Gradle,這不再是事了。 以友盟統計爲例,在AndroidManifest.xml裏面會有這麼一段:
<meta-data android:name="UMENG_CHANNEL" android:value="Channel_ID" />
裏面的Channel_ID就是渠道標示。咱們的目標就是在編譯的時候這個值可以自動變化。
<meta-data android:name="UMENG_CHANNEL" android:value="${UMENG_CHANNEL_VALUE}" />
android { productFlavors { xiaomi {} _360 {} baidu {} wandoujia {} } productFlavors.all { flavor -> flavor.manifestPlaceholders = [UMENG_CHANNEL_VALUE: name] } }
而後直接執行 ./gradlew assembleRelease
而後就等待打包完成吧。
assemble 這個命令,會結合 Build Type 建立本身的task,如:
./gradlew assembleDebug
./gradlew assembleRelease
除此以外 assemble 還能和 Product Flavor 結合建立新的任務,其實 assemble 是和 Build Variants 一塊兒結合使用的,而 Build Variants = Build Type + Product Flavor , 舉個例子你們就明白了:
若是咱們想打包wandoujia渠道的release版本,執行以下命令就行了:
./gradlew assembleWandoujiaRelease
若是咱們只打wandoujia渠道版本,則:
./gradlew assembleWandoujia
此命令會生成wandoujia渠道的Release和Debug版本
同理我想打所有Release版本:
./gradlew assembleRelease
這條命令會把Product Flavor下的全部渠道的Release版本都打出來。
下面是常見的的proguard.cfg配置項:
#指定代碼的壓縮級別 -optimizationpasses 5 #包明不混合大小寫 -dontusemixedcaseclassnames #不去忽略非公共的庫類 -dontskipnonpubliclibraryclasses #優化 不優化輸入的類文件 -dontoptimize #預校驗 -dontpreverify #混淆時是否記錄日誌 -verbose # 混淆時所採用的算法 -optimizations !code/simplification/arithmetic,!field/*,!class/merging/* #保護註解 -keepattributes *Annotation* # 保持哪些類不被混淆 -keep public class * extends android.app.Fragment -keep public class * extends android.app.Activity -keep public class * extends android.app.Application -keep public class * extends android.app.Service -keep public class * extends android.content.BroadcastReceiver -keep public class * extends android.content.ContentProvider -keep public class * extends android.app.backup.BackupAgentHelper -keep public class * extends android.preference.Preference -keep public class com.android.vending.licensing.ILicensingService #若是有引用v4包能夠添加下面這行 -keep public class * extends android.support.v4.app.Fragment #忽略警告 -ignorewarning ##記錄生成的日誌數據,gradle build時在本項目根目錄輸出## #apk 包內全部 class 的內部結構 -dump class_files.txt #未混淆的類和成員 -printseeds seeds.txt #列出從 apk 中刪除的代碼 -printusage unused.txt #混淆先後的映射 -printmapping mapping.txt ########記錄生成的日誌數據,gradle build時 在本項目根目錄輸出-end###### #####混淆保護本身項目的部分代碼以及引用的第三方jar包library####### #-libraryjars libs/umeng-analytics-v5.2.4.jar #三星應用市場須要添加:sdk-v1.0.0.jar,look-v1.0.1.jar #-libraryjars libs/sdk-v1.0.0.jar #-libraryjars libs/look-v1.0.1.jar #若是不想混淆 keep 掉 -keep class com.lippi.recorder.iirfilterdesigner.** {*; } #友盟 -keep class com.umeng.**{*;} #項目特殊處理代碼 #忽略警告 -dontwarn com.lippi.recorder.utils** #保留一個完整的包 -keep class com.lippi.recorder.utils.** { *; } -keep class com.lippi.recorder.utils.AudioRecorder{*;} #若是引用了v4或者v7包 -dontwarn android.support.** ####混淆保護本身項目的部分代碼以及引用的第三方jar包library-end#### -keep public class * extends android.view.View { public <init>(android.content.Context); public <init>(android.content.Context, android.util.AttributeSet); public <init>(android.content.Context, android.util.AttributeSet, int); public void set*(...); } #保持 native 方法不被混淆 -keepclasseswithmembernames class * { native <methods>; } #保持自定義控件類不被混淆 -keepclasseswithmembers class * { public <init>(android.content.Context, android.util.AttributeSet); } #保持自定義控件類不被混淆 -keepclassmembers class * extends android.app.Activity { public void *(android.view.View); } #保持 Parcelable 不被混淆 -keep class * implements android.os.Parcelable { public static final android.os.Parcelable$Creator *; } #保持 Serializable 不被混淆 -keepnames class * implements java.io.Serializable #保持 Serializable 不被混淆而且enum 類也不被混淆 -keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; !static !transient <fields>; !private <fields>; !private <methods>; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve(); } #保持枚舉 enum 類不被混淆 若是混淆報錯,建議直接使用上面的 -keepclassmembers class * implements java.io.Serializable便可 #-keepclassmembers enum * { # public static **[] values(); # public static ** valueOf(java.lang.String); #} -keepclassmembers class * { public void *ButtonClicked(android.view.View); } #不混淆資源類 -keepclassmembers class **.R$* { public static <fields>; } #避免混淆泛型 若是混淆報錯建議關掉 #–keepattributes Signature #移除log 測試了下沒有用仍是建議本身定義一個開關控制是否輸出日誌 #-assumenosideeffects class android.util.Log { # public static boolean isLoggable(java.lang.String, int); # public static int v(...); # public static int i(...); # public static int w(...); # public static int d(...); # public static int e(...); #} #若是用用到Gson解析包的,直接添加下面這幾行就能成功混淆,否則會報錯。 #gson #-libraryjars libs/gson-2.2.2.jar -keepattributes Signature # Gson specific classes -keep class sun.misc.Unsafe { *; } # Application classes that will be serialized/deserialized over Gson -keep class com.google.gson.examples.android.model.** { *; }