Configuré Gradle para agregar el sufijo del nombre del paquete a mi aplicación de depuración para poder lanzar la versión que estoy usando y la versión de depuración en un teléfono. Estaba haciendo referencia a esto: http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Types
Mi archivo build.gradle se ve así:
...
android
{
...
buildTypes
{
debug
{
packageNameSuffix ".debug"
versionNameSuffix " debug"
}
}
}
Todo funciona bien hasta que empiezo a usar un ContentProvider en mi aplicación. Yo obtengo:
Failure [INSTALL_FAILED_CONFLICTING_PROVIDER]
Entiendo que esto sucede porque dos aplicaciones (lanzamiento y depuración) están registrando la misma autoridad de ContentProvider.
Veo una posibilidad para resolver esto. Si entiendo correctamente, deberías poder especificar diferentes archivos para usar cuando construyas. Entonces debería poder poner diferentes autoridades en diferentes archivos de recursos (y desde Manifest establecer la autoridad como recurso de cadena) y decirle a Gradle que use diferentes recursos para la compilación de depuración. ¿Es eso posible? En caso afirmativo, ¡cualquier sugerencia sobre cómo lograrlo sería increíble!
¿O tal vez es posible modificar directamente el Manifiesto usando Gradle? Cualquier otra solución sobre cómo ejecutar la misma aplicación con ContentProvider en un dispositivo siempre es bienvenida.
Respuestas:
Ninguna de las respuestas existentes me satisfizo, sin embargo, Liberty estaba cerca. Así es como lo estoy haciendo. En primer lugar, en este momento estoy trabajando con:
Mi objetivo es ejecutar la
Debug
versión junto con laRelease
versión en el mismo dispositivo usando el mismoContentProvider
.En build.gradle del sufijo del conjunto de aplicaciones para la compilación de depuración:
En la propiedad de conjunto de archivos AndroidManifest.xml
android:authorities
de suContentProvider
:En su propiedad de conjunto de códigos
AUTHORITY
que se puede usar donde sea necesario en su implementación:Consejo: Antes era
BuildConfig.PACKAGE_NAME
¡Eso es! Funcionará como un encanto. ¡Sigue leyendo si usas SyncAdapter!
Actualización para SyncAdapter (14.11.2014)
Una vez más, comenzaré con mi configuración actual:
Básicamente, si necesita personalizar algunos valores para diferentes compilaciones, puede hacerlo desde el archivo build.gradle:
BuildConfig.java
claseComo alternativa para los recursos, puede crear directorios buildType o de sabor separados y anular XML o valores dentro de ellos. Sin embargo, no lo voy a usar en el siguiente ejemplo.
Ejemplo
En el archivo build.gradle agregue lo siguiente:
Verá resultados en la clase BuildConfig.java
y en build / generate / res / generate / debug / values / generate.xml
En su authenticator.xml use el recurso especificado en el archivo build.gradle
En su syncadapter.xml use el mismo recurso nuevamente y @ string / autoridades también
Consejo: el autocompletado (Ctrl + Espacio) no funciona para estos recursos generados, por lo que debe escribirlos manualmente
fuente
Nuevo consejo de sistema de compilación de Android: cambio de nombre de autoridad ContentProvider
Supongo que todos ustedes han oído hablar del nuevo sistema de compilación basado en Android Gradle. Seamos honestos, este nuevo sistema de construcción es un gran paso adelante en comparación con el anterior. Todavía no es definitivo (a partir de este escrito, la última versión es 0.4.2) pero ya puede usarlo de manera segura en la mayoría de sus proyectos.
Personalmente, cambié la mayor parte de mi proyecto a este nuevo sistema de compilación y tuve algunos problemas debido a la falta de soporte en algunas situaciones particulares. Uno de los cuales es el soporte para el cambio de nombre de autoridad ContentProvider
El nuevo sistema integrado de Android le permite lidiar con diferentes tipos de su aplicación simplemente modificando el nombre del paquete en el momento de la compilación. Una de las principales ventajas de esta mejora es que ahora puede tener dos versiones diferentes de su aplicación instaladas en el mismo dispositivo al mismo tiempo. Por ejemplo:
Utilizando dicha configuración de Gradle, puede ensamblar dos APK diferentes:
• Un APK de depuración con el nombre del paquete com.cyrilmottier.android.app.debug • Un APK de lanzamiento con el nombre del paquete com.cyrilmottier.android.app
El único problema con eso es que no podrá instalar los dos APK al mismo tiempo si ambos exponen un ContentProvider con las mismas autoridades. Lógicamente, necesitamos cambiar el nombre de la autoridad según el tipo de compilación actual ... pero esto no es compatible con el sistema de compilación de Gradle (¿todavía? ... estoy seguro de que se solucionará pronto). Así que aquí hay un camino a seguir:
Primero, debemos mover la declaración ContentProvider del manifiesto de Android del proveedor al tipo de compilación apropiado. Para hacer eso simplemente tendremos:
src / debug / AndroidManifest.xml
src / release / AndroidManifest.xml
Asegúrese de eliminar la declaración ContentProvider del AndroidManifest.xml en src / main / porque Gradle no sabe cómo fusionar ContentProviders con el mismo nombre pero con una autoridad diferente.
Finalmente, es posible que necesitemos acceder a la autoridad en el código. Esto se puede hacer fácilmente usando el archivo BuildConfig y el método buildConfig:
Gracias a esta solución, podrá usar BuildConfig.PROVIDER_AUTHORITY en su ProviderContract e instalar dos versiones diferentes de su aplicación al mismo tiempo.
Originalmente en Google+: https://plus.google.com/u/0/118417777153109946393/posts/EATUmhntaCQ
fuente
Si bien el ejemplo de Cyril funciona muy bien si solo tiene unos pocos tipos de compilación, se complica rápidamente si tiene muchos tipos de compilación y / o sabores de productos, ya que necesita mantener muchos AndroidManifest.xml diferentes.
Nuestro proyecto consta de 3 tipos de compilación diferentes y 6 sabores con un total de 18 variantes de compilación, por lo que agregamos soporte para ".res-auto" en las autoridades de ContentProvider, que se expanden al nombre del paquete actual y eliminan la necesidad de mantener diferentes AndroidManifest.xml
El código de ejemplo se puede encontrar aquí: https://gist.github.com/cmelchior/6988275
fuente
Desde la versión del complemento 0.8.3 (en realidad 0.8.1 pero no funcionaba correctamente), puede definir recursos dentro del archivo de compilación, por lo que podría ser una solución más limpia porque no necesita crear archivos de cadenas ni depuración / lanzamiento adicional carpetas
build.gradle
AndroidManifest.xml
fuente
No sé si alguien lo menciona. En realidad, después del complemento Android Gradle 0.10+, la fusión de manifiesto proporcionará el soporte oficial para esta función: http://tools.android.com/tech-docs/new-build-system/user-guide/manifest-merger
En AndroidManifest.xml, puede usar $ {packageName} de esta manera:
Y en su build.gradle puede tener:
Vea el ejemplo completo aquí: https://code.google.com/p/anymemo/source/browse/AndroidManifest.xml#152
y aquí: https://code.google.com/p/anymemo/source/browse/build.gradle#41
fuente
Use
${applicationId}
marcadores de posición en xml yBuildConfig.APPLICATION_ID
en código.Deberá extender el script de compilación para habilitar marcadores de posición en archivos xml que no sean el manifiesto. Puede usar un directorio de origen por variante de compilación para proporcionar diferentes versiones de los archivos xml, pero el mantenimiento se volverá engorroso muy rápidamente.
AndroidManifest.xml
Puede usar el marcador de posición applicationId de fábrica en el manifiesto. Declare así a su proveedor:
Tenga en cuenta el
${applicationId}
bit. Esto se reemplaza en el momento de la compilación con el ID de aplicación real para la variante de compilación que se está construyendo.En codigo
Su ContentProvider necesita construir la cadena de autoridad en el código. Puede usar la clase BuildConfig.
Tenga en cuenta el
BuildConfig.APPLICATION_ID
bit. Es una clase generada con el ID de aplicación real para la variante de compilación que se está construyendo.res / xml / files, por ejemplo, syncadapter.xml, accountauthenticator.xml
Si desea utilizar un adaptador de sincronización, deberá proporcionar metadatos para ContentProvider y AccountManager en archivos xml en el directorio res / xml /. El marcador de posición applicationId no es compatible aquí. Pero puede extender el script de compilación usted mismo para hackearlo.
De nuevo, tenga en cuenta el
${applicationId}
. Esto solo funciona si agrega la secuencia de comandos de Gradle a la raíz de su módulo y la aplica desde build.gradle.build.gradle
Aplique el script de compilación adicional desde el script del módulo build.gradle. Un buen lugar está debajo del complemento de gradle de Android.
build-processApplicationId.gradle
A continuación se muestra la fuente de trabajo para un script de compilación res / xml / placeholder. Una versión mejor documentada está disponible en github . Las mejoras y extensiones son bienvenidas.
Strings.xml
En mi opinión, no es necesario agregar soporte de marcador de posición para las cadenas de recursos. Para el caso de uso anterior, al menos no es necesario. Sin embargo, podría cambiar fácilmente el script para reemplazar no solo los marcadores de posición en el directorio res / xml /, sino también en el directorio res / values /.
fuente
Prefiero una mezcla entre Cyril y rciovati. Creo que es más simple, solo tienes dos modificaciones.
El se
build.gradle
parece a:Y el
AndroidManifest.xml
:fuente
gradle.build
authenticator.xml
sync_adapter.xml
AndroidManifest.xml
Código:
fuente
Basado en la muestra de @ChristianMelchior, aquí está mi solución, que soluciona dos problemas en las soluciones anteriores:
Las soluciones que cambian values.xml en el directorio de compilación provocan una reconstrucción completa de los recursos (incluido un conjunto de todos los elementos extraíbles)
por una razón desconocida, IntelliJ (y probablemente Android Studio) no procesan de manera confiable los recursos, lo que hace que la compilación contenga
.res-auto
autoridades de proveedor no reemplazadasEsta nueva solución hace las cosas más a la manera de Gradle al crear una nueva tarea y permite compilaciones incrementales al definir archivos de entrada y salida.
crear un archivo (en el ejemplo lo puse en un
variants
directorio), formateado como un archivo xml de recursos, que contiene recursos de cadena. Estos se fusionarán en los recursos de la aplicación, y cualquier aparición.res-auto
en los valores se reemplazará con el nombre del paquete de la variante, por ejemplo<string name="search_provider">.res-auto.MySearchProvider</string>
agregue el
build_extras.gradle
archivo de esta esencia a su proyecto y haga referencia desde el principalbuild.gradle
agregando enapply from: './build_extras.gradle'
algún lugar sobre elandroid
bloqueasegúrese de establecer un nombre de paquete predeterminado agregándolo al
android.defaultConfig
bloque debuild.gradle
en
AndroidManifest.xml
y otros archivos de configuración (comoxml/searchable.xml
para proveedores de búsqueda de autocompletado), haga referencia al proveedor (por ejemplo@string/search_provider
)si necesita obtener el mismo nombre, puede usar la
BuildConfig.PACKAGE_NAME
variable, por ejemploBuildConfig.PACKAGE_NAME + ".MySearchProvider"
https://gist.github.com/paour/9189462
Actualización: este método solo funciona en Android 2.2.1 y versiones posteriores. Para plataformas anteriores, vea esta respuesta , que tiene su propio conjunto de problemas, ya que la nueva fusión de manifiesto aún es muy aproximada ...
fuente
variants/res-auto-values.xml
relación con/Applications/Android Studio.app/bin/
. es decir, no recibo FileNotFoundException para/Applications/Android Studio.app/bin/variants/res-auto-values.xml
. Estoy corriendo en una Mac. Esta es una gran solución, pero me encantaría que funcione en el IDE para los otros miembros del equipo.System.getProperty("user.dir")
, lo que devuelve un resultado diferente cuando se invoca por la compilación de Android Studio. La solución es usar la ruta relativa al directorio del proyecto, que se devuelve congradle.startParameter.getProjectDir()
. Vea mi comentario en la esencia vinculada de Paour también.He escrito una publicación de blog con el proyecto de muestra de Github que aborda este problema (y otros problemas similares) de una manera ligeramente diferente a la de Cyril.
http://brad-android.blogspot.com/2013/08/android-gradle-building-unique-build.html
fuente
Desafortunadamente, la versión actual (0.4.1) del complemento de Android no parece proporcionar una buena solución para esto. No he tenido tiempo para probar esto todavía, pero una posible solución a este problema sería el uso de un recurso de cadena
@string/provider_authority
, y el uso que en el manifiesto:android:authority="@string/provider_authority"
. Luego tiene unres/values/provider.xml
en la carpeta res de cada tipo de compilación que debería anular la autoridad, en su caso esto seríasrc/debug/res
He investigado la posibilidad de generar el archivo xml sobre la marcha, pero de nuevo, no parece haber buenos enganches en la versión actual del complemento. Sin embargo, recomiendo poner una solicitud de función, puedo imaginar que más personas se encontrarán con este mismo problema.
fuente
La respuesta en esta publicación me funciona.
http://www.kevinrschultz.com/blog/2014/03/23/using-android-content-providers-with-multiple-package-names/
Utilizo 3 sabores diferentes, así que creo 3 manifiestos con el proveedor de contenido en cada sabor, como dijo kevinrschultz:
Su manifiesto principal no incluye proveedores:
Y su manifiesto en cada sabor, incluido el proveedor.
Gratis:
Pagado:
Otro:
fuente
¿Por qué no solo agregar esto?
fuente
Mi solución es usar el reemplazo de marcador de posición en
AndroidManifest.xml
. También manejapackageNameSuffix
atributos para que pueda tenerdebug
yrelease
también cualquier otra compilación personalizada en el mismo dispositivo.Lo tengo en un
gist
si quieres ver si evoluciona más tarde.Me pareció un enfoque más elegante que los múltiples recursos y los enfoques de análisis XML.
fuente