Icon Switcher
A Flutter plugin to dynamically change your app icon at runtime. Supports iOS, Android, Web, macOS, Windows, and Linux.
Migrating from
mobile_icon_switcher? See the Migration Guide at the bottom.
Platform Support
| Platform | What changes | Persistence | Setup required |
|---|---|---|---|
| iOS | Launcher icon | Permanent | Info.plist + icon files |
| Android | Launcher icon | Permanent | AndroidManifest + activity-aliases |
| Web | Browser tab favicon | Session only (tab lifetime) | Favicon files in web/ |
| macOS | Dock icon | Temporary (resets on restart) | Bundle icon assets |
| Windows | Window + taskbar icon | Temporary (resets on restart) | Bundle icon assets |
| Linux | Window icon | Temporary (resets on restart) | Bundle icon assets |
Installation
dependencies:
basic_icon_switcher: ^1.0.0
Quick Start
import 'package:basic_icon_switcher/basic_icon_switcher.dart';
// Switch to an alternate icon
await IconSwitcher.changeIcon(
iconName: 'dark',
androidActivityAlias: 'com.example.myapp.Dark', // Android only
webFaviconUrl: 'icons/dark.png', // Web only
desktopIconAsset: 'assets/icons/dark.png', // macOS/Windows/Linux
);
// Reset to default
await IconSwitcher.resetIcon();
// Check current icon (iOS/Android)
final current = await IconSwitcher.getCurrentIcon(); // null = default
// Check if supported
final supported = await IconSwitcher.isSupported;
Platform Setup
iOS
Click to expand
Prerequisites
- iOS 12.0+
- Icon images in @1x, @2x, and @3x sizes. Generate them at appicon.co.
Steps
- Open
Runner.xcworkspacein Xcode. - Create a folder named
App Iconsin the Runner group. - Add your icon files:
IconName.png(1x)IconName@2x.png(2x)IconName@3x.png(3x)
- Edit
Info.plistto declare alternate icons:
<key>CFBundleIcons</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>dark</key>
<dict>
<key>UIPrerenderedIcon</key>
<false/>
<key>CFBundleIconFiles</key>
<array>
<string>dark</string>
</array>
</dict>
<key>light</key>
<dict>
<key>UIPrerenderedIcon</key>
<false/>
<key>CFBundleIconFiles</key>
<array>
<string>light</string>
</array>
</dict>
</dict>
</dict>
- Use in Dart:
await IconSwitcher.changeIcon(iconName: 'dark');
Android
Click to expand
Prerequisites
- Android minSdk 21+
- Icon images in mipmap format. Generate them at appicon.co.
- Your
applicationId(e.g.,com.example.myapp)
Steps
-
Place icon images in the mipmap folders under
android/app/src/main/res/(mipmap-hdpi,mipmap-mdpi,mipmap-xhdpi,mipmap-xxhdpi,mipmap-xxxhdpi). -
Add activity-aliases to
AndroidManifest.xml(after the</activity>tag):
<activity-alias
android:name=".Dark"
android:targetActivity=".MainActivity"
android:icon="@mipmap/dark"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
- Create a Kotlin/Java class for each alias in your
MainActivity.kt:
package com.example.myapp
import io.flutter.embedding.android.FlutterActivity
class MainActivity: FlutterActivity()
class Dark: FlutterActivity()
- Use in Dart:
await IconSwitcher.changeIcon(
iconName: 'dark',
androidActivityAlias: 'com.example.myapp.Dark',
);
Note: Unlike the previous version (
mobile_icon_switcher), you no longer need to callsetDefaultComponent(). The plugin auto-detects the default launcher activity.
Web
Click to expand
Steps
-
Place your alternate favicon files in the
web/directory (or a subfolder likeweb/icons/):web/icons/dark.pngweb/icons/light.png
-
Make sure your
web/index.htmlhas a favicon link:
<link rel="icon" type="image/png" href="favicon.png" />
- Use in Dart:
await IconSwitcher.changeIcon(
iconName: 'dark',
webFaviconUrl: 'icons/dark.png',
);
Note: Favicon changes are session-only — they reset when the tab is closed.
macOS
Click to expand
Steps
- Add your icon PNG files as Flutter assets in
pubspec.yaml:
flutter:
assets:
- assets/icons/
-
Place icon files in
assets/icons/(e.g.,dark.png,light.png). -
Use in Dart:
await IconSwitcher.changeIcon(
iconName: 'dark',
desktopIconAsset: 'assets/icons/dark.png',
);
Note: The dock icon change is temporary — it resets when the app restarts. To persist your choice, store the selected icon name (e.g., in
SharedPreferences) and callchangeIcon()again on app startup.
Windows
Click to expand
Steps
Same as macOS — add PNG assets and pass desktopIconAsset:
await IconSwitcher.changeIcon(
iconName: 'dark',
desktopIconAsset: 'assets/icons/dark.png',
);
Note: Changes the window titlebar and taskbar icon. Resets on restart.
Linux
Click to expand
Steps
Same as macOS/Windows — add PNG assets and pass desktopIconAsset:
await IconSwitcher.changeIcon(
iconName: 'dark',
desktopIconAsset: 'assets/icons/dark.png',
);
Note: Changes the window decoration icon. Resets on restart.
API Reference
IconSwitcher.changeIcon()
static Future<bool> changeIcon({
required String iconName,
String? androidActivityAlias,
String? webFaviconUrl,
String? desktopIconAsset,
})
| Parameter | Required on | Description |
|---|---|---|
iconName |
iOS, Android | Icon name matching platform config |
androidActivityAlias |
Android | Fully qualified activity-alias class name |
webFaviconUrl |
Web | URL/path to favicon file |
desktopIconAsset |
macOS, Windows, Linux | Flutter asset path to PNG |
IconSwitcher.resetIcon()
Resets to the default icon on all platforms.
IconSwitcher.getCurrentIcon()
Returns the current icon name, or null if the default is active. Currently supported on iOS and Android only.
IconSwitcher.isSupported
Returns true if icon switching is supported on the current platform.
Platform Limitations
| Platform | Limitation |
|---|---|
| iOS | Shows a system alert when the icon changes (iOS limitation, cannot be suppressed) |
| Android | May briefly kill the app on some devices when switching icons |
| Web | Favicon change is session-only; resets on page reload or tab close |
| macOS | Dock icon resets when the app restarts |
| Windows | Window icon resets when the app restarts |
| Linux | Window icon resets when the app restarts; behavior varies by window manager |
Migration from mobile_icon_switcher
Breaking Changes
- Package name:
mobile_icon_switcher→basic_icon_switcher - Class name:
MobileIconSwitcher→IconSwitcher setDefaultComponent()removed: No longer needed — the Android plugin auto-detects the default component.changeIcon()signature changed: Now uses named parameters.platformVersionremoved: Use Flutter's built-in platform detection instead.
Before (mobile_icon_switcher)
import 'package:mobile_icon_switcher/mobile_icon_switcher.dart';
// Required on Android
MobileIconSwitcher.setDefaultComponent("com.example.app.MainActivity");
// Change icon
await MobileIconSwitcher.changeIcon('dark', 'com.example.app.Dark');
// Reset
await MobileIconSwitcher.resetIcon();
After (basic_icon_switcher)
import 'package:basic_icon_switcher/basic_icon_switcher.dart';
// Change icon (no setDefaultComponent needed!)
await IconSwitcher.changeIcon(
iconName: 'dark',
androidActivityAlias: 'com.example.app.Dark',
);
// Reset
await IconSwitcher.resetIcon();
The first argument here is the IconName, this part is necessary for IOS mostly, the second argument is the Activity with the ApplicationId of Android.
Reseting the Apps Icon to default
To revert the app icon to its default after you have completed the iOS and/or Android Setup mentioned above, you can simply call this method:
await MobileIconSwitcher.resetIcon();
This method doesn’t require any arguments. Calling this will reset the app icon to the default one set in your project, whether you’re on iOS or Android. Remember to handle any possible errors that might occur while resetting, ensuring a smooth user experience.
Note: For IOS there is a real option to reset the App's icon for Android, there isn't therefore I will just set the Default Component as the "new" App Icon.
Note
Please be aware that the Android solution is as stated before not the best solution but however it works, for me it takes a bit until Android updates the App on the Homescreen so pressing on an Icon and getting the message Unknown App or something like this can happen! It takes a few moments and than the App is again back with the new Icon and can be started without any issues.