Eu configurei o Gradle para adicionar o sufixo do nome do pacote ao meu aplicativo de depuração para que eu pudesse ter a versão de lançamento que estou usando e a versão de depuração em um telefone. Eu estava fazendo referência a isso: http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Types
Meu arquivo build.gradle fica assim:
...
android
{
...
buildTypes
{
debug
{
packageNameSuffix ".debug"
versionNameSuffix " debug"
}
}
}
Tudo funciona bem até eu começar a usar um ContentProvider no meu aplicativo. Eu recebo:
Failure [INSTALL_FAILED_CONFLICTING_PROVIDER]
Entendo que isso acontece porque dois aplicativos (versão e depuração) estão registrando a mesma autoridade do ContentProvider.
Eu vejo uma possibilidade de resolver isso. Se bem entendi, você poderá especificar arquivos diferentes para usar na criação. Então eu devo poder colocar autoridades diferentes em arquivos de recursos diferentes (e do Manifest Set Authority como recurso de string) e dizer ao Gradle para usar recursos diferentes para a compilação de depuração. Isso é possível? Se sim, qualquer dica sobre como conseguir isso seria incrível!
Ou talvez seja possível modificar diretamente o Manifest usando Gradle? Qualquer outra solução sobre como executar o mesmo aplicativo com o ContentProvider em um dispositivo é sempre bem-vinda.
Respostas:
Nenhuma das respostas existentes me satisfez, no entanto, a liberdade estava próxima. Então é assim que eu estou fazendo isso. Primeiro de tudo no momento em que estou trabalhando:
Meu objetivo é executar a
Debug
versão juntamente com aRelease
versão no mesmo dispositivo, usando o mesmoContentProvider
.No build.gradle do seu conjunto de aplicativos, sufixo para a compilação Debug:
Na propriedade do conjunto de arquivos AndroidManifest.xml :
android:authorities
ContentProvider
Na propriedade do conjunto de códigos
AUTHORITY
que pode ser usada sempre que necessário em sua implementação:Dica: antes de ser
BuildConfig.PACKAGE_NAME
É isso aí! Funcionará como um encanto. Continue lendo se você usar o SyncAdapter!
Atualização para SyncAdapter (14.11.2014)
Mais uma vez, começarei com minha configuração atual:
Basicamente, se você precisar personalizar alguns valores para diferentes construções, poderá fazê-lo no arquivo build.gradle:
BuildConfig.java
classeComo alternativa aos recursos, você pode criar diretórios buildType ou flavor separados e substituir XMLs ou valores dentro deles. No entanto, não vou usá-lo no exemplo abaixo.
Exemplo
No arquivo build.gradle, adicione o seguinte:
Você verá resultados na classe BuildConfig.java
e em build / gerados / res / gerados / depuração / valores / gerados.xml
No seu authenticator.xml, use o recurso especificado no arquivo build.gradle
No syncadapter.xml, use o mesmo recurso novamente e @ string / autoridades também
Dica: o preenchimento automático (Ctrl + Espaço) não funciona para esses recursos gerados, portanto, você deve digitá-los manualmente
fonte
Nova dica do sistema de compilação do Android: renomeação da autoridade ContentProvider
Acho que todos vocês já ouviram falar do novo sistema de compilação baseado no Android Gradle. Sejamos honestos, este novo sistema de compilação é um grande passo à frente em comparação com o anterior. Ainda não é final (até o momento em que este artigo foi escrito, a versão mais recente é 0.4.2), mas você já pode usá-lo com segurança na maioria dos seus projetos.
Pessoalmente, mudei a maior parte do meu projeto para esse novo sistema de compilação e tive alguns problemas devido à falta de suporte em algumas situações específicas. Um deles é o suporte à renomeação da autoridade ContentProvider
O novo sistema criado para Android permite lidar com diferentes tipos de aplicativo, modificando o nome do pacote no momento da criação. Uma das principais vantagens dessa melhoria é que agora você pode ter duas versões diferentes do seu aplicativo instaladas no mesmo dispositivo ao mesmo tempo. Por exemplo:
Usando essa configuração Gradle, você pode montar dois APKs diferentes:
• Um APK de depuração com o nome do pacote com.cyrilmottier.android.app.debug • Um APK de lançamento com o nome do pacote com.cyrilmottier.android.app
O único problema é que você não poderá instalar os dois APKs ao mesmo tempo se ambos expuserem um ContentProvider com as mesmas autoridades. Logicamente, precisamos renomear a autoridade, dependendo do tipo de compilação atual ... mas isso não é suportado pelo sistema de compilação Gradle (ainda? ... Tenho certeza que será corrigido em breve). Então, aqui está um caminho a percorrer:
Primeiro, precisamos mover a declaração ContentProvider do manifesto Android do provedor para o tipo de construção apropriado. Para fazer isso, teremos simplesmente:
src / debug / AndroidManifest.xml
src / release / AndroidManifest.xml
Certifique-se de remover a declaração ContentProvider do AndroidManifest.xml em src / main / porque Gradle não sabe como mesclar ContentProviders com o mesmo nome, mas com uma autoridade diferente.
Finalmente, podemos precisar acessar a autoridade no código. Isso pode ser feito facilmente usando o arquivo BuildConfig e o método buildConfig:
Graças a esta solução alternativa, você poderá usar o BuildConfig.PROVIDER_AUTHORITY no seu ProviderContract e instalar duas versões diferentes do seu aplicativo ao mesmo tempo.
Originalmente no Google+: https://plus.google.com/u/0/118417777153109946393/posts/EATUmhntaCQ
fonte
Embora o exemplo de Cyril funcione muito bem se você tiver apenas alguns tipos de compilação, fica rapidamente complicado se você tiver muitos tipos de compilação e / ou sabores de produtos, pois precisará manter muitos AndroidManifest.xml diferentes.
Nosso projeto consiste em 3 tipos de compilação diferentes e 6 tipos, totalizando 18 variantes de compilação. Em vez disso, adicionamos suporte para ".res-auto" nas autoridades ContentProvider, que se expandem para o nome do pacote atual e eliminam a necessidade de manter AndroidManifest.xml diferente
O código de exemplo pode ser encontrado aqui: https://gist.github.com/cmelchior/6988275
fonte
Desde a versão 0.8.3 do plug-in (na verdade, 0.8.1, mas não estava funcionando corretamente), é possível definir recursos no arquivo de construção para que esta seja uma solução mais limpa, pois você não precisa criar arquivos de strings nem depuração / liberação adicional pastas
build.gradle
AndroidManifest.xml
fonte
Não sei se alguém mencionou. Na verdade, após o plug-in Android Gradle 0.10+, a fusão do manifesto fornecerá o suporte oficial para esta função: http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger
No AndroidManifest.xml, você pode usar $ {packageName} assim:
E no seu build.gradle você pode ter:
Veja o 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
fonte
Use
${applicationId}
espaços reservados no xml eBuildConfig.APPLICATION_ID
no código.Você precisará estender o script de construção para habilitar espaços reservados em arquivos xml diferentes do manifesto. Você pode usar um diretório de origem por variante de compilação para fornecer versões diferentes dos arquivos xml, mas a manutenção se tornará complicada muito rapidamente.
AndroidManifest.xml
Você pode usar o espaço reservado applicationId fora da caixa no manifesto. Declare seu provedor assim:
Observe o
${applicationId}
bit. Isso é substituído no momento da construção pelo applicationId real da variante de construção que está sendo construída.Em código
Seu ContentProvider precisa construir a cadeia de autoridade no código. Pode usar a classe BuildConfig.
Observe o
BuildConfig.APPLICATION_ID
bit. É uma classe gerada com o applicationId real para a variante de compilação que está sendo construída.res / xml / files, por exemplo, syncadapter.xml, accountauthenticator.xml
Se você deseja usar um adaptador de sincronização, precisará fornecer metadados para o ContentProvider e o AccountManager em arquivos xml no diretório res / xml /. O espaço reservado applicationId não é suportado aqui. Mas você pode estender o script de construção para invadir.
Mais uma vez, observe o
${applicationId}
. Isso funciona apenas se você adicionar o script gradle abaixo à raiz do seu módulo e aplicá-lo em build.gradle.build.gradle
Aplique o script de construção extra no módulo build.gradle script. Um bom lugar é abaixo do plug-in Android gradle.
build-processApplicationId.gradle
Abaixo está a fonte de trabalho para um script de construção res / xml / placeholder. Uma versão melhor documentada está disponível no github . Melhorias e extensões são bem-vindas.
Strings.xml
Na minha opinião, não há necessidade de adicionar suporte de espaço reservado para cadeias de recursos. Para o caso de uso acima, pelo menos, não é necessário. No entanto, você pode alterar facilmente o script, não apenas substituindo espaços reservados no diretório res / xml /, mas também no diretório res / values /.
fonte
Prefiro uma mistura entre Cyril e rciovati. Eu acho que é mais simples, você só tem duas modificações.
Os
build.gradle
parece:E o
AndroidManifest.xml
:fonte
gradle.build
authenticator.xml
sync_adapter.xml
AndroidManifest.xml
Código:
fonte
Com base no exemplo de @ChristianMelchior, aqui está minha solução, que corrige dois problemas nas soluções anteriores:
soluções que alteram values.xml no diretório build causam uma reconstrução completa dos recursos (incluindo aapt de todos os drawables)
por um motivo desconhecido, o IntelliJ (e provavelmente o Android Studio) não processa os recursos de maneira confiável, fazendo com que a construção contenha
.res-auto
autoridades do fornecedor não substituídasEssa nova solução faz as coisas da maneira Gradle, criando uma nova tarefa e permite construções incrementais, definindo arquivos de entrada e saída.
crie um arquivo (no exemplo, coloquei-o em um
variants
diretório), formatado como um arquivo xml de recurso, que contém recursos de string. Eles serão mesclados aos recursos do aplicativo e qualquer ocorrência.res-auto
nos valores será substituída pelo nome do pacote da variante, por exemplo<string name="search_provider">.res-auto.MySearchProvider</string>
adicione o
build_extras.gradle
arquivo dessa essência ao seu projeto e faça referência a ele do principalbuild.gradle
adicionandoapply from: './build_extras.gradle'
algum lugar acima doandroid
blococertifique-se de definir um nome de pacote padrão adicionando-o ao
android.defaultConfig
bloco debuild.gradle
em
AndroidManifest.xml
e outros arquivos de configuração (comoxml/searchable.xml
para provedores de pesquisa de preenchimento automático), faça referência ao provedor (por exemplo@string/search_provider
)se você precisar obter o mesmo nome, poderá usar a
BuildConfig.PACKAGE_NAME
variável, por exemploBuildConfig.PACKAGE_NAME + ".MySearchProvider"
https://gist.github.com/paour/9189462
Atualização: esse método funciona apenas no Android 2.2.1 e posterior. Para plataformas anteriores, consulte esta resposta , que tem seu próprio conjunto de problemas, já que a nova fusão de manifestos ainda é muito difícil nas bordas…
fonte
variants/res-auto-values.xml
relação a/Applications/Android Studio.app/bin/
. ou seja, não recebo FileNotFoundException para/Applications/Android Studio.app/bin/variants/res-auto-values.xml
. Eu estou correndo em um mac. Essa é uma ótima solução, mas eu adoraria fazê-la funcionar no IDE para os outros membros da equipe.System.getProperty("user.dir")
, que retorna um resultado diferente quando chamado pela compilação do Android Studio. A solução é usar o caminho relativo ao diretório do projeto, retornado comgradle.startParameter.getProjectDir()
. Veja meu comentário na essência vinculada de Paour também.Eu escrevi um post no blog com o projeto de exemplo do Github que aborda esse problema (e outros problemas semelhantes) de uma maneira ligeiramente diferente da de Cyril.
http://brad-android.blogspot.com/2013/08/android-gradle-building-unique-build.html
fonte
Infelizmente, a versão atual (0.4.1) do plugin android não parece fornecer uma boa solução para isso. Eu não tive tempo para tentar isso ainda, mas uma possível solução para este problema seria a utilização de um recurso de cadeia
@string/provider_authority
, eo uso que no manifesto:android:authority="@string/provider_authority"
. Você tem umres/values/provider.xml
na pasta res de cada tipo de construção que deve substituir a autoridade; no seu caso, isso seriasrc/debug/res
Eu olhei para gerar o arquivo xml em tempo real, mas, novamente, não parece haver bons ganchos para ele na versão atual do plugin. Eu recomendaria fazer uma solicitação de recurso, no entanto, posso imaginar que mais pessoas irão encontrar esse mesmo problema.
fonte
A resposta neste post funciona para mim.
http://www.kevinrschultz.com/blog/2014/03/23/using-android-content-providers-with-multiple-package-names/
Eu uso 3 sabores diferentes, então crio 3 manifestos com o provedor de conteúdo em cada sabor, como disse kevinrschultz:
Seu principal manifesto não inclui provedores:
E seu manifesto em cada sabor, incluindo o provedor.
Livre:
Pago:
De outros:
fonte
Por que não apenas adicionar isso?
fonte
Minha solução é usar a substituição de espaço reservado no
AndroidManifest.xml
. Ele também lida compackageNameSuffix
atributos para que você possa terdebug
erelease
também qualquer outra compilação personalizada no mesmo dispositivo.Eu tenho isso em um
gist
se você quiser ver se ele evolui mais tarde.Eu achei uma abordagem mais elegante do que os vários recursos e abordagens de análise de XML.
fonte