studio proveedor programacion para móviles libro edición desarrollo curso contenido aplicaciones android android-contentprovider

android - programacion - Múltiples aplicaciones usan el mismo proveedor de contenido



programacion android pdf 2018 (5)

Estoy desarrollando un conjunto de aplicaciones que se distinguen solo en ciertas marcas (piense en diferentes equipos deportivos); sin embargo, me estoy topando con un problema en el que estoy usando un proyecto de Biblioteca para todas las aplicaciones de marca específica y quiero usar el mismo ContentProvider para todas ellas. Cuando creé el ContentProvider, declare AUTORIDAD como una constante en la clase (según el código de ejemplo dev) y estoy usando la misma autoridad en cada aplicación específica en los archivos de manifiesto. Parece que no puedo usar la misma autoridad en todas las aplicaciones, ya que recibo este error al intentar instalar una segunda aplicación (instalo una de marca muy bien, pero la segunda instalación):

WARN/PackageManager(66): Can''t install because provider name com.xxx.Provider (in package com.xxx) is already used by com.zzz

He intentado varios enfoques, pero ninguno de ellos parece funcionar. Una idea que aún no he hecho, fue crear un archivo jar de la biblioteca y simplemente omitir la clase Provider que tengo y personalizarla en cada aplicación específica. ¿Alguna idea sobre cómo solucionar este problema sin recurrir a eso?


¡USTED PUEDE!

Como se dijo en esta publicación (que explica cómo Firebase inicializa su biblioteca sin darle un contexto de su método Application#onCreate() ), puede usar un marcador de posición en su manifiesto, como este:

<provider android:authorities="${applicationId}.yourcontentprovider" android:name=".YourContentProvider" />


Digamos que su paquete de biblioteca es com.android.app.library paquete gratuito es com.android.app.free paquete de pago es com.android.app.paid

En su proyecto gratuito y en el proyecto de pago, cree un archivo idéntico en un paquete que puede ser cualquier cosa, pero debe ser el mismo.

Ejemplo:

  1. Cree un nuevo paquete en su versión gratuita con com.android.app.data

  2. Cree un archivo llamado Authority.java y dentro de (Authority.java) ponga:

    public class Authority {

    `public static final String CONTENT_AUTHORITY = "YOUR PROVIDER";`

    }

  3. Repita esto para la versión paga, recuerde mantener el nombre del paquete igual y el nombre de la clase.

Ahora, en su archivo de contrato, en su biblioteca, use lo siguiente:

public static String AUTHORITY = initAuthority(); private static String initAuthority() { String authority = "something.went.wrong.if.this.is.used"; try { ClassLoader loader = Contract.class.getClassLoader(); Class<?> clz = loader.loadClass("com.android.app.data.Authority"); Field declaredField = clz.getDeclaredField("CONTENT_AUTHORITY"); authority = declaredField.get(null).toString(); } catch (ClassNotFoundException e) {} catch (NoSuchFieldException e) {} catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } return authority; } public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);

Ahora deberías poder usar dos autoridades.

Crédito: Ian Warick (redacción del código) Android - Tener autoridad del proveedor en el proyecto de la aplicación Descargo de responsabilidad: Lo publiqué también aquí: Problema de autoridad del proveedor duplicado de Android - No estoy seguro de poder contestar el mismo tipo de pregunta con la misma respuesta.


Es una vieja pregunta, pero estaba pensando en hacer algo similar recientemente. Con los sabores Build, es realmente sencillo ahora.

Especifique el BuildConfigField en el archivo gradle:

productFlavors { free { applicationId "com.example.free" buildConfigField ''String'', ''AUTHORITY'', ''"com.example.free.contentprovider"'' } paid { applicationId "com.example.paid" buildConfigField ''String'', ''AUTHORITY'', ''"com.example.paid.contentprovider"'' }

Especifique la autoridad del proveedor en el manifiesto:

<provider android:name=".ContentProvider" android:authorities="${applicationId}.contentprovider" />

Establezca la autoridad en el proveedor utilizando la variable BuildConfigField:

public static final String AUTHORITY = BuildConfig.AUTHORITY


La siguiente forma se puede usar para empaquetar un ContentProvider dentro de una biblioteca y establecer la autoridad del ContentProvider en tiempo de ejecución, de modo que se pueda incluir en varios proyectos sin conflicto de ContentProvider Authority. Esto funciona porque la ''autoridad'' real proviene del AndroidManifest ... no de la clase ContentProvider.

Comience con la implementación básica de ContentProvider ... AUTHORITY, CONTENT_URI y UriMatcher son estáticos, pero no "finales" ...

public class MyContentProvider extends ContentProvider { public static String AUTHORITY = "com.foo.bar.content"; public static Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY); protected static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

Luego, anule el método ''attachInfo'', de modo que cuando se inicialice ContentProvider por primera vez, se llamará a su ContentProvider con el ProviderInfo recopilado de AndroidManifest. Esto ocurrirá ANTES de que se realicen las posibles consultas, muy probablemente durante la configuración inicial de la clase de aplicación. Aproveche esta oportunidad para restablecer los valores "reales" de AUTHORITY, CONTENT_URI y UriMatcher, según lo provisto por la aplicación que utiliza la biblioteca ContentProvider.

@Override public void attachInfo(Context context, ProviderInfo info) { super.attachInfo(context, info); AUTHORITY = info.authority; CONTENT_URI = Uri.parse("content://" + AUTHORITY); uriMatcher = new UriMatcher(UriMatcher.NO_MATCH); uriMatcher.addURI(AUTHORITY, AlarmTable.TABLENAME, ALARMS); uriMatcher.addURI(AUTHORITY, AttributeTable.TABLENAME, ATTRIBUTES); uriMatcher.addURI(AUTHORITY, DeepLinkTable.TABLENAME, DEEPLINKS); uriMatcher.addURI(AUTHORITY, NotificationTable.TABLENAME, NOTIFICATIONS); uriMatcher.addURI(AUTHORITY, MetaDataTable.TABLENAME, RESOURCE_METADATA); uriMatcher.addURI(AUTHORITY, ResourceTable.TABLENAME, RESOURCES); uriMatcher.addURI(AUTHORITY, ResourceAttributeTable.TABLENAME, RESOURCES_ATTRIBUTES); uriMatcher.addURI(AUTHORITY, ResourceTagTable.TABLENAME, RESOURCES_TAGS); uriMatcher.addURI(AUTHORITY, TagTable.TABLENAME, TAGS); uriMatcher.addURI(AUTHORITY, UserTagTable.TABLENAME, USER_TAGS); uriMatcher.addURI(AUTHORITY, UserTable.TABLENAME, USERS); uriMatcher.addURI(AUTHORITY, CUSTOM, RAW); }

Cuando se inicia la aplicación, ContentProvider se instancia realmente junto con la clase de la aplicación, por lo que tendrá acceso a toda la información del paquete requerido. el objeto ProviderInfo contendrá la información provista en AndroidManifest ... La lista que se incluye en la aplicación final.

<provider android:authorities="com.foo.barapp.content" android:name="com.foo.bar.MyContentProvider"/>

La Autoridad se reescribirá ahora con "com.foo.barapp.content" en lugar del valor predeterminado, y el UriMatcher se actualizará con el valor de la aplicación en lugar del valor predeterminado. Las clases que dependen de la "AUTORIDAD" ahora accederán al valor actualizado, y el UriMatcher distinguirá correctamente las consultas entrantes para el ''com.foo.barapp.content''.

Probé esto con una aplicación de muestra y un paquete androidTest simultáneamente y encontré que funcionaba correctamente.


Los proveedores de contenido están identificados por la autoridad, por lo que debe ser único. No creo que haya trucos alrededor de eso.

Además, hay un error en la plataforma Android que también evita el uso del mismo nombre de clase para dos ContentProviders diferentes, incluso si tienen una autoridad diferente y están contenidos en APKs separados. Vea el error here .

La solución que recomiendo para usted es crear la clase de proveedor abstracta en su proyecto de biblioteca y luego extenderla con un nombre único en cada una de las aplicaciones individuales. Para que esto sea práctico, probablemente necesitará crear un script para generar / modificar los manifiestos individuales y las clases de proveedores de contenido.

Espero que esto ayude.