Flutter Magic: Changing App Icons Dynamically (Even on Stubborn Android!)

Piyush Kumar
4 min readAug 13, 2024

Hey there, Flutter wizards! 🧙‍♂️ Ever felt like your app could use a wardrobe change now and then? You know, like how Twitter and Snapchat strut their stuff with fancy new icons on special occasions? Well, buckle up, because we’re about to dive into the world of dynamic app icons! 🚀

iOS vs Android: A Tale of Two Platforms 🍎 vs 🤖

Let’s get real for a sec. If you’re working with iOS, changing app icons is like ordering pizza — easy peasy, lemon squeezy. 🍕 There’s a buffet of docs and APIs to choose from. But Android? Oh boy, it’s more like solving a Rubik’s cube while riding a unicycle. Blindfolded. In a hurricane. 🌪️

The Android Conundrum 🤔

Here’s the deal: Android doesn’t exactly roll out the red carpet for changing app icons on the fly. Most solutions out there are like using a sledgehammer to crack a nut — they’ll change your icon all alright, but they’ll also slam your app shut. Not cool, right?

Enter the Superhero: Activity Aliases to the Rescue! 🦸‍♂️

But fear not! We’ve got a trick up our sleeve — Activity Aliases. Think of them as your app’s secret identities. Clark Kent, meet Superman! 🦹‍♂️

Let’s Get This Party Started! 🎉

Step 1: Prep Your Flutter Project

  1. Add your icons: Prepare the different icons you want to switch between and add them to the res/mipmap directory in your Android project.
  2. Create aliases: In your AndroidManifest.xml, create activity aliases for each icon, similar to the example I provided below.

Step 2: Modify AndroidManifest.xml

Open up that AndroidManifest.xml file and let's give it a makeover. We’ll create two types of aliases:

  1. DefaultIconAlias: Enabled by default, representing your app’s primary icon.
  2. Additional icon aliases: For other alternative icons, also disabled by default.

In your android/app/src/main/AndroidManifest.xml file, add the following:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:theme="@style/Theme.AppTheme">

<!-- Launcher activity -->
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="@style/Theme.AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<!-- Default icon alias -->
<activity-alias
android:name=".DefaultIconAlias"
android:enabled="true"
android:icon="@mipmap/ic_launcher"
android:targetActivity=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>

<!-- Additional icon alias -->
<activity-alias
android:name=".NewYearIconAlias"
android:enabled="false"
android:icon="@mipmap/ic_new_year"
android:targetActivity=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>

<!-- Other aliases can be added here -->

</application>

</manifest>

Step 3: The Magic Behind the Curtain 🎩✨ Write the Native Android Code

Now, let’s write some Java/Kotlin voodoo in your MainActivity. Create a method to switch the app icon by toggling the activity-alias states. This will be written in Java/Kotlin inside the MainActivity class.

import android.content.ComponentName;
import android.content.pm.PackageManager;
import io.flutter.embedding.android.FlutterActivity;

public class MainActivity extends FlutterActivity {

public void changeAppIcon(String newIcon) {
PackageManager pm = getPackageManager();

// Enable new alias (newIcon)
pm.setComponentEnabledSetting(
new ComponentName(this, getPackageName() + "." + newIcon),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
);

// Disable current alias
pm.setComponentEnabledSetting(
new ComponentName(this, getPackageName() + ".DefaultIconAlias"),
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP
);
}
}

Step 4: Bridge the Gap — Flutter, Meet Android 🤝

Time to play matchmaker between Flutter and Android. You can use the platform channels to invoke the native Android code from Flutter.
In your Dart code, set up a method channel:

import 'package:flutter/services.dart';
class AppIconChanger {
static const platform = MethodChannel('app.icon');

static Future<void> changeIcon(String iconName) async {
try {
await platform.invokeMethod('changeAppIcon', {'iconName': iconName});
} on PlatformException catch (e) {
print("Failed to change app icon: ${e.message}");
}
}
}

Step 5: Handle Method Channel in Android

In your MainActivity, handle the method call:

@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "app.icon")
.setMethodCallHandler(
(call, result) -> {
if (call.method.equals("changeAppIcon")) {
String iconName = call.argument("iconName");
changeAppIcon(iconName);
result.success(null);
} else {
result.notImplemented();
}
}
);
}

Step 6: The Grand Finale 🎭 Change the Icon from Flutter

Now, in your Flutter code, you can work your magic. You can now call the AppIconChanger.changeIcon('NewYearIconAlias') method in your Flutter code to change the app icon.

ElevatedButton(
onPressed: () => AppIconChanger.changeIcon('NewYearIconAlias'),
child: Text('New Year, New Me! 🎉'),
)

The Fine Print (because there’s always fine print) 📜

  • This trick only works with icons you’ve packed into your app. No pulling rabbits out of empty hats!
  • The app will restart the first time you change the icon due to how Android handles alias changes. Subsequent changes won’t require a restart. It’s just Android being… Android. 🤷‍♂️

And there you have it, folks! You’re now equipped to give your app a face-lift whenever the mood strikes. Go forth and dazzle the world with your shape-shifting app icon prowess! 🌟

Remember, with great power comes great responsibility. Use your new icon-changing superpowers wisely! 😉

Happy coding, you magnificent Flutter magicians! 🧙‍♂️✨

--

--

Piyush Kumar

Fell in love with Flutter development. I build apps like it's my birthright.