Descripción general de las transmisiones

Las apps para Android envían y reciben mensajes de transmisión del sistema Android y otras apps para Android, de manera similar al patrón de diseño de publicación y suscripción. Por lo general, el sistema y las apps envían transmisiones cuando ocurren ciertos eventos. Por ejemplo, el sistema Android envía transmisiones cuando ocurren varios eventos del sistema, como el inicio del sistema o la carga del dispositivo. Las apps también envían transmisiones personalizadas, por ejemplo, para notificar a otras apps sobre algo que podría interesarles (por ejemplo, la descarga de datos nuevos).

Las apps pueden registrarse para recibir emisiones específicas. Cuando se envía una transmisión, el sistema la enruta automáticamente a las apps que se suscribieron para recibir ese tipo en particular.

En términos generales, las transmisiones se pueden usar como un sistema de mensajería entre apps y fuera del flujo de usuarios normal. Sin embargo, debes tener cuidado de no abusar de la oportunidad de responder a las transmisiones y ejecutar trabajos en segundo plano que puedan contribuir a un rendimiento lento del sistema.

Acerca de las emisiones del sistema

El sistema envía transmisiones automáticamente cuando ocurren varios eventos del sistema, como cuando el sistema entra y sale del Modo avión. Todas las apps con suscripción reciben estas transmisiones.

El objeto Intent contiene el mensaje de transmisión. La cadena action identifica el evento que ocurrió, como android.intent.action.AIRPLANE_MODE. El intent también puede incluir información adicional agrupada en su campo adicional. Por ejemplo, el intent del Modo avión incluye un valor booleano adicional que indica si el Modo avión está activado o no.

Para obtener más información sobre cómo leer intents y obtener la cadena de acción de un intent, consulta Intents y filtros de intents.

Acciones de transmisión del sistema

Para obtener una lista completa de las acciones de transmisión del sistema, consulta el archivo BROADCAST_ACTIONS.TXT en el SDK de Android. Cada acción de transmisión tiene un campo constante asociado. Por ejemplo, el valor de la constante ACTION_AIRPLANE_MODE_CHANGED es android.intent.action.AIRPLANE_MODE. La documentación de cada acción de transmisión está disponible en su campo constante asociado.

Cambios en las emisiones del sistema

A medida que evoluciona la plataforma de Android, cambia periódicamente el comportamiento de las transmisiones del sistema. Ten en cuenta los siguientes cambios para admitir todas las versiones de Android.

Android 16

En Android 16, no se garantizará el orden de entrega de la transmisión con el android:priority atributo o IntentFilter.setPriority() en diferentes procesos. Las prioridades de transmisión solo se respetan dentro del mismo proceso de aplicación, en lugar de en todos los procesos.

Además, las prioridades de transmisión se limitan automáticamente al rango (SYSTEM_LOW_PRIORITY + 1, SYSTEM_HIGH_PRIORITY - 1). Solo los componentes del sistema pueden establecer SYSTEM_LOW_PRIORITY y SYSTEM_HIGH_PRIORITY como prioridad de transmisión.

Android 14

Mientras las apps están en un estado almacenado en caché, el sistema optimiza la entrega de transmisiones para el estado del sistema. Por ejemplo, el sistema difiere las transmisiones del sistema menos importantes, como ACTION_SCREEN_ON mientras la app está en un estado almacenado en caché. Una vez que la app pasa del estado almacenado en caché a un ciclo de vida de proceso activo, el sistema entrega cualquier transmisión diferida.

Las transmisiones importantes que se declaran en el manifiesto quitan temporalmente las apps del estado almacenado en caché para la entrega.

Android 9

A partir de Android 9 (nivel de API 28), la NETWORK_STATE_CHANGED_ACTION transmisión no recibe información sobre la ubicación del usuario ni datos de identificación personal.

Si tu app está instalada en un dispositivo que ejecuta Android 9.0 (nivel de API 28) o versiones posteriores, el sistema no incluye SSID, BSSID, información de conexión ni resultados de análisis en las transmisiones de Wi-Fi. Para obtener esta información, llama a getConnectionInfo() en su lugar.

Android 8.0

A partir de Android 8.0 (nivel de API 26), el sistema impone restricciones adicionales a los receptores declarados en el manifiesto.

Si tu app se orienta a Android 8.0 o versiones posteriores, no puedes usar el manifiesto para declarar un receptor para la mayoría de las transmisiones implícitas (transmisiones que no se orientan específicamente a tu app). Aún puedes usar un receptor registrado en el contexto cuando el usuario usa tu app de forma activa.

Android 7.0

Android 7.0 (nivel de API 24) y versiones posteriores no envían las siguientes transmisiones del sistema:

Además, las apps que se orientan a Android 7.0 y versiones posteriores deben registrar la CONNECTIVITY_ACTION transmisión con registerReceiver(BroadcastReceiver, IntentFilter). Declarar un receptor en el manifiesto no funciona.

Recibe transmisiones

Las apps pueden recibir transmisiones de dos maneras: a través de receptores registrados en el contexto y receptores declarados en el manifiesto.

Receptores registrados en el contexto

Los receptores registrados en el contexto reciben transmisiones siempre que su contexto de registro sea válido. Por lo general, esto ocurre entre las llamadas a registerReceiver y unregisterReceiver. El contexto de registro también deja de ser válido cuando el sistema destruye el contexto correspondiente. Por ejemplo, si te registras en un Activity contexto, recibirás transmisiones siempre que la actividad permanezca activa. Si te registras en el contexto de la aplicación, recibirás transmisiones mientras se ejecute la app.

Para registrar un receptor con un contexto, realiza los siguientes pasos:

  1. En el archivo de compilación de nivel del módulo de tu app, incluye la versión 1.9.0 o posterior de la biblioteca de AndroidX Core:

    Groovy

    dependencies {
        def core_version = "1.19.1"
    
        // Java language implementation
        implementation "androidx.core:core:$core_version"
        // Kotlin
        implementation "androidx.core:core-ktx:$core_version"
    
        // To use RoleManagerCompat
        implementation "androidx.core:core-role:1.1.0"
    
        // To use the Animator APIs
        implementation "androidx.core:core-animation:1.0.0"
        // To test the Animator APIs
        androidTestImplementation "androidx.core:core-animation-testing:1.0.0"
    
        // Optional - To enable APIs that query the performance characteristics of GMS devices.
        implementation "androidx.core:core-performance:1.0.0"
    
        // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google
        implementation "androidx.core:core-google-shortcuts:1.1.0"
    
        // Optional - to support backwards compatibility of RemoteViews
        implementation "androidx.core:core-remoteviews:1.1.0"
    
        // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12
        implementation "androidx.core:core-splashscreen:1.2.0"
    }

    Kotlin

    dependencies {
        val core_version = "1.19.1"
    
        // Java language implementation
        implementation("androidx.core:core:$core_version")
        // Kotlin
        implementation("androidx.core:core-ktx:$core_version")
    
        // To use RoleManagerCompat
        implementation("androidx.core:core-role:1.1.0")
    
        // To use the Animator APIs
        implementation("androidx.core:core-animation:1.0.0")
        // To test the Animator APIs
        androidTestImplementation("androidx.core:core-animation-testing:1.0.0")
    
        // Optional - To enable APIs that query the performance characteristics of GMS devices.
        implementation("androidx.core:core-performance:1.0.0")
    
        // Optional - to use ShortcutManagerCompat to donate shortcuts to be used by Google
        implementation("androidx.core:core-google-shortcuts:1.1.0")
    
        // Optional - to support backwards compatibility of RemoteViews
        implementation("androidx.core:core-remoteviews:1.1.0")
    
        // Optional - APIs for SplashScreen, including compatibility helpers on devices prior Android 12
        implementation("androidx.core:core-splashscreen:1.2.0")
    }
  2. Crea una instancia de BroadcastReceiver:

    Kotlin

    val myBroadcastReceiver = MyBroadcastReceiver()
    

    Java

    MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
    
  3. Crea una instancia de IntentFilter:

    Kotlin

    val filter = IntentFilter("com.example.snippets.ACTION_UPDATE_DATA")
    

    Java

    IntentFilter filter = new IntentFilter("com.example.snippets.ACTION_UPDATE_DATA");
    
  4. Elige si el receptor de transmisión debe exportarse y ser visible para otras apps en el dispositivo. Si este receptor está escuchando transmisiones enviadas desde el sistema o desde otras apps (incluso otras apps de tu propiedad), usa la marca RECEIVER_EXPORTED. Si, en cambio, este receptor solo escucha las transmisiones enviadas por tu app, usa la marca RECEIVER_NOT_EXPORTED.

    Kotlin

    val listenToBroadcastsFromOtherApps = false
    val receiverFlags = if (listenToBroadcastsFromOtherApps) {
        ContextCompat.RECEIVER_EXPORTED
    } else {
        ContextCompat.RECEIVER_NOT_EXPORTED
    }
    

    Java

    boolean listenToBroadcastsFromOtherApps = false;
    int receiverFlags = listenToBroadcastsFromOtherApps
            ? ContextCompat.RECEIVER_EXPORTED
            : ContextCompat.RECEIVER_NOT_EXPORTED;
    
  5. Para registrar el receptor, llama a registerReceiver():

    Kotlin

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags)
    

    Java

    ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, receiverFlags);
    
  6. Para dejar de recibir transmisiones, llama a unregisterReceiver(android.content.BroadcastReceiver). Asegúrate de cancelar el registro del receptor cuando ya no lo necesites o el contexto ya no sea válido.

Cancela el registro de tu receptor de transmisión

Mientras el receptor de transmisión esté registrado, tendrá una referencia al contexto con el que lo registraste. Esto puede causar filtraciones si el alcance registrado del receptor supera el alcance del ciclo de vida del contexto. Por ejemplo, esto puede ocurrir cuando registras un receptor en un alcance de actividad, pero olvidas cancelar su registro cuando el sistema destruye la actividad. Por lo tanto, siempre cancela el registro de tu receptor de transmisión.

Kotlin

class MyActivity : ComponentActivity() {
    private val myBroadcastReceiver = MyBroadcastReceiver()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags)
        setContent { MyApp() }
    }

    override fun onDestroy() {
        super.onDestroy()
        // When you forget to unregister your receiver here, you're causing a leak!
        this.unregisterReceiver(myBroadcastReceiver)
    }
}

Java

class MyActivity extends ComponentActivity {
    MyBroadcastReceiver myBroadcastReceiver;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // ...
        ContextCompat.registerReceiver(this, myBroadcastReceiver, filter, receiverFlags);
        // Set content
    }
}

Registra receptores en el alcance más pequeño

Tu receptor de transmisión solo debe registrarse cuando realmente te interese el resultado. Elige el alcance del receptor más pequeño posible:

  • LifecycleResumeEffect o métodos del ciclo de vida onResume/onPause de la actividad: El receptor de transmisión solo recibe actualizaciones mientras la app está en estado reanudado.
  • LifecycleStartEffect o métodos del ciclo de vida onStart/onStop de la actividad: El receptor de transmisión solo recibe actualizaciones mientras la app está en estado reanudado.
  • DisposableEffect: El receptor de transmisión solo recibe actualizaciones mientras el elemento componible está en el árbol de composición. Este alcance no está adjunto al alcance del ciclo de vida de la actividad. Considera registrar el receptor en el contexto de la aplicación. Esto se debe a que el elemento componible podría, en teoría, sobrevivir al alcance del ciclo de vida de la actividad y filtrar la actividad.
  • Actividad onCreate/onDestroy: El receptor de transmisión recibe actualizaciones mientras la actividad está en estado creado. Asegúrate de cancelar el registro en onDestroy() y no en onSaveInstanceState(Bundle), ya que es posible que no se llame a este método.
  • Un alcance personalizado: Por ejemplo, puedes registrar un receptor en tu alcance ViewModel para que sobreviva a la recreación de la actividad. Asegúrate de usar el contexto de la aplicación para registrar el receptor, ya que este puede sobrevivir al alcance del ciclo de vida de la actividad y filtrar la actividad.

Crea elementos componibles con y sin estado

Compose tiene elementos componibles con y sin estado. Registrar o cancelar el registro de un receptor de transmisión dentro de un elemento componible lo convierte en un elemento con estado. El elemento componible no es una función determinista que renderiza el mismo contenido cuando se le pasan los mismos parámetros. El estado interno puede cambiar según las llamadas al receptor de transmisión registrado.

Como práctica recomendada en Compose, te sugerimos que dividas tus elementos componibles en versiones con y sin estado. Por lo tanto, te recomendamos que eleves la creación del receptor de transmisión fuera de un elemento componible para que no tenga estado:

@Composable
fun MyStatefulScreen() {
    val myBroadcastReceiver = remember { MyBroadcastReceiver() }
    val context = LocalContext.current
    LifecycleStartEffect(true) {
        // ...
        ContextCompat.registerReceiver(context, myBroadcastReceiver, filter, flags)
        onStopOrDispose { context.unregisterReceiver(myBroadcastReceiver) }
    }
    MyStatelessScreen()
}

@Composable
fun MyStatelessScreen() {
    // Implement your screen
}

Receptores declarados en el manifiesto

Si declaras un receptor de transmisión en tu manifiesto, el sistema iniciará tu app cuando se envíe la transmisión. Si la app aún no se está ejecutando, el sistema la iniciará.

Para declarar un receptor de transmisiones en el manifiesto, realiza los siguientes pasos:

  1. Especifica el <receiver> elemento en el manifiesto de tu app.

    <!-- If this receiver listens for broadcasts sent from the system or from
         other apps, even other apps that you own, set android:exported to "true". -->
    <receiver android:name=".MyBroadcastReceiver" android:exported="false">
        <intent-filter>
            <action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
        </intent-filter>
    </receiver>
    

    Los filtros de intents especifican las acciones de transmisión a las que se suscribe tu receptor.

  2. Crea una subclase de BroadcastReceiver y, luego, implementa onReceive(Context, Intent). El receptor de transmisión del siguiente ejemplo registra y muestra el contenido de la transmisión:

    Kotlin

    class MyBroadcastReceiver : BroadcastReceiver() {
    
        @Inject
        lateinit var dataRepository: DataRepository
    
        override fun onReceive(context: Context, intent: Intent) {
            if (intent.action == "com.example.snippets.ACTION_UPDATE_DATA") {
                val data = intent.getStringExtra("com.example.snippets.DATA") ?: "No data"
                // Do something with the data, for example send it to a data repository:
                dataRepository.updateData(data)
            }
        }
    }
    

    Java

    public static class MyBroadcastReceiver extends BroadcastReceiver {
    
        @Inject
        DataRepository dataRepository;
    
        @Override
        public void onReceive(Context context, Intent intent) {
            if (Objects.equals(intent.getAction(), "com.example.snippets.ACTION_UPDATE_DATA")) {
                String data = intent.getStringExtra("com.example.snippets.DATA");
                // Do something with the data, for example send it to a data repository:
                if (data != null) { dataRepository.updateData(data); }
            }
        }
    }
    

El administrador de paquetes del sistema registra el receptor cuando se instala la app. Luego, el receptor se convierte en un punto de entrada independiente en tu app, lo que significa que el sistema puede iniciar la app y entregar la transmisión si no se está ejecutando.

El sistema crea un nuevo BroadcastReceiver objeto de componente para controlar cada transmisión que recibe. Este objeto solo es válido durante la duración de la llamada a onReceive(Context, Intent). Una vez que tu código regresa de este método, el sistema considera que el componente ya no está activo.

Efectos en el estado del proceso

El hecho de que tu BroadcastReceiver esté en funcionamiento o no afecta su proceso contenido, lo que puede alterar su probabilidad de eliminación del sistema. Un proceso en primer plano ejecuta el método onReceive() de un receptor. El sistema ejecuta el proceso, excepto en condiciones de presión de memoria extrema.

El sistema desactiva el BroadcastReceiver después de onReceive(). La importancia del proceso host del receptor depende de los componentes de su app. Si ese proceso solo aloja un receptor declarado en el manifiesto, el sistema podría eliminarlo después de onReceive() para liberar recursos para otros procesos más importantes. Esto es común en las apps con las que el usuario nunca interactuó o no lo hizo recientemente.

Por lo tanto, los receptores de transmisión no deben iniciar subprocesos en segundo plano de larga duración. El sistema puede detener el proceso en cualquier momento después de onReceive() para recuperar memoria y finalizar el subproceso creado. Para mantener el proceso activo, programa un JobService desde el receptor con el JobScheduler para que el sistema sepa que el proceso aún está funcionando. En la Descripción general del trabajo en segundo plano , se proporcionan más detalles.

Envía transmisiones

Android proporciona dos formas para que las apps envíen transmisiones:

  • El método sendOrderedBroadcast(Intent, String) envía transmisiones a un receptor a la vez. A medida que se ejecuta cada receptor, se puede propagar un resultado al siguiente receptor. También puede anular por completo la transmisión para que no llegue a otros receptores. Puedes controlar el orden en el que se ejecutan los receptores dentro del mismo proceso de la app. Para ello, usa el atributo android:priority del filtro de intents coincidente. Los receptores con la misma prioridad se ejecutan en un orden arbitrario.
  • El método sendBroadcast(Intent) envía transmisiones a todos los receptores en un orden indefinido. Esto se denomina transmisión normal. Es más eficiente, pero significa que los receptores no pueden leer los resultados de otros receptores, propagar los datos recibidos de la transmisión ni anular la transmisión.

En el siguiente fragmento de código, se muestra cómo enviar una transmisión creando un intent y llamando a sendBroadcast(Intent).

Kotlin

val intent = Intent("com.example.snippets.ACTION_UPDATE_DATA").apply {
    putExtra("com.example.snippets.DATA", newData)
    setPackage("com.example.snippets")
}
context.sendBroadcast(intent)

Java

Intent intent = new Intent("com.example.snippets.ACTION_UPDATE_DATA");
intent.putExtra("com.example.snippets.DATA", newData);
intent.setPackage("com.example.snippets");
context.sendBroadcast(intent);

El mensaje de transmisión se incluye en un Intent objeto. La cadena action del intent debe proporcionar la sintaxis del nombre del paquete Java de la app y debe identificar de forma única el evento de transmisión. Puedes adjuntar información adicional al intent con putExtra(String, Bundle). También puedes limitar una transmisión a un conjunto de apps de la misma organización llamando a setPackage(String) en el intent.

Restringe las transmisiones con permisos

Los permisos te permiten restringir las transmisiones al conjunto de apps que tienen ciertos permisos. Puedes aplicar restricciones al remitente o al receptor de una transmisión.

Envía transmisiones con permisos

Cuando llamas a sendBroadcast(Intent, String) o sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) , puedes especificar un parámetro de permiso. Solo los receptores que solicitaron ese permiso con la etiqueta <uses-permission> en su manifiesto pueden recibir la transmisión. Si el permiso es peligroso, debes otorgarlo antes de que el receptor pueda recibir la transmisión. Por ejemplo, el siguiente código envía una transmisión con un permiso:

Kotlin

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION)

Java

context.sendBroadcast(intent, android.Manifest.permission.ACCESS_COARSE_LOCATION);

Para recibir la transmisión, la app receptora debe solicitar el permiso de la siguiente manera:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Puedes especificar un permiso del sistema existente, como BLUETOOTH_CONNECT o definir un permiso personalizado con el elemento <permission>. Para obtener información sobre los permisos y la seguridad en general, consulta los Permisos del sistema.

Recibe transmisiones con permisos

Si especificas un parámetro de permiso cuando registras un receptor de transmisión (ya sea con registerReceiver(BroadcastReceiver, IntentFilter, String, Handler) o en la etiqueta <receiver> de tu manifiesto), solo los emisores que solicitaron el permiso con la etiqueta <uses-permission> en su manifiesto pueden enviar un intent al receptor. Si el permiso es peligroso, también se debe otorgar al emisor.

Por ejemplo, supongamos que tu app receptora tiene un receptor declarado en el manifiesto de la siguiente manera:

<!-- If this receiver listens for broadcasts sent from the system or from
     other apps, even other apps that you own, set android:exported to "true". -->
<receiver
    android:name=".MyBroadcastReceiverWithPermission"
    android:permission="android.permission.ACCESS_COARSE_LOCATION"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.snippets.ACTION_UPDATE_DATA" />
    </intent-filter>
</receiver>

O tu app receptora tiene un receptor registrado en el contexto de la siguiente manera:

Kotlin

ContextCompat.registerReceiver(
    context, myBroadcastReceiver, filter,
    android.Manifest.permission.ACCESS_COARSE_LOCATION,
    null, // scheduler that defines thread, null means run on main thread
    receiverFlags
)

Java

ContextCompat.registerReceiver(
        context, myBroadcastReceiver, filter,
        android.Manifest.permission.ACCESS_COARSE_LOCATION,
        null, // scheduler that defines thread, null means run on main thread
        receiverFlags
);

Luego, para poder enviar transmisiones a esos receptores, la app emisora debe solicitar el permiso de la siguiente manera:

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

Evita las transmisiones dentro del mismo proceso

Las transmisiones están diseñadas como un mecanismo de comunicación entre procesos (IPC) para enviar mensajes entre diferentes apps o entre el sistema y las apps. Enviar una autotransmisión, que es una transmisión para la que todos los receptores se ejecutan en el mismo proceso que envió la transmisión, es muy ineficiente, crea una sobrecarga innecesaria del sistema y no se recomienda.

Dos situaciones comunes en las que las apps se envían transmisiones a sí mismas son las siguientes:

  • Comunicación entre componentes en el mismo proceso: Por ejemplo, pasar eventos o datos entre actividades, fragmentos, servicios o subprocesos en segundo plano. En lugar de enviar transmisiones, usa mecanismos de comunicación estándar en el proceso , como el patrón de observador o las transmisiones reactivas:

    • Flujos de Kotlin (SharedFlow y StateFlow): Una solución moderna, idiomática en Kotlin para emitir y observar transmisiones de eventos o actualizaciones de estado en corrutinas y componentes de tu app.
    • ViewModel compartido: Facilita el uso compartido de datos y eventos entre diferentes componentes de la IU (como fragmentos o elementos componibles) dentro de la misma actividad.
    • Devoluciones de llamada y objetos de escucha: Devoluciones de llamada de interfaz estándar o referencias de funciones que se pasan directamente entre componentes o se registran con un repositorio o controlador central.
  • Control de eventos, trabajos o alarmas del sistema: Por ejemplo, recibir un trabajo programado, una alarma o una devolución de llamada del sistema y, luego, enviar una transmisión para activar el trabajo real. En lugar de enviar una transmisión, completa el trabajo directamente dentro de ese trabajo (como un JobService o WorkManager trabajador), un controlador de alarmas o un componente de devolución de llamada del sistema, o delega directamente a las clases de lógica empresarial de tu app.

En dispositivos que ejecutan Android 17 QPR2 o versiones posteriores, el sistema entrega autotransmisiones de manera más eficiente devolviéndolas al proceso de envío, que las entrega a sus propios receptores en el subproceso principal. Enviar una autotransmisión no aumenta la importancia de tu proceso y no impide que se congele un proceso almacenado en caché, por lo que no dependas de las autotransmisiones para mantener tu app en ejecución o para realizar tareas en segundo plano. En su lugar, elige la API adecuada para tu tarea, como se describe en la Descripción general de las tareas en segundo plano. Incluso con esta optimización, las autotransmisiones son menos eficientes que los mecanismos de comunicación en el proceso, por lo que debes usar esas alternativas.

Para obtener más información sobre el diseño de la comunicación entre los componentes de la app, consulta la Guía de arquitectura de apps.

Consideraciones de seguridad

Estas son algunas consideraciones de seguridad para enviar y recibir transmisiones:

  • Si muchas apps se registraron para recibir la misma transmisión en su manifiesto, el sistema puede iniciar muchas apps, lo que genera un impacto significativo en el rendimiento del dispositivo y la experiencia del usuario. Para evitar esto, prefiere usar el registro de contexto en lugar de la declaración de manifiesto. A veces, el sistema Android aplica el uso de receptores registrados en el contexto. Por ejemplo, la CONNECTIVITY_ACTION transmisión solo se entrega a los receptores registrados en el contexto.

  • No transmitas información sensible con un intent implícito. Cualquier app puede leer la información si se registra para recibir la transmisión. Existen tres maneras de controlar quién puede recibir tus emisiones:

    • Puedes especificar un permiso cuando envías una emisión.
    • En Android 4.0 (nivel de API 14) y versiones posteriores, puedes especificar un paquete con setPackage(String) cuando envías una transmisión. El sistema restringe la transmisión al conjunto de apps que coinciden con el paquete.
  • Cuando registras un receptor, cualquier app puede enviar transmisiones potencialmente maliciosas al receptor de tu app. Existen varias formas de limitar las transmisiones que recibe tu app:

    • Puedes especificar un permiso cuando registras un receptor de transmisiones.
    • Para los receptores declarados en el manifiesto, puedes configurar el atributo android:exported como "false" en el manifiesto. El receptor no recibe transmisiones de fuentes fuera de la app.
  • El espacio de nombres para las acciones de emisión es global. Asegúrate de que los nombres de las acciones y otras cadenas se escriban en un espacio de nombres de tu propiedad. De lo contrario, es posible que, sin darte cuenta, entres en conflicto con otras apps.

  • Debido a que el método onReceive(Context, Intent) de un receptor se ejecuta en el subproceso principal, debe ejecutarse y regresar rápidamente. Si necesitas realizar un trabajo de larga duración, ten cuidado con la generación de subprocesos o el inicio de servicios en segundo plano, ya que el sistema puede eliminar todo el proceso después de que regrese onReceive(). Para obtener más información, consulta Efectos en el estado del proceso. Para realizar trabajos de larga duración, te recomendamos lo siguiente:

    • Llamar a goAsync() en el método onReceive() de tu receptor y pasar el BroadcastReceiver.PendingResult a un subproceso en segundo plano. Esto mantiene la transmisión activa después de regresar de onReceive(). Sin embargo, incluso con este enfoque, el sistema espera que termines con la transmisión muy rápido (en menos de 10 segundos). Te permite mover el trabajo a otro subproceso para evitar fallas en el subproceso principal.
    • Programar un trabajo con el JobScheduler. Para obtener más información, consulta Programación inteligente de trabajos.
  • No inicies actividades desde receptores de transmisión porque la experiencia del usuario es brusca, en especial si hay más de un receptor. En su lugar, considera mostrar una notificación.