Usar os tipos de compilação na Gradle para executar a mesma aplicação que usa o obturador de conteúdo num dispositivo

configurei o Gradle para adicionar o sufixo do nome do pacote à minha aplicação de depuração para que pudesse ter a versão de lançamento que estou a usar e a versão de depuração num telemóvel. Estava a referir-me a isto: http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Types

A minha constituição.o ficheiro do gradle parece-se com isto:
...
android
{
    ...
    buildTypes
    {
        debug
        {
            packageNameSuffix ".debug"
            versionNameSuffix " debug"
        }
    }
}

tudo funciona bem até eu começar a usar um Provador de conteúdo na minha aplicação. Eu entendo.

Failure [INSTALL_FAILED_CONFLICTING_PROVIDER]

eu entendo que isso acontece porque dois aplicativos (lançamento e debug) estão registrando a mesma autoridade Provedora de conteúdo.

Vejo uma possibilidade de resolver isto. Se eu entender corretamente, você deve ser capaz de especificar diferentes arquivos para usar ao construir. Então eu deveria ser capaz de colocar diferentes autoridades em diferentes arquivos de recursos (e a partir de Manifest set authority como string resource) e dizer a Gradle para usar recursos diferentes para debug build. Isso é possível? Se sim, então qualquer sugestão sobre como alcançar isso seria incrível!

Ou talvez seja ... é possível modificar diretamente o Manifesto usando o Grale? Qualquer outra solução sobre como executar o mesmo aplicativo com o Obtentprovider em um dispositivo é sempre bem-vindo.

Author: Jonik, 2013-05-27

14 answers

Nenhuma das respostas existentes me satisfez, por Mais que a liberdade estivesse perto. Então é assim que eu faço. Em primeiro lugar, neste momento estou a trabalhar com:
    Android Studio Beta 0.8.2
  • 'plugin' de grelhas 0.12.+
  • Gradle 1, 12

O meu objectivo é executar a versão Debug juntamente com Release a versão no mesmo dispositivo usando o mesmo ContentProvider.


Em construir.gradle do seu sufixo de conjunto de aplicações para a depuração compilar:

buildTypes {
    debug {
        applicationIdSuffix ".debug"
    }
}

In AndroidManifest.xml conjunto de ficheiros android:authorities propriedade do seu ContentProvider:

<provider
    android:name="com.example.app.YourProvider"
    android:authorities="${applicationId}.provider"
    android:enabled="true"
    android:exported="false" >
</provider>

No seu código conjunto AUTHORITY que pode ser usado sempre que necessário na sua implementação:

public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".provider";

Dica: Antes de ser BuildConfig.PACKAGE_NAME

É isso! Vai funcionar como um amuleto. Continue a ler se utilizar SyncAdapter!

Actualização para SyncAdapter (14.11.2014)

Mais uma vez começarei com a minha corrente. configuração:
    Android Studio Beta 0.9.2
  • 'plugin' de grelhas 0. 14. 1
  • Grale 2, 1

Basicamente, se você precisa personalizar alguns valores para diferentes compilações você pode fazê-lo a partir da compilação.ficheiro da grelha:

  • use buildConfigField para aceder a ele a partir da classe BuildConfig.java
  • utilize resValue para aceder a ele a partir de recursos, por exemplo @string/your_ value
Como uma alternativa para os recursos, você pode criar directórios de tipo de construção ou de sabor separados e sobrepor XMLs ou valores dentro deles. No entanto, não vou usá-lo no exemplo abaixo.

Exemplo


Em construir.gradle adicione o seguinte:

defaultConfig {
    resValue "string", "your_authorities", applicationId + '.provider'
    resValue "string", "account_type", "your.syncadapter.type"
    buildConfigField "String", "ACCOUNT_TYPE", '"your.syncadapter.type"'
}

buildTypes {
    debug {
        applicationIdSuffix ".debug"
        resValue "string", "your_authorities", defaultConfig.applicationId + '.debug.provider'
        resValue "string", "account_type", "your.syncadapter.type.debug"
        buildConfigField "String", "ACCOUNT_TYPE", '"your.syncadapter.type.debug"'
    }
}

Verá resultados em BuildConfig.java Classe

public static final String ACCOUNT_TYPE = "your.syncadapter.type.debug";

E em build/generated/res/generated/debug/values / generated.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <!-- Automatically generated file. DO NOT MODIFY -->
    <!-- Values from default config. -->
    <item name="account_type" type="string">your.syncadapter.type.debug</item>
    <item name="authorities" type="string">com.example.app.provider</item>

</resources>

No seu autenticador.xml usar o recurso indicado em construir.ficheiro de gradle
<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
                       android:accountType="@string/account_type"
                       android:icon="@drawable/ic_launcher"
                       android:smallIcon="@drawable/ic_launcher"
                       android:label="@string/app_name"
/>

No teu sincadapter.xml utilize o mesmo recurso novamente e @string / authorities too

<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
              android:contentAuthority="@string/authorities"
              android:accountType="@string/account_type"
              android:userVisible="true"
              android:supportsUploading="false"
              android:allowParallelSyncs="false"
              android:isAlwaysSyncable="true"
        />

Dica: a completação automática (Ctrl+Espaço) não funciona para estes recursos gerados, pelo que terá de os Escrever manualmente

 208
Author: Damian Petla, 2015-05-19 12:24:54

Nova dica do sistema de compilação Android: Autoridade de fornecedores de conteúdos a renomear

Acho que todos já ouviram falar do novo sistema de Compilação baseado em Android. Sejamos honestos, este novo sistema de construção é um grande passo em frente em comparação com o anterior. Ainda não é final (a partir desta escrita, a última versão é 0.4.2), mas você já pode usá-lo com segurança na maioria dos seus projetos. Mudei a maior parte do meu projecto para este novo sistema de construção e tive alguns problemas. devido à falta de apoio em algumas situações específicas. Um dos quais é o apoio à mudança de nome da Autoridade fornecedora do Conteúdo

O novo sistema construído Android permite-lhe lidar com diferentes tipos do seu aplicativo, simplesmente modificando o nome do pacote no tempo de construção. Uma das principais vantagens desta melhoria é que você agora pode ter duas versões diferentes do seu aplicativo instalado no mesmo dispositivo ao mesmo tempo. Por exemplo:

android {
   compileSdkVersion 17
   buildToolsVersion "17.0.0"

   defaultConfig {
       packageName "com.cyrilmottier.android.app"
       versionCode 1
       versionName "1"
       minSdkVersion 14 // Listen to +Jeff Gilfelt advices :)
       targetSdkVersion 17
   }

   buildTypes {
       debug {
        packageNameSuffix ".debug"
            versionNameSuffix "-debug"
       }
   }
}

Usando tal configuração de graxa, você pode montar dois APKs diferentes:

• uma APK de depuração com a comunicação.cyrilmottier.androide.aplicacao.depurar o nome do pacote • Um APK de lançamento com o com.cyrilmottier.androide.nome do pacote da aplicação

O único problema com isso é que você não será capaz de instalar os dois APKs ao mesmo tempo, se ambos expor um Provador de contentamento com as mesmas autoridades. Logicamente, precisamos de mudar o nome da Autoridade dependendo do tipo de compilação actual ... mas isto não é suportado pelo sistema de compilação do Gradle (ainda? ... Eu ... claro que será consertado em breve). Então, aqui está uma maneira de ir:

Primeiro precisamos mover a declaração de conteúdo Manifesto Android para o tipo de construção Apropriado. Para isso, teremos simplesmente:

Src/debug / AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.cyrilmottier.android.app"
   android:versionCode="1"
   android:versionName="1">

   <application>

       <provider
           android:name=".provider.Provider1"
           android:authorities="com.cyrilmottier.android.app.debug.provider"
           android:exported="false" />

   </application>
</manifest>

Src / release / AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.cyrilmottier.android.app"
   android:versionCode="1"
   android:versionName="1">

   <application>

       <provider
           android:name=".provider.Provider1"
           android:authorities="com.cyrilmottier.android.app.provider"
           android:exported="false" />

   </application>
</manifest>

Certifique-se de remover a declaração do obtentor do AndroidManifest.xml no src / main / porque o Gradle não sabe como mesclar os fornecedores de conteúdos ter o mesmo nome, mas uma autoridade diferente.

Finalmente podemos precisar de ter acesso à autoridade do Código. Isso pode ser feito facilmente usando o arquivo BuildConfig e o método buildConfig:
android {   
   // ...

    final PROVIDER_DEBUG = "com.cyrilmottier.android.app.debug.provider"
    final PROVIDER_RELEASE = "com.cyrilmottier.android.app.provider"

   buildTypes {
       debug {
           // ...
           buildConfigField "String", "PROVIDER_AUTHORITY", PROVIDER_DEBUG
       }

       release {
           buildConfigField "String", "PROVIDER_AUTHORITY", PROVIDER_RELEASE
       }
   }
}
Graças a este trabalho vais poder usar o BuildConfig.PROVIDER_AUTHORITY no seu ProviderContract e instalar duas versões diferentes do seu aplicativo ao mesmo tempo.

Originaly no Google+: https://plus.google.com/u/0/118417777153109946393/posts/EATUmhntaCQ

 38
Author: Cyril Mottier, 2014-07-25 09:23:57

Enquanto o exemplo de Cyril funciona muito bem se você só tem alguns tipos de construção, rapidamente se torna complicado se você tem muitos tipos de construção e/ou sabores de produto como você precisa para manter muitos diferentes AndroidManifest.xml.

Nosso projeto consiste em 3 diferentes tipos de construção e 6 sabores totalizando 18 variantes de construção, então em vez disso adicionamos suporte para".res-auto " em autoridades fornecedoras de conteúdos, que se expandem para o actual nome de packagename e removem a necessidade de manter diferentes AndroidManifest.xml

/**
 * Version 1.1.
 *
 * Add support for installing multiple variants of the same app which have a
 * content provider. Do this by overriding occurrences of ".res-auto" in
 * android:authorities with the current package name (which should be unique)
 *
 * V1.0 : Initial version
 * V1.1 : Support for ".res-auto" in strings added, 
 *        eg. use "<string name="auth">.res-auto.path.to.provider</string>"
 *
 */
def overrideProviderAuthority(buildVariant) {
    def flavor = buildVariant.productFlavors.get(0).name
    def buildType = buildVariant.buildType.name
    def pathToManifest = "${buildDir}/manifests/${flavor}/${buildType}/AndroidManifest.xml"

    def ns = new groovy.xml.Namespace("http://schemas.android.com/apk/res/android", "android")
    def xml = new XmlParser().parse(pathToManifest)
    def variantPackageName = xml.@package

    // Update all content providers
    xml.application.provider.each { provider ->
        def newAuthorities = provider.attribute(ns.authorities).replaceAll('.res-auto', variantPackageName)
        provider.attributes().put(ns.authorities, newAuthorities)
    }

    // Save modified AndroidManifest back into build dir
    saveXML(pathToManifest, xml)

    // Also make sure that all strings with ".res-auto" are expanded automagically
    def pathToValues = "${buildDir}/res/all/${flavor}/${buildType}/values/values.xml"
    xml = new XmlParser().parse(pathToValues)
    xml.findAll{it.name() == 'string'}.each{item ->
        if (!item.value().isEmpty() && item.value()[0].startsWith(".res-auto")) {
            item.value()[0] = item.value()[0].replace(".res-auto", variantPackageName)
        }
    }
    saveXML(pathToValues, xml)
}

def saveXML(pathToFile, xml) {
    def writer = new FileWriter(pathToFile)
    def printer = new XmlNodePrinter(new PrintWriter(writer))
    printer.preserveWhitespace = true
    printer.print(xml)
}

// Post processing of AndroidManifest.xml for supporting provider authorities
// across build variants.
android.applicationVariants.all { variant ->
    variant.processManifest.doLast {
        overrideProviderAuthority(variant)
    }
}

O código de exemplo pode ser encontrado aqui: https://gist.github.com/cmelchior/6988275

 23
Author: Christian Melchior, 2013-10-22 13:47:07

Dado que a versão do plugin 0.8. 3 (na verdade 0. 8. 1, mas não estava a funcionar correctamente), poderá definir os recursos dentro do ficheiro de compilação, para que esta possa ser uma solução mais limpa, porque não precisa de criar ficheiros de texto nem pastas adicionais de depuração/libertação.

Construir.enxada

android {
    buildTypes {
        debug{
            resValue "string", "authority", "com.yourpackage.debug.provider"
        }
        release {
            resValue "string", "authority", "com.yourpackage.provider"
        }
    }
}

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.yourpackage"
   android:versionCode="1"
   android:versionName="1">

   <application>

       <provider
           android:name=".provider.Provider1"
           android:authorities="@string/authority"
           android:exported="false" />

   </application>
</manifest>
 20
Author: rciovati, 2014-03-14 10:37:49
Não sei se alguém falou nisso. Na verdade, após o plugin android gradle 0.10+, a fusão Manifesto irá fornecer o suporte oficial para esta função: http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger

Em AndroidManifest.xml, você pode usar o ${packageName} assim:

<provider
    android:name=".provider.DatabasesProvider"
    android:authorities="${packageName}.databasesprovider"
    android:exported="true"
    android:multiprocess="true" />
E na tua Constituição.gradle você pode ter:
productFlavors {
    free {
        packageName "org.pkg1"
    }
    pro {
        packageName "org.pkg2"
    }
}

Ver exemplo completo aqui: https://code.google.com/p/anymemo/source/browse/AndroidManifest.xml#152

E aqui: https://code.google.com/p/anymemo/source/browse/build.gradle#41
 13
Author: Liberty, 2014-05-08 22:50:14

Usar ${applicationId} espaços em xml e BuildConfig.APPLICATION_ID em código.

Terá de extender o programa de compilação para activar substituições em ficheiros xml que não o manifesto. Você poderia usar um diretório de código por variante de compilação para fornecer diferentes versões dos arquivos xml, mas a manutenção se tornará complicada muito rapidamente.

AndroidManifest.xml

Pode usar a substituição do aplicadorid na caixa do manifesto. Declarar o seu fornecedor como isto:

<provider
    android:name=".provider.DatabaseProvider"
    android:authorities="${applicationId}.DatabaseProvider"
    android:exported="false" />

Repara na parte de ${applicationId}. Isto é substituído no tempo de construção com o aplicationid real para a variante de construção que está sendo construída.

Em código

O Seu Fornecedor precisa de construir a cadeia de autoridade em código. Ele pode usar a classe BuildConfig.

public class DatabaseContract {
    /** The authority for the database provider */
    public static final String AUTHORITY = BuildConfig.APPLICATION_ID + ".DatabaseProvider";
    // ...
}

Repara na parte de BuildConfig.APPLICATION_ID. É uma classe gerada com o aplicationid real para a variante de construção sendo construída.

Ficheiros Res/ xml / xml, por exemplo syncadapter.xml, accountauthenticator.xml

Se quiser usar um adaptador de sincronização, terá de fornecer meta-dados para o obturador de Conteúdo e Gestor de contas em ficheiros xml no directório res/xml/. O item de substituição do applicationId não é suportado aqui. Mas você pode estender o script de construção para hackeá-lo.

<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="${applicationId}"
    android:allowParallelSyncs="false"
    android:contentAuthority="${applicationId}.DatabaseProvider"
    android:isAlwaysSyncable="true"
    android:supportsUploading="true"
    android:userVisible="true" />

<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="${applicationId}"
    android:icon="@drawable/ic_launcher"
    android:label="@string/account_authenticator_label"
    android:smallIcon="@drawable/ic_launcher" />

De novo, note o ${applicationId}. Isso só funciona se você adicionar o script abaixo gradle para a raiz do seu módulo e aplicá-lo a partir de construir.gradle.

Construir.enxada

Aplica o programa de compilação extra da compilação do módulo.guião de gradle. Um bom lugar está abaixo do plugin Android gradle.

apply plugin: 'com.android.application'
apply from: './build-processApplicationId.gradle'

android {
    compileSdkVersion 21
    // etc.

Build-process applicationId.enxada

Abaixo está o código de trabalho para um programa de compilação res/xml/ substituição. Uma versão melhor documentada está disponível em github . Melhorias e extensões são bem-vindas.

def replace(File file, String target, String replacement) {
    def result = false;

    def reader = new FileReader(file)
    def lines = reader.readLines()
    reader.close()

    def writer = new FileWriter(file)
    lines.each { line ->
        String replacedLine = line.replace(target, replacement)
        writer.write(replacedLine)
        writer.write("\n")
        result = result || !replacedLine.equals(line)
    }
    writer.close()

    return result
}

def processXmlFile(File file, String applicationId) {
    if (replace(file, "\${applicationId}", applicationId)) {
        logger.info("Processed \${applicationId} in $file")
    }
}

def processXmlDir(File dir, String applicationId) {
    dir.list().each { entry ->
        File file = new File(dir, entry)
        if (file.isFile()) {
            processXmlFile(file, applicationId)
        }
    }
}

android.applicationVariants.all { variant ->
    variant.mergeResources.doLast {
        def applicationId = variant.mergedFlavor.applicationId + (variant.buildType.applicationIdSuffix == null ? "" : variant.buildType.applicationIdSuffix)
        def path = "${buildDir}/intermediates/res/${variant.dirName}/xml/"
        processXmlDir(new File(path), applicationId)
    }
}

Cordas.xml

Na minha opinião não há necessidade de adicionar suporte de substituição para os textos de recursos. Para o caso de uso acima, pelo menos não é necessário. No entanto, poderá alterar facilmente o programa para substituir não só as substituições no directório res/xml/, mas também no directório res/values/ directory.

 8
Author: Rob Meeuwisse, 2014-11-13 19:51:42
Prefiro uma mistura entre Cyril e rciovati. Eu acho que é mais simples, você só tem duas modificações.

O build.gradle parece:

android {
    ...
    productFlavors {
        production {
            packageName "package.name.production"
            resValue "string", "authority", "package.name.production.provider"
            buildConfigField "String", "AUTHORITY", "package.name.production.provider"
        }

        testing {
            packageName "package.name.debug"
            resValue "string", "authority", "package.name.debug.provider"
            buildConfigField "String", "AUTHORITY", "package.name.debug.provider"
        }
    }
    ...
}

E a AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="package.name" >

    <application
        ...>

        <provider android:name=".contentprovider.Provider" android:authorities="@string/authority" />

    </application>
</manifest>
 6
Author: icastell, 2014-07-25 10:33:01
Com base na amostra de @ChristianMelchior, aqui está a minha solução, que fixa duas questões nas soluções anteriores:
  • Soluções que mudam valores.o xml na pasta de compilação faz com que uma reconstrução completa dos recursos (incluindo o aapt de todos os itens desenhados)

  • Por uma razão desconhecida, o Intelij (e provavelmente o Android Studio) não processam os recursos de forma fiável, fazendo com que a compilação contenha o fornecedor {[[0]} não substituído autoridades

Esta nova solução faz as coisas mais à maneira de Gradle, criando uma nova tarefa e permite a compilação incremental, definindo ficheiros de entrada e saída.

  1. Criar um ficheiro (no exemplo que o pus numa pasta variants), formatado como um ficheiro xml de recurso, que contém recursos de texto. Estes serão reunidos nos recursos do aplicativo, e qualquer ocorrência de .res-auto nos valores será substituído pelo nome do pacote da variante, por exemplo <string name="search_provider">.res-auto.MySearchProvider</string>

  2. Adicione o arquivo build_extras.gradle de Este gist ao seu projeto e faça referência a ele do principal build.gradle adicionando apply from: './build_extras.gradle' em algum lugar acima do bloco android

  3. Certifique-se que define um nome de pacote por omissão, adicionando-o ao bloco android.defaultConfig de build.gradle

  4. Em AndroidManifest.xml e outros ficheiros de configuração (como xml/searchable.xml para fornecedores de pesquisa de completação automática), consulte o fornecedor (por exemplo @string/search_provider)

  5. Se precisares de ter o mesmo nome, você pode usar a variável BuildConfig.PACKAGE_NAME, por exemplo BuildConfig.PACKAGE_NAME + ".MySearchProvider"

Https://gist.github.com/paour/9189462


Atualização: este método só funciona no Android 2.2.1 e mais tarde. Para plataformas anteriores, Ver esta resposta, que tem o seu próprio conjunto de problemas, uma vez que a nova fusão manifesta ainda é muito áspera em torno das bordas…
 4
Author: Pierre-Luc Paour, 2017-05-23 10:31:11
Gradle.build
android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    defaultConfig {
        applicationId "com.example.awsomeapp"
        minSdkVersion 9
        targetSdkVersion 23
        versionCode 1
        versionName "1.0.0"
    }

    productFlavors
    {
        prod {
            applicationId = "com.example.awsomeapp"
        }

        demo {
            applicationId = "com.example.awsomeapp.demo"
            versionName = defaultConfig.versionName + ".DEMO"
        }
    }

    buildTypes {
        release {
            signingConfig signingConfigs.release
            debuggable false
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }

        debug {
            applicationIdSuffix ".debug"
            versionNameSuffix = ".DEBUG"
            debuggable true
        }
    }

    applicationVariants.all { variant ->
        variant.outputs.each { output ->
            // rename the apk
            def file = output.outputFile;
            def newName;
            newName = file.name.replace(".apk", "-" + defaultConfig.versionName + ".apk");
            newName = newName.replace(project.name, "awsomeapp");
            output.outputFile = new File(file.parent, newName);
        }

        //Generate values Content Authority and Account Type used in Sync Adapter, Content Provider, Authenticator
        def valueAccountType = applicationId + '.account'
        def valueContentAuthority = applicationId + '.authority'

        //generate fields in Resource string file generated.xml
        resValue "string", "content_authority", valueContentAuthority
        resValue "string", "account_type", valueAccountType

        //generate fields in BuildConfig class
        buildConfigField "String", "ACCOUNT_TYPE", '"'+valueAccountType+'"'
        buildConfigField "String", "CONTENT_AUTHORITY", '"'+valueContentAuthority+'"'

        //replace field ${valueContentAuthority} in AndroidManifest.xml
        mergedFlavor.manifestPlaceholders = [ valueContentAuthority: valueContentAuthority ]
    }
}

Autenticador.xml

<?xml version="1.0" encoding="utf-8"?>
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
    android:accountType="@string/account_type"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:smallIcon="@drawable/ic_launcher" />

Sync_adapter.xml

<?xml version="1.0" encoding="utf-8"?>
<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
              android:contentAuthority="@string/content_authority"
              android:accountType="@string/account_type"
              android:userVisible="true"
              android:allowParallelSyncs="false"
              android:isAlwaysSyncable="true"
              android:supportsUploading="true"/>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0.0" package="com.example.awsomeapp">

    <uses-permission android:name="android.permission.GET_ACCOUNTS"/><!-- SyncAdapter and GCM requires a Google account. -->
    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"/>
    <uses-permission android:name="android.permission.USE_CREDENTIALS"/>

    <!-- GCM Creates a custom permission so only this app can receive its messages. -->
    <permission android:name="${applicationId}.permission.C2D_MESSAGE" android:protectionLevel="signature"/>
    <uses-permission android:name="${applicationId}.permission.C2D_MESSAGE"/>

    <application....
    .......

        <!-- Stub Authenticator --> 
        <service 
                android:name="com.example.awsomeapp.service.authenticator.CAuthenticatorService"
                android:exported="true">
            <intent-filter>
                <action android:name="android.accounts.AccountAuthenticator"/>
            </intent-filter>
            <meta-data android:name="android.accounts.AccountAuthenticator" android:resource="@xml/authenticator"/>
        </service>
        <!--  -->

        <!-- Sync Adapter -->
        <service
                android:name="com.example.awsomeapp.service.sync.CSyncService"
                android:exported="true"
                android:process=":sync">
            <intent-filter>
                <action android:name="android.content.SyncAdapter"/>
            </intent-filter>
            <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/sync_adapter" />
        </service>
        <!--  -->

        <!-- Content Provider -->
        <provider android:authorities="${valueContentAuthority}"
            android:exported="false" 
            android:name="com.example.awsomeapp.database.contentprovider.CProvider">
        </provider>
        <!--  --> 
    </application>
</manifest>

Código:

public static final String CONTENT_AUTHORITY = BuildConfig.CONTENT_AUTHORITY;
public static final String ACCOUNT_TYPE = BuildConfig.ACCOUNT_TYPE;
 4
Author: maros136, 2015-11-06 17:16:35
[[1]} eu escrevi um blogpost com o GitHub sample project que aborda este problema (e outros problemas semelhantes) de uma forma ligeiramente diferente do Cyril. {[[2]}

Http://brad-android.blogspot.com/2013/08/android-gradle-building-unique-build.html

 3
Author: icecreamman, 2013-08-27 18:57:03

Infelizmente, a versão atual (0.4.1) do plugin android não parece fornecer uma boa solução para isso. Ainda não tive tempo de tentar isto, mas uma possível solução para este problema seria usar um recurso de string @string/provider_authority, e usar isso no manifesto: android:authority="@string/provider_authority". Você então tem um res/values/provider.xml na pasta res de cada tipo de compilação que deve sobrepor a autoridade, no seu caso este seria src/debug/res

Investiguei a geração do ficheiro xml no momento, mas outra vez, lá ... não parece ser nenhum hooks bom para ele na versão atual do plugin. Eu recomendaria colocar um pedido de recurso embora, eu posso imaginar que mais pessoas vão encontrar este mesmo problema.
 2
Author: Marcus Forsell Stahre, 2013-05-28 12:42:01

A resposta neste post funciona para mim.

Http://www.kevinrschultz.com/blog/2014/03/23/using-android-content-providers-with-multiple-package-names/

Uso 3 sabores diferentes, por isso crio 3 manifestos com fornecedores de conteúdo em cada sabor, como disse o kevinrschultz:
productFlavors {
    free {
        packageName "your.package.name.free"
    }

    paid {
        packageName "your.package.name.paid"
    }

    other {
        packageName "your.package.name.other"
    }
}

O seu manifesto principal não inclui fornecedores:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<!-- Permissions -->
<application>
    <!-- Nothing about Content Providers at all -->
    <!-- Activities -->
    ...
    <!-- Services -->
    ...
</application>

E o seu manifesto em cada sabor, incluindo fornecedor.

Livre:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<application>
    <!-- Content Providers -->
    <provider
        android:name="your.package.name.Provider"
        android:authorities="your.package.name.free"
        android:exported="false" >
    </provider>
</application>
</manifest>

Pago:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<application>
    <!-- Content Providers -->
    <provider
        android:name="your.package.name.Provider"
        android:authorities="your.package.name.paid"
        android:exported="false" >
    </provider>
</application>
</manifest>

Outros:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" >
<application>
    <!-- Content Providers -->
    <provider
        android:name="your.package.name.Provider"
        android:authorities="your.package.name.other"
        android:exported="false" >
    </provider>
</application>
</manifest>
 2
Author: jcmore2, 2014-12-05 11:56:18
Porque não adicionar isto?

Tipo.packageNameSuffix =". $type.name "

 0
Author: guydemossyrock, 2014-02-14 12:40:27

A minha solução é usar substituição de substituição em AndroidManifest.xml. Ele também lida com packageNameSuffix Atributos para que você possa ter debug e release, bem como qualquer outra compilação personalizada sobre o mesmo dispositivo.

applicationVariants.all { variant ->
    def flavor = variant.productFlavors.get(0)
    def buildType = variant.buildType
    variant.processManifest.doLast {
        println '################# Adding Package Names to Manifest #######################'
        replaceInManifest(variant,
            'PACKAGE_NAME',
            [flavor.packageName, buildType.packageNameSuffix].findAll().join()) // ignores null
    }
}

def replaceInManifest(variant, fromString, toString) {
    def flavor = variant.productFlavors.get(0)
    def buildtype = variant.buildType
    def manifestFile = "$buildDir/manifests/${flavor.name}/${buildtype.name}/AndroidManifest.xml"
    def updatedContent = new File(manifestFile).getText('UTF-8').replaceAll(fromString, toString)
    new File(manifestFile).write(updatedContent, 'UTF-8')
}
Tenho-o em cima de um ... gist também se quiser ver se evolui mais tarde. Achei que era uma abordagem mais elegante do que os vários recursos e as abordagens de análise XML.
 0
Author: Saad Farooq, 2014-04-04 02:53:25