2014-01-16 89 views
22

我想用resdle重寫res/strings.xml中的一些字符串。根據buildType覆蓋gradle資源

我知道since Android Gradle Plugin 0.7.+ theres可能性具有變體特定的源文件夾。 但我的應用程序有很多風味,我不想額外添加變體特定的文件夾。

UPDATE 2014年1月17日

我想詳細:

我有我的一些資源變量由buildType(例如「發佈」),僅僅依靠。 首先,我認爲我的SOLUTION_1(覆蓋資源合併後的數據)是很好的,因爲如果我必須更改這些變量,我只需要在build.config(只是一個地方)中更改它們。 但是正如Scott Barta在下面的評論中所寫的那樣,這個解決方案不是一個好主意,有一些很好的理由。

所以我嘗試了另一個解決方案SOLUTION_2(只是合併正確的資源)根據this GitHub project of shakalaca。我認爲這種方式更優雅,我仍然有優勢,只是改變一個地方的變量!

SOLUTION_1(資源後,覆蓋的數據合併):

我所做的在AS 0.4.2:

  • build.gradle我試圖重寫字符串 「Hello World」 到「越權」(based on my answer at this post):

    android.applicationVariants.all{ variant -> 
        // override data in resource after merge task 
        variant.processResources.doLast { 
         overrideDataInResources(variant) 
        } 
    } 
    
    def overrideDataInResources(buildVariant){ 
        copy { 
         // *** SET COPY PATHS *** 
         try { 
          from("${buildDir}/res/all/${buildVariant.dirName}") { 
           // println "... FROM: ${buildDir}/res/all/${buildVariant.dirName}" 
           include "values/values.xml" 
          } 
         } catch (e) { 
          println "... EXCEPTION: " + e 
         } 
    
         into("${buildDir}/res/all/${buildVariant.dirName}/values") 
         // println "... INTO: ${buildDir}/res/all/${buildVariant.dirName}/values" 
    
         // --- override string "hello_world" 
         filter { 
          String line -> 
           line.replaceAll("<string name=\"hello_world\">Hello world!</string>", 
             "<string name=\"hello_world\">OVERRIDE</string>"); 
         } 
    
        // *** SET PATH TO NEW RES *** 
        buildVariant.processResources.resDir = file("${buildDir}/res/all/${buildVariant.dirName}/values/values/values.xml") 
        // println "... NEW RES PATH: " + "${buildDir}/res/all/${buildVariant.dirName}/values/values/values.xml" 
        } 
    } 
    

複製和篩選任務工作正常,但我無法將「新」values.xml設置爲字符串資源。

SOLUTION_2(只是合併了正確的資源)

  • 定義特定buildType一個floavor(如 「releaseRes」)
  • 合併要建立這個資源的開發與味:

    android.applicationVariants.all{ variant -> 
        variant.mergeResources.doFirst{ 
         checkResourceFolder(variant) 
        } 
    } 
    
    def checkResourceFolder(variant){ 
        def name = variant.name; 
        if(name.contains("Release")){ 
         android.sourceSets.release.res.srcDirs = ['src/releaseRes/res'] 
         android.sourceSets.flavor1.res.srcDirs = ['src/flavor1/res'] 
        } 
    } 
    
+6

這一般只是不是一個很好的主意。如果您嘗試在構建系統中執行重要的體操操作來修改資源,那麼整個項目的維護和調試將非常困難。這將會非常脆弱,因爲對該插件的更改可能會破壞它,或者對Android Studio的更改可能會使其無法使用。這是值得發佈的問題,解釋你到底想要完成什麼,並列出你考慮的方法,包括這一個。 –

+0

感謝您的回答。我編輯了我的問題,並詳細解釋了我想要的內容。我想我爲我的問題找到了一個很好的解決方案(SOLUTION_2)! – owe

+0

斯科特是對的:)我已經實施了solution_1,一年後我用更新的IDE返回了我的項目,更新了插件,它全部壞掉了。 –

回答

18

你應該努力想出一個解決方案,在編譯文件中編寫任何自定義代碼,特別是那些在動態重新分配源代碼集時會做出棘手事情的代碼。自定義Gradle代碼編寫起來有點時髦,而且很難調試和維護。新的構建系統非常強大,並且已經具有很大的靈活性,並且很可能您已經可以做到您想要的;這只是一個學習如何的問題。

尤其是如果您只是在學習Android-Gradle項目的細節(而且它是如此新以至於我們都是),那麼最好儘量使用內置於系統中的功能,然後再考慮外框。

一些建議:

  • 這是不可能的,你需要根據構建類型來改變資源。 Android-Gradle中的構建類型應該是類似調試或發佈的類型,其差別在於可調試性,編譯器優化或簽名;構建類型應該在功能上彼此等效。如果你看一下properties you can set on a build type through the Groovy DSL,你可以看到意圖:debuggablejniDebugBuildrenderscriptDebugBuildrenderscriptOptimLevelpackageNameSuffixversionNameSuffixsigningConfigzipAlignrunProguardproguardFileproguardFiles
  • 如果您仍然認爲您想要根據構建類型來改變資源,那麼現有的構建系統就已經有了一種簡單的方法。您可以擁有一個特定於構建類型的資源目錄,將資源置於其中,構建系統中的資源合併將在構建時爲您提供幫助。這是Android/Gradle中的強大功能之一。有關如何完成此項工作的信息,請參閱Using Build Flavors - Structuring source folders and build.gradle correctly
  • 如果您想根據構建類型來改變某些內容,並且您的需求非常快速且簡單,那麼您可能希望使用Java代碼而不是資源而不是構建系統進行切換。這種類型的機制有BuildConfig--它是一個Java類,它根據debug/release構建狀態定義了一個DEBUG標誌,並且您可以從不同的構建類型添加您自己的自定義Java代碼以執行更有意義的事情。 BuildConfig旨在允許構建類型之間存在小的功能差異,例如調試構建可能希望執行一些浪費操作以協助開發的情況,如進行更廣泛的數據驗證或創建更詳細的調試日誌記錄,以及對這些浪費的事情進行最佳優化沒有發佈版本。話雖如此,它可能是一個適當的機制去做你想做的事情。
  • 考慮爲目前使用的構建類型使用flavor。從概念上講,風味就像構建類型,因爲它是可以構建的應用程序的另一種變體;構建系統將創建一個風格與構建類型的矩陣,並可以構建所有組合。然而,口味處理不同的用例,其中不同口味共享大部分代碼,但可能具有顯着的功能差異。一個常見的例子是應用程序的免費版本與付費版本。由於應用的不同變體中的不同資源表示不同的功能,因此可能表明需要不同的風格。 Flavors可以擁有不同的資源目錄,這些資源目錄在構建時以與構建配置相同的方式進行合併;查看上面鏈接的問題獲取更多信息。
+2

現在有可能通過DSL生成資源值:https://plus.google.com/109385828142935151413/posts/UVKA58MZV3J。只是爲了興趣:應該像'BuildConfig'機制一樣工作嗎?我只是試過這個 - gradle沒有拋出任何異常,但我找不到資源值。 – owe

+0

這是值得發佈的,作爲一個單獨的問題,你正在使用的代碼。我會upvote它;-) –

+0

是的...你說得對。我會在接下來的幾天寫一個新的問題。感謝您的讚揚:) – owe

5

我不相信你需要定製構建腳本來達到你想要的。根據我的閱讀http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants;構建運行時,資源將從以下文件夾合併(如果存在);

src/[flavour][buildType]/res 
src/[buildType]/res 
src/[flavour]/res 
src/main/res 

所以我相信你可以通過簡單地添加資源在src/release/res中實現你想要的。

雖然你可以通過指定相關的sourceSets來調整文件夾名稱,如果你真的想改變它們,你可以使用[type] .res.srcDirs。

+0

非常好! IDE甚至建議在創建資源文件之前選擇構建類型。謝謝 – Viktor

0

如果有人偶然發現了這個

buildTypes { 
     debug{ 
      buildConfigField "String", "Your_string_key", '"yourkeyvalue"' 
      buildConfigField "String", "SOCKET_URL", '"some text"' 
      buildConfigField "Boolean", "LOG", 'true' 
     } 
     release { 
      buildConfigField "String", "Your_string_key", '"release text"' 
      buildConfigField "String", "SOCKET_URL", '"release text"' 
      buildConfigField "Boolean", "LOG", 'false' 

     } 
    } 

並訪問使用建變種這些值:

if(!BuildConfig.LOG) 
     // do something with the boolean value 

或者

view.setText(BuildConfig.yourkeyvalue); 
+1

這增加了一個字符串常量,但不是像OP想要的字符串資源。例如,您可能需要一個資源來引用Manifest或xml文件。 – sorianiv