Ir al contenido
charmotion

Íconos alternativos de app en iOS, Android, Expo y Flutter

Por el equipo de Charmotion · Actualizado el

Ilustración de portada de la guía: íconos alternativos de app en iOS, Android, Expo y Flutter, con personajes de demostración de Charmotion

Las apps pueden permitir que los usuarios elijan entre íconos alternativos, pero solo entre los que vienen incluidos en la app, y el cambio reemplaza una imagen estática por otra. iOS usa setAlternateIconName con sets de íconos declarados al compilar. Android no tiene una API específica; las apps suelen activar y desactivar entradas activity-alias. Expo y Flutter envuelven ambos mecanismos mediante plugins como expo-alternate-app-icons.

Puntos clave

  • Cada ícono alternativo debe venir incluido en la app; no puedes descargar uno nuevo en tiempo de ejecución.
  • En iOS, comprueba supportsAlternateIcons y luego llama a setAlternateIconName; nil restaura el ícono principal.
  • Los íconos alternativos de iOS necesitan sus propias variantes oscura, transparente y tintada, y deben parecerse a tu app.
  • Cambiar el ícono en Android mediante activity-alias es un patrón habitual, no una API oficial de íconos, y tiene efectos secundarios reportados.
  • Alternar íconos no es animación; para tener movimiento, usa una intro de inicio o una mascota de marca dentro de la app.

¿Ya tienes un personaje o logo? Mira tu personaje en pantallas reales de una app: pantallas de splash, onboarding, carga y estado vacío. Es gratis, funciona en tu navegador y no sube nada.

¿Cómo funcionan los íconos alternativos de app en iOS?

Agrega los sets de íconos adicionales a tu catálogo de assets y enuméralos en el ajuste de compilación "Alternate App Icon Sets" del target; Xcode genera las entradas CFBundleAlternateIcons dentro de CFBundleIcons. Después, cambia el ícono en tiempo de ejecución (Apple Developer Documentation):

func setIcon(_ name: String?) {
    guard UIApplication.shared.supportsAlternateIcons else { return }
    UIApplication.shared.setAlternateIconName(name) { error in
        if let error { print("Icon change failed: \(error)") }
    }
}

setIcon("IconNight")  // a declared alternate icon set
setIcon(nil)          // back to the primary icon

El completion handler se ejecuta en una cola proporcionada por UIKit, no necesariamente en la cola principal, así que pasa al main actor antes de actualizar la interfaz. Apple indica que el método sigue funcionando en apps compatibles de iPhone y iPad que se ejecutan en visionOS, pero los íconos alternativos no están disponibles en apps compiladas con el SDK de visionOS.

Las reglas de diseño vienen de las HIG: en iOS y iPadOS, los íconos alternativos necesitan sus propias variantes oscura, transparente y tintada, todas sujetas a App Review (Apple HIG), y la directriz 2.3.8 pide que los íconos alternativos se mantengan similares a los demás íconos de tu app (App Review Guidelines).

¿Se puede cambiar el ícono de la app por código en Android?

No existe una API de Android llamada "set icon". El patrón que suelen usar las apps se construye con dos piezas oficiales: un <activity-alias>, que presenta tu actividad de inicio como una entrada separada con su propio android:icon y un indicador android:enabled (Android Developers), y PackageManager.setComponentEnabledSetting para activar y desactivar los alias.

<activity-alias
    android:name=".MainActivityNight"
    android:targetActivity=".MainActivity"
    android:icon="@mipmap/ic_launcher_night"
    android:enabled="false"
    android:exported="true">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>
</activity-alias>
fun switchIcon(context: Context, enable: String, disable: String) {
    val pm = context.packageManager
    pm.setComponentEnabledSetting(ComponentName(context, enable),
        PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP)
    pm.setComponentEnabledSetting(ComponentName(context, disable),
        PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP)
}

Como esto cambia qué componentes del launcher existen, el comportamiento depende del launcher. Algunos desarrolladores han reportado que la app se cierra al hacer el cambio y que los deep links requieren cuidado cuando hay varios alias (Back Market Engineering). Prueba en varios launchers, haz el cambio mientras el usuario está en los ajustes y mantén exactamente un alias activado a la vez.

¿Cómo se cambia el ícono de la app en Expo?

Usa un config plugin, ya que los íconos son recursos nativos. expo-alternate-app-icons copia tus íconos en los proyectos nativos durante el prebuild y expone supportsAlternateIcons y setAlternateAppIcon(name), donde null restablece el ícono predeterminado (GitHub). Su README indica compatibilidad con Expo SDK 51+ y con iOS y Android, con imágenes clara, oscura y tintada de iOS para cada ícono, y un primer plano adaptativo de Android más un color de fondo.

// app.json (excerpt)
["expo-alternate-app-icons", [
  { "name": "IconNight",
    "ios": { "light": "./assets/night.png", "dark": "./assets/night-dark.png", "tinted": "./assets/night-tinted.png" },
    "android": { "foregroundImage": "./assets/night-fg.png", "backgroundColor": "#0E1116" } }
]]

// in a settings screen
import { setAlternateAppIcon } from "expo-alternate-app-icons";
await setAlternateAppIcon("IconNight");

Ejecuta npx expo prebuild --clean después de editar el plugin y usa un development build: los config plugins y los módulos nativos no se aplican en Expo Go (Expo).

¿Cómo se cambia el ícono de la app en Flutter?

Con un plugin que llama a los mecanismos de plataforma descritos arriba. flutter_dynamic_icon_plus se describe como un plugin para cambiar dinámicamente el ícono de la app en iOS 10.3+ y Android (pub.dev). Aun así, debes declarar cada ícono de forma nativa: sets de íconos alternativos en el proyecto de iOS y entradas activity-alias en el manifest de Android, como explica el README del plugin.

Revisa el estado de mantenimiento del plugin y sus issues abiertos antes de depender de él, porque cambiar el ícono afecta comportamientos de la plataforma que varían entre versiones del sistema operativo. La configuración nativa de las dos secciones anteriores es lo que el plugin envuelve, así que vale la pena entenderla en cualquier caso.

¿Puedes alternar íconos para simular un ícono animado?

No. Cada cambio es un paso deliberado entre íconos estáticos, no una reproducción, y la demo de 2024 que alternaba íconos lo bastante rápido como para parecer animados dependía de un método privado para omitir la confirmación que ve el usuario (9to5Mac). La directriz 2.5.1 solo permite API públicas. En Android, activar y desactivar componentes del launcher repetidamente chocaría con el launcher y, según los reportes mencionados arriba, puede cerrar la app.

Si lo que buscas es movimiento, ponlo donde sí es compatible: una intro de inicio de tu ícono en la primera pantalla, una mascota de marca dentro de la app o tu sitio web. La guía del ícono de app animado enumera todas las opciones.

¿Qué usos tienen los íconos alternativos de app?

  • Elección personal: una versión oscura, clara o minimalista, o un equipo o tema, que es el ejemplo que dan las HIG de Apple con una app deportiva.
  • Un beneficio: íconos adicionales para suscriptores o por alcanzar un hito.
  • Variantes de temporada, elegidas por el usuario en lugar de cambiarse sin avisar.

Haz que cada variante se reconozca claramente como tu app. Las HIG de Apple advierten contra íconos que alguien podría confundir con otra app, y los íconos alternativos pasan por App Review igual que tu ícono principal.

Preguntas frecuentes

¿Puedo descargar un ícono de app nuevo desde mi servidor?

No. En iOS, setAlternateIconName solo acepta íconos declarados en el bundle de la app al compilarla, y los íconos de activity-alias de Android son recursos de tu APK o bundle. Para tener íconos nuevos necesitas actualizar la app.

¿iOS avisa al usuario cuando una app cambia su ícono?

Sí. Al cambiar el ícono con setAlternateIconName, el usuario ve una confirmación. Por eso la demo de ícono animado de 2024 tuvo que llamar a la API mediante un método privado para omitirla. Vincula los cambios de ícono a una elección explícita en tu pantalla de ajustes y comprueba primero supportsAlternateIcons.

¿Los íconos alternativos admiten los modos oscuro y tintado?

En iOS y iPadOS es obligatorio: las HIG de Apple indican que los íconos alternativos requieren sus propias variantes oscura, transparente y tintada. En Android, asigna a cada alias un ícono adaptativo con una capa monocromática para que los íconos temáticos funcionen en Android 13 y versiones posteriores.

Respuestas rápidas de esta guía

Fuentes

Guías relacionadas