A flutter plugin for dynamically changing app icon in mobile platform. Supports iOS and Android (IOS with version > 10.3
).
- Each android version will have different behavior, with Android 8 it may take a few seconds before we can notice the change
- Caution: Using this feature on some android versions will cause your app to crash (it will crash the first time you change the icon, next time it won't), it's a bad user experience that you have to crash the app to change the app icon, you can read more about this issue here
- Due to Splash screen problems of newest Android versions, please consider to remove the below code in your activivy and activity-alias tags:
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
- Add this code to your MainActivity.kt, in onCreate function:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
// Disable the Android splash screen fade out animation to avoid
// a flicker before the similar frame is drawn in Flutter.
splashScreen.setOnExitAnimationListener { splashScreenView -> splashScreenView.remove() }
}
- Add the latest version of the plugin to your
pubpsec.yaml
under dependencies section - Run
flutter pub get
- Update
android/src/main/AndroidManifest.xml
as follows:<application ...> <activity android:name=".MainActivity" android:launchMode="singleTop" android:theme="@style/LaunchTheme" android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode" android:hardwareAccelerated="true" android:windowSoftInputMode="adjustResize" android:enabled="true"> <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> <meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable" android:resource="@drawable/launch_background" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <!-- The activity-alias are your alternatives icons and name of your app, the default one must be enabled (and the others disabled) and the name must be ".DEFAULT". All the names of your activity-alias' name must begin with a dot. --> <!-- FOR NOW USE "icon_1" AS ALTERNATIVE ICON NAME --> <activity-alias android:label="Your app" android:icon="@mipmap/ic_launcher_1" android:name=".icon_1" android:enabled="false" android:targetActivity=".MainActivity"> <meta-data android:name="io.flutter.embedding.android.NormalTheme" android:resource="@style/NormalTheme" /> <meta-data android:name="io.flutter.embedding.android.SplashScreenDrawable" android:resource="@drawable/launch_background" /> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity-alias> </application>
- You can have multiple app icon, in your app you can now use:
- The name you pass in the method must be in the
AndroidManifest.xml
and for each icon, you must declare an activity-alias inAndroidManifest.xml
like above - Declare an list of string (your available app icons)
- Dont forget to add
MainActivity
to your list
const List<String> list = ["icon_1", "icon_2", "icon_n", "MainActivity"] DynamicIconFlutter.setIcon(icon: 'icon_1', listAvailableIcon: list);
- The name you pass in the method must be in the
2x
-120px x 120px
3x
-180px x 180px
To integrate your plugin into the iOS part of your app, follow these steps
-
First let us put a few images for app icons, they are
-
These icons shouldn't be kept in
Assets.xcassets
folder, but outside -
Next, we need to setup the
Info.plist
- Add
Icon files (iOS 5)
to the Information Property List - Add
CFBundleAlternateIcons
as a dictionary, it is used for alternative icons - Set 3 dictionaries under
CFBundleAlternateIcons
, they are correspond toteamfortress
,photos
, andchills
- For each dictionary, two properties —
UIPrerenderedIcon
andCFBundleIconFiles
need to be configured
- Add
Note that if you need it work for iPads, You need to add these icon declarations in CFBundleIcons~ipad
as well. See here for more details.
Here is Info.plist
after adding Alternate Icons
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIcons</key>
<dict>
<key>CFBundleAlternateIcons</key>
<dict>
<key>chills</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>chills</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>photos</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>photos</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>teamfortress</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>teamfortress</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string>chills</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
</dict>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>flutter_dynamic_icon_example</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
Now, you can call DynamicIconFlutter.setAlternateIconName
with the CFBundleAlternateIcons
key as the argument to set that icon.
From your Dart code, you need to import the plugin and use it's static methods:
import 'package:dynamic_icon_flutter/dynamic_icon_flutter.dart';
try {
if (await DynamicIconFlutter.supportsAlternateIcons) {
await DynamicIconFlutter.setAlternateIconName("photos");
print("App icon change successful");
return;
}
} on PlatformException catch (e) {
if (await DynamicIconFlutter.supportsAlternateIcons) {
await DynamicIconFlutter.setAlternateIconName(null);
print("Change app icon back to default");
return;
} else {
print("Failed to change app icon");
}
}