A flutter plugin for dynamically changing app icon in mobile platform. Supports iOS and Android (IOS with version > 10.3
).
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
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() }
}
pubpsec.yaml
under dependencies sectionflutter 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>
AndroidManifest.xml
and for each icon, you must declare an activity-alias in AndroidManifest.xml
like aboveMainActivity
to your list
const List<String> list = ["icon_1", "icon_2", "icon_n", "MainActivity"]
DynamicIconFlutter.setIcon(icon: 'icon_1', listAvailableIcon: list);
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
teamfortress@2x.png
, teamfortress@3x.png
photos@2x.png
, photos@3x.png
, chills@2x.png
, chills@3x.png
,These icons shouldn't be kept in Assets.xcassets
folder, but outside
Next, we need to setup the Info.plist
Icon files (iOS 5)
to the Information Property ListCFBundleAlternateIcons
as a dictionary, it is used for alternative iconsCFBundleAlternateIcons
, they are correspond to teamfortress
, photos
, and chills
UIPrerenderedIcon
and CFBundleIconFiles
need to be configuredNote 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");
}
}