flutter_dynamic_launcher_icon

pub version license

A Lightweight Flutter Plugin for Dynamic Launcher Icons

A lightweight Flutter plugin that lets you dynamically change your app's launcher icon at runtime โ€” with full Android and iOS support.


๐ŸŽฌ Demo

Demo of dynamic app icon change

๐Ÿ“ฑ Platform Behavior

Android Icon Change Behavior

On Android, icon changes work differently than iOS to ensure a smooth user experience:

  • Deferred Icon Application: - When you call changeIcon(), the request is saved but not immediately applied. - The icon change is deferred until the app goes to the background (e.g., when the user presses home or switches apps). - This prevents the app from being killed while the user is actively using it.

  • Why This Approach?: - Android requires disabling/enabling components to change icons, which can cause app restarts. - Immediate changes would interrupt the user's current session. - By waiting for the background state, the change happens at a natural transition point.


iOS Icon Change Behavior

iOS provides native support for alternate icons:

  • Instant application: - Icon changes apply immediately when changeIcon() is called (default: silent: false). - Uses Apple's public UIApplication.shared.setAlternateIconName() API. - Available on iOS 10.3+.
  • System alert (expected): - iOS shows a brief system confirmation when the home-screen icon changes. - This is required behavior for the public API and is appropriate for production apps.

The optional silent: true flag on changeIcon() is not recommended for production and should not be relied on.

What it tries to do Skip the iOS system alert when changing the icon.
How Uses a private UIKit API (_setAlternateIconName), not Apple's supported API.
Reliability Unreliable. It may have worked on older iOS versions, but on iOS 26+ the icon can still change while the alert is shown anyway.
App Store Uses private APIs โ†’ review risk and may conflict with App Store Review Guidelines (alternate icons are meant for explicit user choice, not hidden/automatic changes).
Maintenance Apple can change or remove private APIs in any iOS release without notice.

What to do instead

  • Use the default API: await FlutterDynamicLauncherIcon.changeIcon('AppIconDart'); (silent: false).
  • Treat the system alert as normal UX on iOS.
  • Do not ship silent: true in App Store builds.

The example app includes a "Silent (demo only)" button to illustrate the flag; it is for local testing only.


Table of Contents


๐Ÿงฉ Android Setup

๐Ÿ”ง Installation

Add the dependency to your pubspec.yaml:

dependencies:
  flutter_dynamic_launcher_icon: ^<latest_version>

Fetch the packages:

flutter pub get

๐Ÿงน Clean & Full Restart

Since this plugin includes native Android code, perform a clean build and fully restart the app:

flutter clean
flutter pub get
flutter run

๐Ÿ–ผ๏ธ Add Launcher Icons

Place your launcher icon image files inside the res/mipmap folders:

android/app/src/main/res/
  โ”œโ”€ mipmap-mdpi/
  โ”œโ”€ mipmap-hdpi/
  โ”œโ”€ mipmap-xhdpi/
  โ”œโ”€ mipmap-xxhdpi/
  โ””โ”€ mipmap-xxxhdpi/

Example filenames:

mipmap-mdpi/ic_launcher_dart.png
mipmap-hdpi/ic_launcher_dart.png
mipmap-xhdpi/ic_launcher_dart.png
mipmap-xxhdpi/ic_launcher_dart.png
mipmap-xxxhdpi/ic_launcher_dart.png

Repeat this for all alternate icons you want to use.

๐Ÿงพ AndroidManifest.xml Setup

Update your AndroidManifest.xml to define activity aliases for alternate icons:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  package="com.example.app">

  <application
    android:icon="@mipmap/ic_launcher"
    android:label="My App">

    <activity
      android:name=".MainActivity"
      android:exported="true"
      android:launchMode="singleTop"
      android:theme="@style/LaunchTheme">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity>

    <!-- Alternate Icon 1 -->
    <activity-alias
      android:name=".AppIconDart"
      android:enabled="false"
      android:icon="@mipmap/ic_launcher_dart"
      android:targetActivity=".MainActivity">
      <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
      </intent-filter>
    </activity-alias>

    <!-- Alternate Icon 2 -->
    <activity-alias
      android:name=".AppIconSwift"
      android:enabled="false"
      android:icon="@mipmap/ic_launcher_swift"
      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>

Notes:

  • android:enabled="false" keeps alternate icons disabled until activated.
  • android:targetActivity must always point to .MainActivity.
  • If your project uses an applicationIdSuffix or a custom setup, you may need to specify the fully qualified class name in android:name.
<activity-alias
        android:name="${applicationId}.AppIconDart"
        android:enabled="false"
        android:icon="@mipmap/ic_launcher_dart"
        android:targetActivity=".MainActivity">
        <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity-alias>

๐ŸŽ iOS Setup

๐Ÿงญ Steps in Xcode

  1. Open the ios/Runner project in Xcode.
  2. Navigate to Assets.xcassets and create a new folder: App Icons โ†’ New iOS App Icon.
  3. Add your alternate icons (e.g., AppIconDart, AppIconSwift) in the asset catalog.

App Icon Folder in Xcode

  1. Go to Runner โ†’ Build Settings and search for "Alternate App Icon Sets."
  2. Add the names of your alternate icons.

Alternate App Icon Setup

Notes:

  • Ensure the names in "Alternate App Icon Sets" match the icon set folder names.

๐Ÿš€ Usage

๐Ÿ“ฆ Import

import 'package:flutter_dynamic_launcher_icon/flutter_dynamic_launcher_icon.dart';

๐ŸŽฏ Change App Icon

To switch icons:

await FlutterDynamicLauncherIcon.changeIcon('AppIconDart');

To reset to the default icon:

await FlutterDynamicLauncherIcon.changeIcon(null);

On iOS, prefer the default call above. Avoid silent: true in production โ€” see iOS silent parameter.

โš™๏ธ Example

import 'package:flutter/material.dart';
import 'package:flutter_dynamic_launcher_icon/flutter_dynamic_launcher_icon.dart';

class IconSwitcherExample extends StatefulWidget {
  @override
  _IconSwitcherExampleState createState() => _IconSwitcherExampleState();
}

class _IconSwitcherExampleState extends State<IconSwitcherExample> {
  String? _currentIcon;

  @override
  void initState() {
    super.initState();
    _loadCurrentIcon();
  }

  Future<void> _loadCurrentIcon() async {
    final icon = await FlutterDynamicLauncherIcon.alternateIconName;
    setState(() => _currentIcon = icon);
  }

  Future<void> _changeIcon(String? iconName) async {
    await FlutterDynamicLauncherIcon.changeIcon(iconName);
    await _loadCurrentIcon();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Dynamic Icon Example')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Current Icon: ${_currentIcon ?? "Default"}'),
            ElevatedButton(
              onPressed: () => _changeIcon('AppIconDart'),
              child: Text('Switch to Dart Icon'),
            ),
            ElevatedButton(
              onPressed: () => _changeIcon('AppIconSwift'),
              child: Text('Switch to Swift Icon'),
            ),
            ElevatedButton(
              onPressed: () => _changeIcon(null),
              child: Text('Reset to Default'),
            ),
          ],
        ),
      ),
    );
  }
}

๐Ÿงฉ API Reference

Method Description
changeIcon(String? iconName, {bool silent}) Changes the launcher icon. Pass null to reset. On iOS, use silent: false (default) in production.
alternateIconName Returns the currently active icon name, or null if using the default icon.
isSupported Returns true if the platform supports dynamic icons.

silent (iOS only): Best-effort, uses private APIs, unreliable on iOS 26+, not recommended for App Store apps. See iOS silent parameter.


๐Ÿค Contributing

Contributions are welcome! Please feel free to submit a Pull Request.


๐Ÿ“œ License

This project is licensed under the MIT License.

Libraries

flutter_dynamic_launcher_icon
Dynamically change the app launcher icon on Android and iOS.