2014-01-07 32 views
16

我創建了一個需要在許多(30+)口味中構建的Android應用。我的想法是直接從我的src目錄中的文件夾結構中生成不同的productFlavors,因爲配置總是非常相似(基本上只是另一個packageName,一個新的啓動器圖標和一些字符串更改)。動態生成產品口味

src文件夾是這樣的:

└── src 
    ├── flavor1 
    │   ├── flavor2.keystore 
    │   ├── res 
    ├── flavor2 
    │   ├── res 
    │   ├── flavor2.keystore  
    └── main 
       ├── AndroidManifest.xml 
       ├── java 
       └── res 

如果我不得不手動創建gradle這個特性它看起來在某種程度上是這樣的:

android { 

    .... 

    productFlavors { 
     flavor1 { 
      packageName 'com.example.flavor1' 
     } 
     flavor2 { 
      packageName 'com.example.flavor2' 
     } 
    } 

} 

每次我試圖改變productFlavors配置創建後,我得到一個錯誤或更改/添加被默默地忽略。
這可能是由我造成的問題,因爲我的Gradle/Groovy體驗非常有限,或者這是不可能的。

我大多會得到錯誤,說GroupableProductFlavorDsl_Decorated不能按我想要的方式操縱。

我試圖存檔應該以某種方式是這樣的:

android { 

    .... 

    def flavors = getMyFlavorsFromFileSystem() 

    productFlavors { 

    } 

    flavors.each { name, config -> 
     productFlavors[name] << config 
    } 

} 

注:我知道這個問題基本上是一個老問題,可惜這種情況從來沒有回答的duplicate。由於Gradle對Android世界是一種新鮮的東西,我希望能夠從上次提問時得到更多答案,因爲更多的開發人員現在正在使用Gradle。

更新:

在這裏,我嘗試了一些非常簡單的方法:

變體1:

android { 

    productFlavors { 

    } 

    productFlavors['flavor1'] << { 
     packageName "com.example.flavor1" 
    } 

    productFlavors['flavor2'] << { 
     packageName "com.example.flavor2" 
    } 
} 

/* 

A problem occurred evaluating root project 'MyProject'. 
> GroupableProductFlavorDsl with name 'flavor1' not found. 

*/ 

變2:

android { 

    productFlavors { 

    } 

    productFlavors['flavor1'] = { 
     packageName "com.example.flavor1" 
    } 

    productFlavors['flavor2'] = { 
     packageName "com.example.flavor2" 
    } 
} 

/* 

no error, but does not work 

*/ 

變3:

android { 

    productFlavors { 

    } 

    productFlavors['flavor1'] = [packageName: "com.example.flavor1"] 

    productFlavors['flavor2'] = [packageName: "com.example.flavor2"] 
} 

/* 

no error, but does not work 

*/ 

所有這些作爲Gist

+0

「每次我嘗試弄亂productFlavors配置時,我得到一個錯誤或者更改/添加被默認忽略」 - 當你不解釋什麼「混亂」意味着很難幫助你,你得到了什麼錯誤,什麼是「默默無視」的「變化/添加」等等。 – CommonsWare

+0

爲什麼要創建這麼多的構建?你的代碼無法識別它運行的是哪個版本並相應地調整它的方法? Google/Android人員在支持庫的工作方面做得很好 – Martin

+1

@Martin我需要這麼多版本,因爲這些應用程序是作爲白標籤應用程序出售給客戶的(不同的packageName,不同的Google開發者賬戶,不同的keyStore)。我的公司在打印到網絡部門工作,所以是的:我需要這麼多的版本。 – TheHippo

回答

18

通過試驗和錯誤解決:

android { 

    // let's assume these are return by a function which reads the filesystem 
    def myFlavors = [ 
     flavor1: [ 
      packageName: "com.example.flavor1" 
     ], 
     flavor2: [ 
      packageName: "com.example.flavor2" 
     ] 
    ] 

    productFlavors { 
     myFlavors.each { name, config -> 
      "$name" { 
       packageName config.packageName 
      } 
     } 
    } 

} 
+0

你可以分享讀取文件系統的代碼來獲取packageNames嗎? –

+0

@SeanBarbeau我寧可不要。如上所述,這有點複雜。 (閱讀目錄,檢查各種文件,解析一些YAML和JSON ...) – TheHippo

+0

@TheHippo你還在手動創建'src /'文件夾,還是在其他地方創建它們。如果它們不是手動創建的,你會介意發佈那段創建文件夾結構的代碼。謝謝。 – danypata

3

由於問題筆者不想分享他的代碼讀取文件。我會寫我做了什麼。我把所有的變量名在一個名爲「應用程序/ build_variants.txt」文件,每一行,像這樣:

flavor1 
flavor2 
flavor3 
flavor4 
flavor5 

而在「應用程序/編譯。gradle這個「:

//...other configs... 

android { 
    productFlavors { 
     new File('app/build_variants.txt').eachLine { "$it" { resValue "string", "build_variant_name", "$it" } } 
    } 
} 

//...other configs 

這將有同樣的結果如下面的代碼:

//...other configs... 

android { 
    productFlavors { 
     flavor1 { resValue "string", "build_variant_name", "flavor1" } 
     flavor2 { resValue "string", "build_variant_name", "flavor2" } 
     flavor3 { resValue "string", "build_variant_name", "flavor3" } 
     flavor4 { resValue "string", "build_variant_name", "flavor4" } 
     flavor5 { resValue "string", "build_variant_name", "flavor5" } 
    } 
} 

//...other configs 

這裏的關鍵是線new File('app/build_variants.txt').eachLine { "$it" { resValue "string", "build_variant_name", "$it" } }它讀取文件‘應用程序/ build_variants.txt’和每個。如果你想要更深入的理解,我強烈建議你看看@Daniel Lew's video關於groovy和gradle的內容,這真棒! 。

+0

問題是關於如何動態生成flavor,而不是關於如何從gradle構建腳本讀取文件。 – TheHippo

+1

@TheHippo我的答案還包括動態生成風味的代碼,以及閱讀文件的代碼,這可能有助於那些將產品風味保留在單獨文件中的人。 –

+0

如果每行包含以逗號分隔的多個值,該怎麼辦?我怎樣才能把它們分開放入生成的口味中?在你的例子中,你把整條線(這只是味道的名字)。哪些工作適合我。但我想傳遞應用程序ID和resValues以及文件。那可能嗎? – AndroidMechanic

6

我知道這已經有了一個答案,但我把Chris.Zou的方法與TheHippo結合在一起。並添加我自己的方法來做到這一點。

基本上,在處理風味時,我們通常使用包含資源的/ app/src /下的不同目錄。由於目錄名稱等於包名稱,我只列出了該文件夾下的目錄(不包括「main」和「androidTest」)。

因此,這裏是我的完整,工作gradle這個腳本:

def map = [:] 

new File("./app/src").eachFile() { file-> 

    def fileName = file.getName() 
    if(fileName == "main" || fileName == "androidTest") { 
     return 
    } 

    map.put(fileName, 'com.mypackagename.' + fileName) 


} 
productFlavors { 
    map.each { flavorName, packagename -> 
     "$flavorName" { 
      applicationId packagename 
     } 
    } 
} 

編輯:

  • 還想補充的com.mypackagename基本上是所有口味的根路徑。
  • 我有一個單獨的腳本,將flavor目錄複製到/ app/src /文件夾。