Skip to content

Most visited

Recently visited

navigation

Creación de un proveedor de contenido

Un proveedor de contenido administra el acceso a un repositorio central de datos. Un proveedor se implementa como una o más clases en una aplicación de Android, junto con elementos en el archivo de manifiesto. Una de tus clases implementa una subclase ContentProvider, que es la interfaz entre tu proveedor y otras aplicaciones. Si bien los proveedores de contenido permiten que los datos estén disponibles para otras aplicaciones, puedes tener actividades en tu aplicación que le permitan al usuario consultar y modificar los datos administrados por tu proveedor.

El resto de este tema es una lista básica de pasos para crear un proveedor de contenido y una lista de API para usar.

Antes de que empieces a crear

Antes de que empieces a crear un proveedor, haz lo siguiente:

  1. Decide si necesitas un proveedor de contenido. Debes crear un proveedor de contenido si quieres proporcionar una o más de las siguientes funciones:
    • Te recomendamos que ofrezcas datos o archivos complejos para otras aplicaciones.
    • Te recomendamos que permitas que los usuarios copien datos complejos de tu aplicación en otras aplicaciones.
    • Te recomendamos que proporciones sugerencias personalizadas usando el framework de búsqueda.

    No necesitas un proveedor para usar una base de datos SQLite si el uso ocurre completamente dentro de tu aplicación.

  2. Si todavía no lo hiciste, lee el tema Conceptos básicos sobre el proveedor de contenido para obtener más información acerca de los proveedores.

A continuación, sigue estos pasos para crear tu proveedor:

  1. Diseña el almacenamiento sin formato para tus datos. Un proveedor de contenido ofrece datos de dos maneras:
    Datos de archivo
    Datos que normalmente se presentan en archivos, como fotos, audio o videos. Guarda los archivos en el espacio privado de tu aplicación. En respuesta a una solicitud de un archivo por parte de otra aplicación, tu proveedor puede ofrecer un controlador para el archivo.
    Datos "estructurados"
    Datos que normalmente se encuentran en una base de datos, una matriz o una estructura similar. Guarda los datos en un formato compatible con tablas de filas y columnas. Una fila representa una entidad, como una persona o un elemento en el inventario. Una columna representa datos para la entidad, como el nombre de la persona o el precio de un artículo. Una forma común de guardar este tipo de datos es en una base de datos SQLite, pero puedes usar cualquier tipo de almacenamiento persistente. Para obtener más información acerca de los tipos de almacenamiento disponibles en el sistema Android, consulta la sección Diseño del almacenamiento de datos.
  2. Define una implementación concreta de la clase ContentProvider y sus métodos necesarios. Esta clase es la interfaz entre tus datos y el resto del sistema Android. Para obtener más información acerca de esta clase, consulta la sección Implementación de la clase ContentProvider.
  3. Define la string de autoridad del proveedor, sus URI de contenido y nombres de columnas. Si quieres que la aplicación del proveedor aborde intents, define también acciones de intent, datos extra e indicadores. Define también los permisos que requerirás para las aplicaciones que quieran acceder a tus datos. Considera definir todos estos valores como constantes en una clase Contract independiente; posteriormente, puedes exponer esa clase a otros desarrolladores. Para obtener más información acerca de los URI de contenido, consulta la sección Diseño de URI de contenido. Para obtener más información acerca de las intents, consulta la sección Intents y acceso a datos.
  4. Agrega otras piezas opcionales, como datos de muestra o una implementación de AbstractThreadedSyncAdapter que pueda sincronizar datos entre el proveedor y datos basados en la nube.

Diseño del almacenamiento de datos

Un proveedor de contenido es la interfaz para los datos guardados en un formato estructurado. Antes de crear la interfaz, debes decidir cómo guardar los datos. Puedes guardar los datos en cualquier formato que quieras y luego diseñar la interfaz para leer y escribir los datos, según sea necesario.

Estas son algunas de las tecnologías de almacenamiento de datos disponibles en Android:

Consideraciones del diseño de datos

Aquí te proporcionamos algunas sugerencias para diseñar la estructura de datos de tu proveedor:

Diseño de URI de contenido

Un URI de contenido es un URI que identifica datos de un proveedor. Los URI de contenido incluyen el nombre simbólico de todo el proveedor (su autoridad) y un nombre que apunta a una tabla o un archivo (una ruta de acceso). La parte de id. opcional apunta a una fila individual de una tabla. Cada método de acceso a datos del ContentProvider tiene un URI de contenido en forma de argumento; esto te permite determinar la tabla, la fila o el archivo al que se accederá.

Los conceptos básicos de los URI de contenido se describen en el tema Conceptos básicos sobre el proveedor de contenido.

Diseño de una autoridad

Un proveedor generalmente tiene una sola autoridad, que sirve como su nombre interno en Android. Para evitar conflictos con otros proveedores, debes usar propiedad de dominios de Internet (en sentido inverso) como base de la autoridad de tu proveedor. Debido a que esta recomendación también aplica para los nombres de paquete de Android, puedes definir la autoridad de tu proveedor como una extensión del nombre del paquete que contiene al proveedor. Por ejemplo, si tu nombre de paquete de Android es com.example.<appname>, debes proporcionarle a tu proveedor la autoridad com.example.<appname>.provider.

Diseño de la estructura de una ruta de acceso

Los desarrolladores generalmente crean URI de contenido a partir de la autoridad anexando rutas de acceso que apuntan a tablas individuales. Por ejemplo, si tienes dos tablas, table1 y table2, combinas la autoridad del ejemplo anterior para obtener URI de contenido com.example.<appname>.provider/table1 y com.example.<appname>.provider/table2. Las rutas de acceso se limitan a un solo segmento, y no es necesario que haya una tabla para cada nivel de la ruta de acceso.

Manipulación de ID de URI de contenido

Por convención, los proveedores ofrecen acceso a una sola fila en una tabla al aceptar un URI de contenido con un valor de ID para la fila al final del URI. También por convención, los proveedores comparan el valor del ID con la columna _ID de la tabla y realizan el acceso solicitado en función de la fila que coincide.

Esta convención facilita un patrón de diseño común para aplicaciones que acceden a un proveedor. La aplicación realiza una consulta al proveedor y muestra el Cursor resultante en unaListView usando un CursorAdapter. La definición de CursorAdapter requiere que una de las columnas en el Cursor sea _ID

Luego, el usuario selecciona una de las filas exhibidas de la IU para observar o modificar los datos. La aplicación obtiene la fila correspondiente del Cursor que respalda la ListView, obtiene el valor _ID para esta fila, lo anexa al URI de contenido y envía la solicitud de acceso al proveedor. Luego el proveedor puede realizar la consulta o la modificación en la fila exacta que seleccionó el usuario.

Patrones de URI de contenido

Para ayudarte a seleccionar la acción que debes realizar para un URI de contenido entrante, la Provider API incluye la clase de conveniencia UriMatcher, que asigna “patrones” de URI de contenido a valores enteros. Puedes usar los valores enteros en una instrucción switch que seleccione la acción deseada para el o los URI de contenido que coincidan con un patrón específico.

Un patrón de URI de contenido compara URI de contenido usando caracteres comodín:

Como ejemplo de diseño y programación de la manipulación de URI de contenido, considera un proveedor con la autoridad com.example.app.provider que reconozca los siguientes URI de contenido que apunten a tablas:

El proveedor también reconoce esos URI de contenido si tienen un ID de fila anexado a ellos, como por ejemplo content://com.example.app.provider/table3/1 para la fila identificada por 1 en table3.

Los siguientes patrones de URI de contenido serían posibles:

content://com.example.app.provider/*
Compara cualquier URI de contenido en el proveedor.
content://com.example.app.provider/table2/*:
Compara un URI de contenido para las tablas dataset1 y dataset2, pero no compara URI de contenido para table1 ni table3.
content://com.example.app.provider/table3/#: Compara un URI de contenido para filas individuales en table3, como content://com.example.app.provider/table3/6 para la fila identificada por 6.

El siguiente fragmento de código muestra cómo funcionan los métodos en UriMatcher. Este código manipula URI para una tabla entera de forma diferente de los URI para una sola fila mediante el uso del patrón de URI de contenido content://<authority>/<path> para tablas y content://<authority>/<path>/<id> para filas individuales.

El método addURI() asigna una autoridad y una ruta de acceso a un valor entero. El método match() devuelve el valor entero para un URI. Una instrucción switch elige entre consultar toda la tabla o consultar un solo registro:

public class ExampleProvider extends ContentProvider {
...
    // Creates a UriMatcher object.
    private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

    static {
        /*
         * The calls to addURI() go here, for all of the content URI patterns that the provider
         * should recognize. For this snippet, only the calls for table 3 are shown.
         */

        /*
         * Sets the integer value for multiple rows in table 3 to 1. Notice that no wildcard is used
         * in the path
         */
        sUriMatcher.addURI("com.example.app.provider", "table3", 1);

        /*
         * Sets the code for a single row to 2. In this case, the "#" wildcard is
         * used. "content://com.example.app.provider/table3/3" matches, but
         * "content://com.example.app.provider/table3 doesn't.
         */
        sUriMatcher.addURI("com.example.app.provider", "table3/#", 2);
    }
...
    // Implements ContentProvider.query()
    public Cursor query(
        Uri uri,
        String[] projection,
        String selection,
        String[] selectionArgs,
        String sortOrder) {
...
        /*
         * Choose the table to query and a sort order based on the code returned for the incoming
         * URI. Here, too, only the statements for table 3 are shown.
         */
        switch (sUriMatcher.match(uri)) {


            // If the incoming URI was for all of table3
            case 1:

                if (TextUtils.isEmpty(sortOrder)) sortOrder = "_ID ASC";
                break;

            // If the incoming URI was for a single row
            case 2:

                /*
                 * Because this URI was for a single row, the _ID value part is
                 * present. Get the last path segment from the URI; this is the _ID value.
                 * Then, append the value to the WHERE clause for the query
                 */
                selection = selection + "_ID = " uri.getLastPathSegment();
                break;

            default:
            ...
                // If the URI is not recognized, you should do some error handling here.
        }
        // call the code to actually do the query
    }

Otra clase, ContentUris, proporciona métodos de conveniencia para trabajar con la parte id de los URI de contenido. Las clases Uri y Uri.Builder incluyen métodos de conveniencia para analizar objetos Uri y crear nuevos.

Implementación de la clase ContentProvider

La instancia ContentProvider administra el acceso a un conjunto de datos estructurados mediante la manipulación de solicitudes de otras aplicaciones. Todas las formas de acceso eventualmente llaman a ContentResolver, que luego llama a un método concreto de ContentProvider para obtener acceso.

Métodos necesarios

La clase abstracta ContentProvider define seis métodos abstractos que debes implementar como parte de tu propia subclase concreta. A todos estos métodos, excepto onCreate(), los llama una aplicación cliente que intenta acceder a tu proveedor de contenido:

query()
Recupera datos de tu proveedor. Usa los argumentos para seleccionar la tabla que quieres consultar, las filas y columnas que quieres devolver y el orden de los resultados. Devuelve los datos en forma de objeto Cursor.
insert()
Inserta una nueva fila en tu proveedor. Usa los argumentos para seleccionar la tabla de destino y obtener los valores de columna que se usarán. Devuelve un URI de contenido para la fila recientemente insertada.
update()
Actualiza las filas existentes en tu proveedor. Usa los argumentos para seleccionar la tabla de destino y obtener los valores de columna que se usarán. Devuelve el número de filas actualizadas.
delete()
Elimina filas de tu proveedor. Usa los argumentos para seleccionar la tabla y las filas que se eliminarán. Devuelve el número de filas eliminadas.
getType()
Devuelve el tipo de MIME correspondiente al URI de contenido. Este método se describe en más detalle en la sección Implementación de tipos de MIME del proveedor de contenido.
onCreate()
Inicializa tu proveedor. El sistema Android llama a este método inmediatamente después de crear tu proveedor. Ten en cuenta que tu proveedor no se crea hasta que un objeto ContentResolver intenta acceder a él.

Ten en cuenta que estos métodos tienen la misma firma que los métodos ContentResolver de igual nombre.

La implementación que realices de estos métodos debe considerar lo siguiente:

Implementación del método query()

El método ContentProvider.query() debe devolver un objeto Cursor o, si falla , producir una Exception. Si estás usando una base de datos SQLite como tu punto de almacenamiento de datos, puedes simplemente devolver el Cursor devuelto por uno de los métodos query() de la clase SQLiteDatabase. Si la consulta no coincide con ninguna fila, debes mostrar una instancia Cursor cuyo método getCount() muestre 0. Debes mostrar null solo si se produce un error interno durante el proceso de consulta.

Si no estás usando una base de datos SQLite como tu punto de almacenamiento de datos, usa una de las subclases de Cursor. Por ejemplo, la clase MatrixCursor implementa un cursor en el que cada fila es una matriz de Object. Con esta clase, usa addRow() para agregar una nueva fila.

Recuerda que el sistema Android debe poder comunicar la Exception en todos los límites del proceso. Android puede hacer esto para las siguientes excepciones que podrían ser útiles para manipular errores en la consulta:

Implementación del método insert()

El método insert() agrega una nueva fila a la tabla correspondiente usando los valores del argumento ContentValues . Si el nombre de una columna no está en el argumento ContentValues, puedes proporcionar un valor predeterminado para él ya sea en tu código de proveedor o en el esquema de tu base de datos.

Este método debe devolver el URI de contenido para la nueva fila. Para construir esto, anexa el nuevo valor _ID de la fila (u otra clave primaria) al URI de contenido de la tabla usando withAppendedId().

Implementación del método delete()

El método delete() no tiene que borrar filas físicamente de tu punto de almacenamiento de datos. Si usas un adaptador de sincronización con tu proveedor, debes considerar marcar una fila eliminada con un indicador eliminar en lugar de "eliminar" la fila por completo. El adaptador de sincronización puede comprobar la existencia de filas eliminadas y quitarlas del servidor antes de eliminarlas del proveedor.

Implementación del método update()

El método update() toma el mismo argumento ContentValues usado por insert(), y los mismos argumentos selection y selectionArgs usados por delete() y ContentProvider.query(). Esto te puede permitir reutilizar código entre estos métodos.

Implementación del método onCreate()

El sistema Android llama a onCreate() cuando inicia el proveedor. En este método, solo debes realizar tareas de inicialización rápida y aplazar la creación de la base de datos y la carga de datos hasta que el proveedor reciba una solicitud de datos. Si realizas tareas más extensas en onCreate(), harás que el inicio de tu proveedor sea más lento. A la vez, esto demorará la respuesta del proveedor a otras aplicaciones.

Por ejemplo, si estás usando una base de datos SQLite, puedes crear un nuevo objeto SQLiteOpenHelper en ContentProvider.onCreate(), y luego crear las tablas SQL la primera vez que abras la base de datos. Para facilitar esto, la primera vez que llamas a getWritableDatabase(), automáticamente llamará al método SQLiteOpenHelper.onCreate().

Los dos fragmentos de código siguientes demuestran la interacción entre ContentProvider.onCreate() y SQLiteOpenHelper.onCreate(). El primer fragmento de código es la implementación de ContentProvider.onCreate():

public class ExampleProvider extends ContentProvider

    /*
     * Defines a handle to the database helper object. The MainDatabaseHelper class is defined
     * in a following snippet.
     */
    private MainDatabaseHelper mOpenHelper;

    // Defines the database name
    private static final String DBNAME = "mydb";

    // Holds the database object
    private SQLiteDatabase db;

    public boolean onCreate() {

        /*
         * Creates a new helper object. This method always returns quickly.
         * Notice that the database itself isn't created or opened
         * until SQLiteOpenHelper.getWritableDatabase is called
         */
        mOpenHelper = new MainDatabaseHelper(
            getContext(),        // the application context
            DBNAME,              // the name of the database)
            null,                // uses the default SQLite cursor
            1                    // the version number
        );

        return true;
    }

    ...

    // Implements the provider's insert method
    public Cursor insert(Uri uri, ContentValues values) {
        // Insert code here to determine which table to open, handle error-checking, and so forth

        ...

        /*
         * Gets a writeable database. This will trigger its creation if it doesn't already exist.
         *
         */
        db = mOpenHelper.getWritableDatabase();
    }
}

El siguiente fragmento de código es la implementación de SQLiteOpenHelper.onCreate(), incluida una clase de ayuda:

...
// A string that defines the SQL statement for creating a table
private static final String SQL_CREATE_MAIN = "CREATE TABLE " +
    "main " +                       // Table's name
    "(" +                           // The columns in the table
    " _ID INTEGER PRIMARY KEY, " +
    " WORD TEXT"
    " FREQUENCY INTEGER " +
    " LOCALE TEXT )";
...
/**
 * Helper class that actually creates and manages the provider's underlying data repository.
 */
protected static final class MainDatabaseHelper extends SQLiteOpenHelper {

    /*
     * Instantiates an open helper for the provider's SQLite data repository
     * Do not do database creation and upgrade here.
     */
    MainDatabaseHelper(Context context) {
        super(context, DBNAME, null, 1);
    }

    /*
     * Creates the data repository. This is called when the provider attempts to open the
     * repository and SQLite reports that it doesn't exist.
     */
    public void onCreate(SQLiteDatabase db) {

        // Creates the main table
        db.execSQL(SQL_CREATE_MAIN);
    }
}

Implementación de tipos de MIME ContentProvider

La clase ContentProvider tiene dos métodos para devolver tipos de MIME:

getType()
Uno de los métodos obligatorios que debes implementar para cualquier proveedor.
getStreamTypes()
Un método que se espera que implementes si tu proveedor ofrece archivos.

Tipos de MIME para tablas

El método getType() devuelve una String en formato MIME que describe el tipo de datos devuelto por el argumento del URI de contenido. El argumento Uri puede ser un patrón en lugar de un URI específico; en ese caso, debes devolver el tipo de datos asociado con los URI de contenido que coincidan con el patrón.

Para los tipos de datos comunes como texto, HTML o JPEG, getType() debe devolver el tipo de MIME estándar para esos datos. Puedes encontrar una lista completa de esos tipos estándar en el sitio web IANA MIME Media Types.

Para los URI de contenido que apuntan a una fila o filas de datos de una tabla, getType() debe devolver un tipo de MIME en formato MIME específico para proveedores de Android:

Por ejemplo, si la autoridad de un proveedor es com.example.app.provider y expone una tabla llamada table1, el tipo de MIME para múltiples filas en table1 es:

vnd.android.cursor.dir/vnd.com.example.provider.table1

Para una sola fila de table1, el tipo de MIME es:

vnd.android.cursor.item/vnd.com.example.provider.table1

Tipos de MIME para archivos

Si tu proveedor ofrece archivos, implementa getStreamTypes(). El método devuelve una matriz String de tipos de MIME para los archivos que tu proveedor puede devolver para un URI de contenido determinado. Debes filtrar los tipos de MIME que ofreces por el argumento del filtro de tipos de MIME, de modo que devuelvas solo los tipos de MIME que el cliente quiere manipular.

Por ejemplo, piensa en un proveedor que ofrece fotos en forma de archivo con formato .jpg, .png y .gif. Si una aplicación llama a ContentResolver.getStreamTypes() con la string de filtros image/* (algo que es una "imagen"), el método ContentProvider.getStreamTypes() debe devolver la matriz:

{ "image/jpeg", "image/png", "image/gif"}

Si a la aplicación solo le interesan los archivos .jpg, puede llamar a ContentResolver.getStreamTypes() con la string de filtros *\/jpeg, y ContentProvider.getStreamTypes() debe devolver:

{"image/jpeg"}

Si tu proveedor no ofrece ninguno de los tipos de MIME solicitados en la string de filtros, getStreamTypes() debe devolver null.

Implementación de una clase Contract

Una clase Contract es una clase public final que contiene definiciones de constantes para los URI, nombres de columnas, tipos de MIME y otros metadatos que le pertenecen al proveedor. La clase establece un contrato entre el proveedor y otras aplicaciones al asegurarse de que se pueda acceder correctamente al proveedor aunque se hayan producido cambios en los valores de los URI, los nombres de las columnas, etc.

Una clase Contract también ayuda a los desarrolladores porque generalmente tiene nombres mnemotécnicos para sus constantes, de modo que los desarrolladores tengan menos probabilidades de usar valores incorrectos para los nombres de las columnas o los URI. Como es una clase, puede contener documentación Javadoc. Los entornos de desarrollo integrados, como Android Studio, pueden autocompletar nombres de constantes desde la clase Contract y mostrar Javadoc para las constantes.

Los desarrolladores no pueden acceder al archivo de clase de la clase Contract desde tu aplicación, pero pueden compilar estáticamente en su aplicación desde un archivo .jar que tú proporciones.

La clase ContactsContract y sus clases anidadas son ejemplos de clases de contrato.

Implementación de permisos del proveedor de contenido

Los permisos y el acceso para todos los aspectos del sistema Android se describen en detalle en el tema Seguridad y permisos. El tema Almacenamiento de datos también describió la seguridad y los permisos vigentes para varios tipos de almacenamiento. En resumen, los puntos importantes son los siguientes:

Si quieres usar permisos del proveedor de contenido para controlar el acceso a tus datos, debes guardar tus datos en archivos internos, bases de datos SQLite o en la nube (por ejemplo, en un servidor remoto), y debes mantener los archivos y las bases de datos de forma privada para tu aplicación.

Implementación de permisos

Todas las aplicaciones pueden leer de tu proveedor o escribir en él, incluso si los datos subyacentes son privados, ya que, de forma predeterminada, tu proveedor no tiene permisos establecidos. Para cambiar esto, configura permisos para tu proveedor en tu archivo de manifiesto usando atributos o elementos secundarios del elemento <provider>. Puedes establecer permisos que apliquen a todo el proveedor, o a ciertas tablas, o incluso a ciertos registros, o a los tres.

Defines permisos para tu proveedor con uno o más elementos <permission> en tu archivo de manifiesto. Para que el sea exclusivo de tu proveedor, usa el ámbito de estilo Java para el atributo android:name. Por ejemplo, nombre y permiso de lectura com.example.app.provider.permission.READ_PROVIDER.

La siguiente lista describe el ámbito de los permisos del proveedor comenzando con los permisos que aplican a todo el proveedor y luego se van refinando. Los permisos más refinados tienen prioridad sobre aquellos con un alcance más amplio:

Permiso individual de lectura y escritura a nivel del proveedor
Permiso que controla el acceso a lectura y escritura a todo el proveedor, especificado con el atributo android:permission del elemento <provider>.
Permisos independientes de lectura y escritura a nivel del proveedor
Un permiso de lectura y un permiso de escritura para todo el proveedor. Los especificas con los atributos android:readPermission y android:writePermission del elemento <provider>. Tienen prioridad sobre el permiso requerido por android:permission.
Permiso a nivel de ruta de acceso
Permiso de lectura, escritura o lectura/escritura para un URI de contenido en tu proveedor. Especificas cada URI que quieres controlar con un elemento secundario <path-permission> del elemento <provider>. Para cada URI de contenido que especificas, puedes especificar un permiso de lectura/escritura, un permiso de lectura, un permiso de escritura o los tres. Los permisos de lectura y escritura tienen prioridad sobre el permiso de lectura/escritura. Asimismo, el permiso a nivel de ruta de acceso tiene prioridad sobre los permisos a nivel del proveedor.
Permiso temporal
Un nivel de permiso que permite el acceso temporal a una aplicación, incluso cuando la aplicación no tenga los permisos que normalmente se requieren. La función de acceso temporal reduce la cantidad de permisos que una aplicación debe requerir en su manifiesto. Cuando activas los permisos temporales, las únicas aplicaciones que necesitan permisos "permanentes" para tu proveedor son las que acceden continuamente a todos tus datos.

Considera los permisos que necesitas para implementar un proveedor y una aplicación de correo electrónico cuando quieras permitir que una aplicación de visor de imágenes externa muestre archivos adjuntos de fotografía desde tu proveedor. Para otorgarle al visor de imágenes el acceso necesario sin requerir permisos, establece permisos temporales para los URI de contenido para fotos. Diseña tu aplicación de correo electrónico de modo que cuando el usuario quiera mostrar una foto la aplicación envíe una intent con el URI de contenido de la foto e indicadores de permiso al visor de imágenes. Luego, el visor de imágenes podrá consultar tu proveedor de correo electrónico para recuperar la foto, aunque el visor no tenga el permiso de lectura normal para tu proveedor.

Para activar los permisos temporales, establece el atributo android:grantUriPermissions del elemento <provider> o agrega uno o más elementos secundarios <grant-uri-permission> a tu elemento <provider>. Si usas permisos temporales, tienes que llamar a Context.revokeUriPermission() cada vez que quites el soporte para un URI de contenido de tu proveedor y el URI de contenido esté asociado a un permiso temporal.

El valor del atributo determina la porción del proveedor a la que se puede acceder. Si el atributo está configurado en true, el sistema otorgará permiso temporal para todo tu proveedor y anulará cualquier otro permiso que requieran tus permisos a nivel de proveedor o de ruta de acceso.

Si este indicador está configurado en false, debes agregar elementos secundarios <grant-uri-permission> a tu elemento <provider>. Cada elemento secundario especifica el URI o los URI de contenido para los que se concede el acceso temporal.

Para delegar el acceso temporal a una aplicación, una intent debe contener el indicador FLAG_GRANT_READ_URI_PERMISSION o FLAG_GRANT_WRITE_URI_PERMISSION, o ambos. Estos indicadores se establecen con el método setFlags().

Si el atributo android:grantUriPermissions no está presente, se supone que es false.

El elemento <provider>

Al igual que los componentes Activity y Service, se debe definir una subclase deContentProvider en el archivo de manifiesto para su aplicación usando el elemento <provider>. El sistema Android obtiene la siguiente información del elemento:

Autoridad (android:authorities)
Nombres simbólicos que identifican al proveedor completo en el sistema. Este atributo se describe en más detalle en la sección Diseño de URI de contenido.
Nombre de clase del proveedor ( android:name )
La clase que implementa ContentProvider. Esta clase se describe en más detalle en la sección Implementación de la clase ContentProvider.
Permisos
Atributos que especifican los permisos que otras aplicaciones deben tener para poder acceder a los datos del proveedor:

Los permisos y sus atributos correspondientes se describen en más detalle en la sección Implementación de permisos del proveedor de contenido.

Atributos de inicio y control
Estos atributos determinan cómo y cuándo el sistema Android inicia el proveedor, las características del proceso del proveedor y otras configuraciones de tiempo de ejecución:
  • android:enabled: Indicador que le permite al sistema iniciar el proveedor.
  • android:exported: Indicador que permite que otras aplicaciones usen este proveedor.
  • android:initOrder: El orden en el que se debe iniciar el proveedor en función de otros proveedores en el mismo proceso.
  • android:multiProcess: Indicador que le permite al sistema iniciar el proveedor en el mismo proceso que el cliente que realiza la llamada.
  • android:process: Nombre del proceso en el que se debe ejecutar el proveedor.
  • android:syncable: Indicador que señala que los datos del proveedor se sincronizarán con los datos de un servidor.

Los atributos están completamente documentados en el tema para el elemento <provider> de la guía para desarrolladores.

Atributos informativos
Un ícono y una etiqueta opcionales para el proveedor:
  • android:icon: Un recurso de elemento de diseño que contiene un ícono para el proveedor. El ícono aparece junto a la etiqueta del proveedor en la lista de aplicaciones en Configuración > Aplicaciones > Todas.
  • android:label: Una etiqueta informativa que describe el proveedor o sus datos, o ambos. La etiqueta aparece en la lista de aplicaciones en Configuración > Aplicaciones > Todas.

Los atributos están completamente documentados en el tema para el elemento <provider> de la guía para desarrolladores.

Intents y acceso a datos

Las aplicaciones pueden acceder a un proveedor de contenido de forma indirecta con una Intent. La aplicación no llama a ninguno de los métodos de ContentResolver o ContentProvider. En su lugar, envía una intent que inicia una actividad, que a menudo forma parte de la aplicación del proveedor. La actividad de destino está a cargo de recuperar y mostrar los datos en su IU. Según la acción en la intent, la actividad de destino también puede indicarle al usuario que modifique los datos del proveedor. Una intent también debe contener datos extra que la actividad de destino muestra en la IU; el usuario tiene la opción de cambiar estos datos antes de usarlos para modificar los datos en el proveedor.

Te recomendamos que uses acceso mediante intents para ayudar a garantizar la integridad de los datos. Es posible que tu proveedor esté sujeto a la inserción, actualización y eliminación de datos conforme a lógica de negocio bien definida. Si este fuera el caso, permitir que otras aplicaciones modifiquen directamente tus datos puede generar datos no válidos. Si quieres que los desarrolladores usen acceso mediante intents, asegúrate de documentarlo exhaustivamente. Explícales por qué el acceso mediante intents con la IU de tu aplicación es mejor que intentar modificar datos con su código.

La manipulación de una intent entrante que quiere modificar los datos de tu proveedor no difiere de la manipulación de otras intents. Puedes obtener más información acerca de cómo usar intents leyendo el tema Intents y filtros de intents.

This site uses cookies to store your preferences for site-specific language and display options.

Get the latest Android developer news and tips that will help you find success on Google Play.

* Required Fields

Hooray!

Follow Google Developers on WeChat

Browse this site in ?

You requested a page in , but your language preference for this site is .

Would you like to change your language preference and browse this site in ? If you want to change your language preference later, use the language menu at the bottom of each page.

This class requires API level or higher

This doc is hidden because your selected API level for the documentation is . You can change the documentation API level with the selector above the left navigation.

For more information about specifying the API level your app requires, read Supporting Different Platform Versions.

Take a short survey?
Help us improve the Android developer experience.
(Sep 2017 survey)