dynamic_app_icon_flutter_plus 0.0.8
dynamic_app_icon_flutter_plus: ^0.0.8 copied to clipboard
Dynamic App Icon for Flutter enables Flutter apps to change their launcher icon at runtime, ideal for branding updates, seasonal themes, and feature-based icon switching.
dynamic_app_icon_flutter_plus #
A Flutter plugin for dynamically changing app icons on Android and iOS.
|
Android |
iOS |
Features π #
- π¨ Android Support: Change app icons using activity aliases
- π iOS Support: Use alternate app icons (iOS 10.3+)
- π Auto-Discovery: Automatically finds all available icons from configuration
- π No Hardcoding: Fully dynamic, client-driven configuration
- π± Cross-Platform: Works seamlessly on both Android and iOS
Installation #
Add this to your package's pubspec.yaml file:
dependencies:
dynamic_app_icon_flutter_plus: ^0.0.1
Then run:
flutter pub get
Quick Start π #
Let's get you started with dynamic app icons in no time!
import 'package:dynamic_app_icon_flutter_plus/dynamic_app_icon_flutter_plus.dart';
// Check if dynamic icons are supported on this platform
bool supported = await DynamicAppIconFlutterPlus.supportsAlternateIcons;
// Get all available icons
List<String> icons = await DynamicAppIconFlutterPlus.getAvailableIcons();
// Get the currently active icon
String? currentIcon = await DynamicAppIconFlutterPlus.getAlternateIconName();
// Change to a different icon
await DynamicAppIconFlutterPlus.setAlternateIconName('dark');
// Restore default icon
await DynamicAppIconFlutterPlus.setAlternateIconName(null);
That's it! You're ready to change app icons dynamically. π
API Reference π #
supportsAlternateIcons #
Check if the current platform supports dynamic app icons.
Returns: Future<bool> - true if supported, false otherwise
Example:
bool supported = await DynamicAppIconFlutterPlus.supportsAlternateIcons;
if (supported) {
print('Dynamic icons are supported!');
} else {
print('Dynamic icons not supported on this platform');
}
Platform Support:
- β
Android: Always returns
true - β
iOS: Returns
trueon iOS 10.3+,falseotherwise
getAlternateIconName() #
Get the name of the currently active alternate icon.
Returns: Future<String?> - The icon name if an alternate icon is active, null if using the default icon
Example:
String? currentIcon = await DynamicAppIconFlutterPlus.getAlternateIconName();
if (currentIcon == null) {
print('Using default icon');
} else {
print('Current icon: $currentIcon');
}
Note: Returns null when the default app icon is active.
getAvailableIcons() #
Get a list of all available alternate icon names that can be used.
Returns: Future<List<String>> - List of available icon names
Example:
List<String> availableIcons = await DynamicAppIconFlutterPlus.getAvailableIcons();
print('Available icons: $availableIcons');
// Output: Available icons: [dark, light]
Platform Behavior:
- Android: Dynamically discovers all activity aliases from
AndroidManifest.xmlthat follow the patternpackage.MainActivity.iconName - iOS: Reads icon names from
Info.plistunderCFBundleAlternateIcons
Note: The "default" alias is automatically excluded from this list on Android.
setAlternateIconName(iconName, {showAlert}) #
Set the app icon to the specified alternate icon, or restore the default icon.
Parameters:
iconName(String?): The name of the icon to set, ornullto restore the default iconshowAlert(bool, optional): iOS only - Whether to show the system alert when changing icons. Defaults totrue.
Returns: Future<void>
Throws: PlatformException if the icon name doesn't exist or there's an error
Example:
// Set an alternate icon
await DynamicAppIconFlutterPlus.setAlternateIconName('dark');
// Set icon without alert on iOS (use at your own risk)
await DynamicAppIconFlutterPlus.setAlternateIconName('light', showAlert: false);
// Restore default icon
await DynamicAppIconFlutterPlus.setAlternateIconName(null);
Platform Behavior:
- Android: Enables the corresponding activity alias and disables others
- iOS: Changes the app icon using
UIApplication.setAlternateIconName()
iOS Alert Suppression:
The showAlert parameter uses a private API on iOS to suppress the system alert. Use this at your own risk as it may break in future iOS versions.
Platform Setup π§ #
Android Setup #
1. Configure AndroidManifest.xml
Add activity aliases for each alternate icon. The plugin automatically discovers all aliases following the pattern: package.MainActivity.iconName
Important: The main activity must have exported="true" and a launcher intent-filter to serve as the default icon.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="Your App Name"
android:icon="@mipmap/ic_launcher">
<!-- Main Activity - Used as default icon launcher -->
<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="com.example.yourapp.MainActivity.dark"
android:targetActivity=".MainActivity"
android:exported="true"
android:icon="@mipmap/ic_launcher_dark"
android:label="@string/app_name"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
<!-- Alternate icon 2 - Add as many as you need -->
<activity-alias
android:name="com.example.yourapp.MainActivity.light"
android:targetActivity=".MainActivity"
android:exported="true"
android:icon="@mipmap/ic_launcher_light"
android:label="@string/app_name"
android:enabled="false">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
</application>
</manifest>
2. Create Icon Resources
For each alternate icon, create icon files in all density folders. You must provide icons for all density variants:
![]()
-
Navigate to your Android app's
resdirectory (e.g.,android/app/src/main/res/) -
For each alternate icon, create icon files in all density folders:
mipmap-mdpi/ic_launcher_{iconName}.pngmipmap-hdpi/ic_launcher_{iconName}.pngmipmap-xhdpi/ic_launcher_{iconName}.pngmipmap-xxhdpi/ic_launcher_{iconName}.pngmipmap-xxxhdpi/ic_launcher_{iconName}.png
-
Example structure for multiple icons:
res/ mipmap-mdpi/ ic_launcher.png (default icon - required) ic_launcher_dark.png (alternate icon) ic_launcher_light.png (alternate icon) mipmap-hdpi/ ic_launcher.png ic_launcher_dark.png ic_launcher_light.png mipmap-xhdpi/ ic_launcher.png ic_launcher_dark.png ic_launcher_light.png mipmap-xxhdpi/ ic_launcher.png ic_launcher_dark.png ic_launcher_light.png mipmap-xxxhdpi/ ic_launcher.png ic_launcher_dark.png ic_launcher_light.png
Important:
- Replace
{iconName}with your actual icon name (e.g.,dark,light) - The icon name in the filename must match the name used in the
activity-aliasinAndroidManifest.xml - Ensure all density variants are provided for each icon
- The default icon (
ic_launcher.png) is required and should be present in all density folders
iOS Setup #
Configure Info.plist
Add alternate icons configuration to your Info.plist. Important: You must include both the alternate icons (CFBundleAlternateIcons) and the default/primary icon (CFBundlePrimaryIcon) configuration:
<key>CFBundleIcons</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>dark</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>dark</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>light</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>light</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>default</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundleIcons~ipad</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>dark</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>dark</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>light</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>light</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>default</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
Note: The CFBundlePrimaryIcon configuration for the default icon is required. Make sure to include it in both CFBundleIcons (for iPhone) and CFBundleIcons~ipad (for iPad) sections. The default icon name should match the icon files you place in the App Icon folder (e.g., default@2x.png and default@3x.png).
Add Icon Assets
![]()
-
Open your project in Xcode
-
Create an
App Iconfolder in yourRunnerdirectory (e.g.,ios/Runner/App Icon/) -
Add icon image files for each icon (including the required default icon) with the following naming convention:
- For each icon name (e.g.,
dark,light,default), add:{iconName}@2x.png(120x120 pixels for iPhone){iconName}@3x.png(180x180 pixels for iPhone)
Important: You must include the default icon files. Example files:
default@2x.png(required - for default/primary icon)default@3x.png(required - for default/primary icon)dark@2x.png(for alternate icon)dark@3x.png(for alternate icon)light@2x.png(for alternate icon)light@3x.png(for alternate icon)
- For each icon name (e.g.,
-
Ensure the icon names in your files match the keys used in
Info.plist(e.g., if you use"dark"in Info.plist, name your filesdark@2x.pnganddark@3x.png) -
Open
Runner.xcworkspacein Xcode (notRunner.xcodeproj) -
Right-click on
Runnerin the project navigator and select "Add Files to 'Runner'"
-
Select the
App Iconfolder you created in step 2
-
In the dialog that appears, select "Create folder references" (not "Create groups") and click "Add"

Requirements:
- iOS 10.3 or later
- Icon files must be placed in the
App Iconfolder within your Runner directory - Provide both @2x and @3x versions for each alternate icon
Complete Example π‘ #
Here's a complete example showing how to build an icon selector:
import 'package:flutter/material.dart';
import 'package:dynamic_app_icon_flutter_plus/dynamic_app_icon_flutter_plus.dart';
class IconSelector extends StatefulWidget {
@override
_IconSelectorState createState() => _IconSelectorState();
}
class _IconSelectorState extends State<IconSelector> {
List<String> availableIcons = [];
String? currentIcon;
bool isLoading = true;
@override
void initState() {
super.initState();
_loadIcons();
}
Future<void> _loadIcons() async {
final icons = await DynamicAppIconFlutterPlus.getAvailableIcons();
final current = await DynamicAppIconFlutterPlus.getAlternateIconName();
setState(() {
availableIcons = icons;
currentIcon = current;
isLoading = false;
});
}
Future<void> _setIcon(String? iconName) async {
try {
await DynamicAppIconFlutterPlus.setAlternateIconName(iconName);
await _loadIcons();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Icon changed successfully!')),
);
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Error: $e')),
);
}
}
@override
Widget build(BuildContext context) {
if (isLoading) {
return Center(child: CircularProgressIndicator());
}
return ListView(
children: [
// Default icon option
ListTile(
title: Text('Default'),
trailing: currentIcon == null ? Icon(Icons.check) : null,
onTap: () => _setIcon(null),
),
// Alternate icons
...availableIcons.map((iconName) => ListTile(
title: Text(iconName),
trailing: currentIcon == iconName ? Icon(Icons.check) : null,
onTap: () => _setIcon(iconName),
)),
],
);
}
}
For a complete example with a beautiful UI, check out the example directory.
How It Works π #
Android #
The plugin uses Android's activity aliases feature:
- Each alternate icon is configured as an
activity-aliastargeting the main activity - The plugin dynamically discovers all aliases from
AndroidManifest.xml - When changing icons, it enables the target alias and disables others
- The main activity serves as the default icon launcher
iOS #
The plugin uses iOS's alternate app icons feature:
- Alternate icons are configured in
Info.plistunderCFBundleAlternateIcons - The plugin reads available icons from the Info.plist
- Uses
UIApplication.setAlternateIconName()to change icons - Returns
nullwhen the default icon is active
Notes β οΈ #
- Android: After changing the icon, users may need to go to the home screen to see the change
- Android: The icon change happens immediately
- iOS: Changing icons may show a system alert (can be suppressed with
showAlert: false) - iOS: Requires iOS 10.3 or later
- All activity aliases (Android) must target the same MainActivity
- Only one icon can be active at a time
License #
MIT License - see LICENSE file for details.