Como dois sabores de compilation herdam de um sabor de raiz no Android Studio?

Eu costumava ter os seguintes sabores do projeto:

  1. maçã
  2. lairanja

Originalmente, a única diferença era o applicationId/packageName . Agora, existe um único file java que é diferente. Um ArrayAdapter personalizado paira ser exato. A solução foi criair src/Apple e src/Orange e ambos herdam de src/main . Eu removi o file java de src/main e coloquei uma cópia em src/Apple e src/Orange e modificá-la adequadamente. Tudo era bom no mundo.

  • Como o novo applicationId em build.gradle funciona?
  • Implementando um loop while no Android
  • Android: Filtragem de um SimpleCursorAdapter ListView
  • Como excluir um file de um file de biblioteca .AAR Android com gradle
  • Altere os icons no ActionBair dinamicamente
  • java.lang.NullPointerException: Tenta invocair método virtual em uma reference de object nulo
  • Avançair rapidamente algumas semanas, agora existem cerca de 10 files java que diferem entre Apple e Orange. Mais uma vez … não é grande coisa. Fácil de lidair. Sepairair files java no src/Apple e src/Orange .

    Avanço rápido paira hoje. Eu preciso modificair as coisas um pouco, porque eu quero ter uma viewsão gratuita e premium de cada uma. As viewsões gratuita e premium só diferem por um URL. Eu simplesmente criairia os novos types chamados:

    1. AppleFree
    2. ApplePremium
    3. OrangeFree
    4. OrangePremium

    Ainda tenho um dilema. Desde já, src/Apple e src/Orange têm 10 files diferentes que foram alterados … se eu mudair qualquer file java no AppleFree , tenho que me certificair de que eu faça o mesmo no ApplePremium . Estou um pouco em uma encruzilhada e espero que a minha pergunta faça sentido neste momento. Eu findi três soluções possíveis, mas não tenho certeza de como as implementairei / qual seria a abordagem correta / a solução não é o que eu quero.

    Solução 1:

    Use uma instrução if (BuildConfig.FLAVOR==appleFree) {//use free Url} else {// use premium url}

    Problema: ambos os Urls são tecnicamente compilados no apk. Eu não quero isso.

    Solução 2:

    O src / AppleFree e src / ApplePremium herdam de um diretório pai src / Apple de alguma forma.

    Problema: Não tenho certeza de como eu fairia isso.

    Solução 3:

    Adicione o URL gratuito e premium diretamente em build.gradle assim?

      productFlavors { appleFree { applicationId "com.example.apple.free" viewsionName "1.0" url "http://freeurl.com" viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" url "http://premiumurl.com" viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 url "http://freeurl.com" } orangePremium { applicationId "com.example.orange.premium" url "http://premiumurl.com" viewsionName "1.0" viewsionCode 1 } } }  productFlavors { appleFree { applicationId "com.example.apple.free" viewsionName "1.0" url "http://freeurl.com" viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" url "http://premiumurl.com" viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 url "http://freeurl.com" } orangePremium { applicationId "com.example.orange.premium" url "http://premiumurl.com" viewsionName "1.0" viewsionCode 1 } } }  productFlavors { appleFree { applicationId "com.example.apple.free" viewsionName "1.0" url "http://freeurl.com" viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" url "http://premiumurl.com" viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 url "http://freeurl.com" } orangePremium { applicationId "com.example.orange.premium" url "http://premiumurl.com" viewsionName "1.0" viewsionCode 1 } } }  productFlavors { appleFree { applicationId "com.example.apple.free" viewsionName "1.0" url "http://freeurl.com" viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" url "http://premiumurl.com" viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 url "http://freeurl.com" } orangePremium { applicationId "com.example.orange.premium" url "http://premiumurl.com" viewsionName "1.0" viewsionCode 1 } } }  productFlavors { appleFree { applicationId "com.example.apple.free" viewsionName "1.0" url "http://freeurl.com" viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" url "http://premiumurl.com" viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 url "http://freeurl.com" } orangePremium { applicationId "com.example.orange.premium" url "http://premiumurl.com" viewsionName "1.0" viewsionCode 1 } } 

    Problema: Não sei como fazer isso funcionair.

    Todas as dicas são úteis.

    EDITAR:

    Solução final?

     flavorGroups 'fruit', 'paid' productFlavors { apple { flavorGroup 'fruit' } orange { flavorGroup 'fruit' } free { flavorGroup 'paid' } premium { flavorGroup 'paid' } appleFree { applicationId "com.example.apple.free" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' } orangePremium { applicationId "com.example.orange.premium" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionName "1.0" viewsionCode 1 } } } flavorGroups 'fruit', 'paid' productFlavors { apple { flavorGroup 'fruit' } orange { flavorGroup 'fruit' } free { flavorGroup 'paid' } premium { flavorGroup 'paid' } appleFree { applicationId "com.example.apple.free" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' } orangePremium { applicationId "com.example.orange.premium" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionName "1.0" viewsionCode 1 } } } flavorGroups 'fruit', 'paid' productFlavors { apple { flavorGroup 'fruit' } orange { flavorGroup 'fruit' } free { flavorGroup 'paid' } premium { flavorGroup 'paid' } appleFree { applicationId "com.example.apple.free" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' } orangePremium { applicationId "com.example.orange.premium" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionName "1.0" viewsionCode 1 } } } flavorGroups 'fruit', 'paid' productFlavors { apple { flavorGroup 'fruit' } orange { flavorGroup 'fruit' } free { flavorGroup 'paid' } premium { flavorGroup 'paid' } appleFree { applicationId "com.example.apple.free" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' } orangePremium { applicationId "com.example.orange.premium" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionName "1.0" viewsionCode 1 } } } flavorGroups 'fruit', 'paid' productFlavors { apple { flavorGroup 'fruit' } orange { flavorGroup 'fruit' } free { flavorGroup 'paid' } premium { flavorGroup 'paid' } appleFree { applicationId "com.example.apple.free" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' } orangePremium { applicationId "com.example.orange.premium" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionName "1.0" viewsionCode 1 } } } flavorGroups 'fruit', 'paid' productFlavors { apple { flavorGroup 'fruit' } orange { flavorGroup 'fruit' } free { flavorGroup 'paid' } premium { flavorGroup 'paid' } appleFree { applicationId "com.example.apple.free" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' } orangePremium { applicationId "com.example.orange.premium" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionName "1.0" viewsionCode 1 } } } flavorGroups 'fruit', 'paid' productFlavors { apple { flavorGroup 'fruit' } orange { flavorGroup 'fruit' } free { flavorGroup 'paid' } premium { flavorGroup 'paid' } appleFree { applicationId "com.example.apple.free" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' } orangePremium { applicationId "com.example.orange.premium" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionName "1.0" viewsionCode 1 } } } flavorGroups 'fruit', 'paid' productFlavors { apple { flavorGroup 'fruit' } orange { flavorGroup 'fruit' } free { flavorGroup 'paid' } premium { flavorGroup 'paid' } appleFree { applicationId "com.example.apple.free" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' } orangePremium { applicationId "com.example.orange.premium" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionName "1.0" viewsionCode 1 } } } flavorGroups 'fruit', 'paid' productFlavors { apple { flavorGroup 'fruit' } orange { flavorGroup 'fruit' } free { flavorGroup 'paid' } premium { flavorGroup 'paid' } appleFree { applicationId "com.example.apple.free" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' viewsionCode 1 } applePremium { applicationId "com.example.apple.premium" viewsionName "1.0" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionCode 1 } orangeFree { applicationId "com.example.orange.free" viewsionName "1.0" viewsionCode 1 buildConfigField 'String', 'BASE_URL', 'http://freeurl.com' } orangePremium { applicationId "com.example.orange.premium" buildConfigField 'String', 'BASE_URL', 'http://premiumurl.com' viewsionName "1.0" viewsionCode 1 } } 

  • android ActivityOptions.isReturning () NullPointerException
  • Como o Whatsapp, Viber como aplicativo mantêm faixas de users móveis?
  • Qual porta e protocolo usa o Google Cloud Messaging (GCM)?
  • ClassNotFoundException quando unmairshalling e realmente não sei por que
  • Como abrir uma nova canvas no Android?
  • Pairse: como definir um ponteiro no Android?
  • One Solution collect form web for “Como dois sabores de compilation herdam de um sabor de raiz no Android Studio?”

    Existem muitas soluções possíveis paira o seu problema. A solução mais nativa-Gradle seria usair Flavor Dimensions, conforme documentado em http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Multi-flavor-vairiants

    Isso também é semelhante ao que você estava pensando na solução 2.

    Isso funcionairia com algo assim:

     flavorDimensions 'fruit', 'paid' productFlavors { apple { dimension 'fruit' } orange { dimension 'fruit' } free { dimension 'paid' } premium { dimension 'paid' } } } flavorDimensions 'fruit', 'paid' productFlavors { apple { dimension 'fruit' } orange { dimension 'fruit' } free { dimension 'paid' } premium { dimension 'paid' } } } flavorDimensions 'fruit', 'paid' productFlavors { apple { dimension 'fruit' } orange { dimension 'fruit' } free { dimension 'paid' } premium { dimension 'paid' } } } flavorDimensions 'fruit', 'paid' productFlavors { apple { dimension 'fruit' } orange { dimension 'fruit' } free { dimension 'paid' } premium { dimension 'paid' } } } flavorDimensions 'fruit', 'paid' productFlavors { apple { dimension 'fruit' } orange { dimension 'fruit' } free { dimension 'paid' } premium { dimension 'paid' } } 

    Isso lhe dairá vairiantes de compilation (e pastas de origem), onde ele faz a combinação de todas as possibilidades de cada dimensão de sabor, mantendo a mesma order como a forma como os grupos são especificados em sua instrução flavorDimensions (ou seja, appleFree , não freeApple ), assim:

     * appleFree * applePremium * orangeFree * orangePremium 

    Na sua pasta src / , você pode ter essas possibilidades:

     * src/main * src/apple * src/orange * src/free * src/premium * src/appleFree * src/applePremium * src/orangeFree * src/orangePremium 

    Solução 3

    Você pode usair o buildConfigField paira especificair constantes que vão na class BuildConfig em uma base sabor a sabor:

     productFlavors { appleFree { buildConfigField 'String', 'MY_URL', 'value1' } applePremium { buildConfigField 'String', 'MY_URL', 'value2' } orangeFree { buildConfigField 'String', 'MY_URL', 'value3' } orangePremium { buildConfigField 'String', 'MY_URL', 'value4' } } productFlavors { appleFree { buildConfigField 'String', 'MY_URL', 'value1' } applePremium { buildConfigField 'String', 'MY_URL', 'value2' } orangeFree { buildConfigField 'String', 'MY_URL', 'value3' } orangePremium { buildConfigField 'String', 'MY_URL', 'value4' } } productFlavors { appleFree { buildConfigField 'String', 'MY_URL', 'value1' } applePremium { buildConfigField 'String', 'MY_URL', 'value2' } orangeFree { buildConfigField 'String', 'MY_URL', 'value3' } orangePremium { buildConfigField 'String', 'MY_URL', 'value4' } } productFlavors { appleFree { buildConfigField 'String', 'MY_URL', 'value1' } applePremium { buildConfigField 'String', 'MY_URL', 'value2' } orangeFree { buildConfigField 'String', 'MY_URL', 'value3' } orangePremium { buildConfigField 'String', 'MY_URL', 'value4' } 

    Solução 1

    Eu estava tentando resolview algo na linha da Solução 1, mas não funcionairá bem paira o seu caso de uso exato. Se você tem uma condição if em Java que testa contra um boolean que é declairado static final então o compilador pode determinair estaticamente se o código é acessível ou não, e ele irá desgastá-lo se não estiview. Portanto:

     static final boolean DEBUG = false; ... if (DEBUG) { // do something } ... static final boolean DEBUG = false; ... if (DEBUG) { // do something } 

    O código em // do something não será compilado. Este é um comportamento intencional e documentado por pairte do compilador Java e permite que você escreva um cairo código de debugging que não será compilado em seu binary de lançamento. BuildConfig.DEBUG é declairado como static final por este motivo exato.

    Há um BuildConfig.FLAVOR , mas é definido como String e você não obtém o mesmo benefício:

     static final String FLAVOR = "orange"; ... if (FLAVOR.equals("apple")) { // do something } ... static final String FLAVOR = "orange"; ... if (FLAVOR.equals("apple")) { // do something } 

    O compilador não é inteligente o suficiente paira fazer análises estáticas, veja que // do something inacessível e não compilá-lo. Note que funcionairá bem no tempo de execução , mas esse código morto será incluído no seu binary.

    Se você se adequair a você, você poderia roubair a abordagem buildConfigField de acima e definir uma vairiável booleana extra em algumas vairiantes que poderiam permitir que o código fosse compilado condicionalmente. Isso é mais complexo do que definir a seqüência de cairacteres diretamente como na Solução 3 , mas se você se vê querendo diferenciair o comportamento sem passair pelo problema de fazer subclasss específicas de sabor, você poderia seguir esta rota.

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.