2015-12-21 38 views
27

對於模塊的build.gradle文件是否有合理簡單的方法來指示應排除來自依賴項的某些文件?我特別希望從AAR中排除某些資源。如何從AAR依賴中排除特定資源?


LeakCanary是一個有趣的庫,用於幫助追蹤內存泄漏。但是,它有一個無法證明的要求,即compileSdkVersion爲21或更高。雖然大多數項目不應該有這個問題,但圖書館不需要一個好的理由就需要某個compileSdkVersion。作爲一般政策的一部分,開發團隊可能會凍結他們的compileSdkVersion,以便僅將這些設置作爲其應用程序的主要版本更新的一部分進行更改。

在這種情況下,對於至少LeakCanary的V1.3.1,唯一的原因compileSdkVersion是必需的,AFAICT,是因爲AAR具有res/values-v21/目錄,包含從Theme.Material繼承的主題定義。這個主題被診斷活動使用。最終用戶從未看到該活動,只有debug版本的開發人員才能看到。坦率地說,主題式的活動看起來並不重要。迫使21個compileSdkVersion只是爲了讓診斷活動有一定的主題,恕我直言,愚蠢。

如果作爲compile指令的一部分,我們可以說:「嘿,請從此AAR跳過res/values-v21/,m'kay?」。由於-v21主題僅僅提供了在其他地方定義的主題的替代定義,因此放棄-v21主題不會破壞構建或在運行時中斷事件,而只會給我們提供主題性診斷活動。

我無法看到this answer如何與依賴關係一起使用。我也不確定if it is complete, and it certainly does not appear to be supported。它也沒有真正的資格作爲「簡單」—我不希望有人嘗試在build.gradle文件中嘗試刪除此文件,以阻止像LeakCanary這樣的診斷庫中的單個文件。

那麼,有沒有比這更簡單的工作,現在用於Gradle的Android插件的最新版本?

+0

我認爲,對於LeakCanary解決辦法(https://github.com/square/leakcanary)將分叉它並編譯適當的'compileSdkVersion'自己的版本。我不確定它是否可以作爲問題的答案。 –

+0

@KonstantinLoginov:LeakCanary似乎有相當數量的相互關聯的移動部件,這就是爲什麼我懷疑叉子會很容易。我做了足夠的探索,以確定唯一的Android 5.0+功能是「Theme.Material」,這就是讓我提出這個問題的原因。當我在LeakCanary的背景下構思問題時,這個問題超越了這個圖書館。 – CommonsWare

+0

這將是很好,如果谷歌目前的gradle插件源是公開的。 DSL源代碼的標籤[1]落後於發佈標籤[2]。 [1] https://android.googlesource.com/platform/tools/gradle/+refs [2] https://jcenter.bintray.com/com/android/tools/build/gradle/ – JBirdVegas

回答

-3

是的,你可以使用Proguard

buildTypes { 
    release { 
     proguardFiles getDefaultProguardFile('proguard-android.txt'), 
     'proguard-rules.pro' 
    } 
debug { 
     proguardFiles getDefaultProguardFile('proguard-android.txt'), 
     'proguard-rules.pro' 
    } 
} 
+1

這是行不通的。 –

11

編輯:

爲你寫先進gradle這個任務:

final List<String> exclusions = []; 

Dependency.metaClass.exclude = { String[] currentExclusions -> 
    currentExclusions.each { 
     exclusions.add("${getGroup()}/${getName()}/${getVersion()}/${it}") 
    } 
    return thisObject 
} 

dependencies { 
    compile fileTree(dir: 'libs', include: ['*.jar']) 
    testCompile 'junit:junit:4.12' 
    compile ('com.android.support:appcompat-v7:20.+') 
    debugCompile ('com.squareup.leakcanary:leakcanary-android:1.3.1') 
      .exclude("res/values-v21/values-v21.xml") 
    releaseCompile ('com.squareup.leakcanary:leakcanary-android-no-op:1.3.1') 
} 

tasks.create("excludeTask") << { 
    exclusions.each { 
     File file = file("${buildDir}/intermediates/exploded-aar/${it}") 
     println("Excluding file " + file) 
     if (file.exists()) { 
      file.delete(); 
     } 
    } 
} 

tasks.whenTaskAdded({ 
    if (it.name.matches(/^process.*Resources$/)) { 
     it.dependsOn excludeTask 
    } 
}) 

現在你可以在每個相關使用方法.exclude(),提供到路徑列表中,您希望從指定的依賴項中排除。 另外,您可以堆疊.exclude()方法調用。

+0

我認爲你的'LEAKCANARY_ARTIFACT_NOOP'定義有一個錯誤。雖然這很有趣,但它並沒有回答實際的問題:「模塊的'build.gradle'文件是否有合理的簡單方法來指示應該排除依賴項中的某些文件?」它以另一種方式解決我的示例場景(修改資源)。不過謝謝! – CommonsWare

+0

我不認爲有什麼辦法可以做你想要的東西。但是,您可以編寫自己的任務,如下所示,這將在資源合併之前執行,並會刪除不需要的資源。每個模塊的所有資源都存儲在build/exploded-aar目錄中,並且您可以安全地從這些目錄中刪除它們,並且根本不會處理它們。但是,關於簡單性:您可以編寫自己的「編譯」關閉封裝,它可以接收任務中將排除的文件/目錄數組。我會盡力明天做出這個決定。 – IlyaGulya

+0

編輯答案。現在排除是更簡單,我想。 – IlyaGulya

0

我相信你可以使用Android Gradle Plugin DSL的PackagingOptions工具更優雅地解決這個問題。

我自己可以使用它來排除一些我不需要在我的項目中由AAR引入的本地庫。

android { 
    ... 
    packagingOptions { 
     exclude '/lib/armeabi-v7a/<file_to_exclude>' 
    } 
} 

對於這個問題概括的話,我相信這會工作:

android { 
    ... 
    packagingOptions { 
     exclude '/res/values-v21/<file_to_exclude>' 
    } 
} 
+1

我會在某個時候嘗試,但我懷疑這會起作用。首先,'pacakgingOptions'在構建過程中已經太晚了 - 構建應該在compileSdkVersion到達之前由於'compileSdkVersion'失敗。其次,AFAIK,'packagingOptions'指的是基於APK中的位置排除事物,而XML資源不會以普通文件的形式出現在APK中。不過謝謝! – CommonsWare

+0

有沒有機會動態地做到這一點? https://stackoverflow.com/questions/46543271/how-to-exclude-files-from-aar-with-gradle-dynamically – 4ntoine

相關問題