all_app_icon

Português | English

Beta Flutter plugin for changing the application launcher icon at runtime on Android and iOS.

all_app_icon keeps the Dart API small: discover configured alternate icons, read the current icon, switch to another icon, restore the default icon, and optionally defer Android icon swaps until the app goes to the background.

Beta status: this package is currently used as a local plugin by Tatame Master. The API is intentionally small and may still change before a stable public release.

Features

  • Android and iOS support.
  • No external Dart dependencies.
  • Discovers available Android icons from launcher activity-alias entries.
  • Reads available iOS icons from CFBundleAlternateIcons.
  • Restores the default icon with setAlternateIconName(null).
  • Optional deferred Android swap to avoid foreground launcher refresh issues on OEM launchers such as MIUI, EMUI, OneUI and ColorOS.
  • Android recovery path for pending icon changes after process restart.

Installing

Because this is still a beta release, use the prerelease constraint:

dependencies:
  all_app_icon: ^0.1.0-beta.1

Then import it:

import 'package:all_app_icon/all_app_icon.dart';

Quick Start

final supported = await AllAppIcon.supportsAlternateIcons;

if (supported) {
  final icons = await AllAppIcon.getAvailableIcons();

  await AllAppIcon.setAlternateIconName(
    icons.first,
    deferUntilBackground: true,
  );
}

Restore the default launcher icon:

await AllAppIcon.setAlternateIconName(null);

Android Setup

Android icons are configured in the host app manifest as launcher activity-alias entries. The plugin looks for aliases that follow this naming pattern:

${applicationId}.MainActivity.<iconName>

Example:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
  <application>
    <activity
      android:name=".MainActivity"
      android:exported="true"
      android:theme="@style/LaunchTheme">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>

    <activity-alias
      android:name=".MainActivity.dark"
      android:enabled="false"
      android:exported="true"
      android:icon="@mipmap/ic_launcher_dark"
      android:roundIcon="@mipmap/ic_launcher_dark_round"
      android:targetActivity=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity-alias>
  </application>
</manifest>

With the example above, getAvailableIcons() returns dark, and you can use:

await AllAppIcon.setAlternateIconName('dark');

To return to the default MainActivity launcher icon:

await AllAppIcon.setAlternateIconName(null);

Deferred Android Changes

Changing Android launcher components while the app is foregrounded can make some launchers send the user back to the home screen. To avoid that, queue the change and apply it when the app is paused:

class AppLifecycleIconApplier with WidgetsBindingObserver {
  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.paused) {
      AllAppIcon.applyPendingIcon();
    }
  }
}

Queue the icon change:

await AllAppIcon.setAlternateIconName(
  'dark',
  deferUntilBackground: true,
);

applyPendingIcon() is safe to call when there is no pending change. On iOS it is a no-op.

iOS Setup

iOS alternate icons must be declared in the host app Info.plist under CFBundleIcons > CFBundleAlternateIcons.

Example:

<key>CFBundleIcons</key>
<dict>
  <key>CFBundlePrimaryIcon</key>
  <dict>
    <key>CFBundleIconFiles</key>
    <array>
      <string>AppIcon</string>
    </array>
  </dict>
  <key>CFBundleAlternateIcons</key>
  <dict>
    <key>dark</key>
    <dict>
      <key>CFBundleIconFiles</key>
      <array>
        <string>AppIconDark</string>
      </array>
    </dict>
  </dict>
</dict>

With the example above, getAvailableIcons() returns dark.

await AllAppIcon.setAlternateIconName('dark');
await AllAppIcon.setAlternateIconName(null); // restore default

iOS normally shows a system confirmation alert when the app icon changes. The showAlert argument defaults to true. Setting it to false uses a private, undocumented iOS selector and should be treated as experimental:

await AllAppIcon.setAlternateIconName(
  'dark',
  showAlert: false,
);

API

class AllAppIcon {
  static Future<bool> get supportsAlternateIcons;

  static Future<List<String>> getAvailableIcons();

  static Future<String?> getAlternateIconName();

  static Future<void> setAlternateIconName(
    String? iconName, {
    bool showAlert = true,
    bool deferUntilBackground = false,
  });

  static Future<void> applyPendingIcon();
}

supportsAlternateIcons

Returns whether the current platform supports dynamic launcher icons.

  • Android: returns true.
  • iOS: returns UIApplication.shared.supportsAlternateIcons on iOS 10.3+.

getAvailableIcons()

Returns the configured alternate icon names.

  • Android: reads aliases named .MainActivity.<iconName>.
  • iOS: reads keys from CFBundleAlternateIcons.

getAlternateIconName()

Returns the current alternate icon name, or null when the default icon is active. On Android, a pending deferred change is reported as the current value so the Dart side does not observe stale state after queueing a change.

setAlternateIconName(iconName)

Changes the launcher icon.

  • Pass an icon name returned by getAvailableIcons().
  • Pass null to restore the default icon.
  • Throws a PlatformException when the icon is invalid or the platform call fails.

applyPendingIcon()

Android-only helper that applies a deferred icon change immediately. It is intended to be called from an app lifecycle handler when the app moves to the background. On iOS this method completes without doing work.

Limitations

  • This package does not generate launcher icons or modify native project files. Icons must be configured in Android and iOS manually.
  • Android launchers cache icons aggressively; the visible change can depend on the device launcher.
  • The package expects Android launcher aliases to target .MainActivity.
  • iOS alternate icons require iOS 10.3 or newer.
  • Suppressing the iOS icon-change alert uses private API and is not recommended for production App Store builds.

License

MIT.

Libraries

all_app_icon