Building Dynamic App Icons in Android

5 min read

Introduction

Have you ever glanced at your mobile screen and noticed an app’s icon looking fresh and different from before? This isn’t just visual flair; it’s the magic of dynamic app icons at play. This fascinating feature allows Android apps to change their icons dynamically, all without needing updates from the Play Store! It’s a subtle yet powerful strategy to engage users and add vibrancy to your app. Though it might seem like advanced wizardry, mastering dynamic app icons is absolutely within your reach. Let’s embark on this learning journey together!

If you’re new to Android development or even if you’ve been in the game for years, you might not have explored the intriguing world of dynamic app icons yet. But fear not! This guide is designed to demystify the process, offering a step-by-step journey into creating dynamic app icons in Android. Whether you’re just starting your coding adventure or looking to add another skill to your toolkit, this post is here to guide you through enhancing your app’s user experience in a unique way.

Why Dynamic App Icons?

Imagine, for instance, your app’s icon changing to celebrate a holiday, additionally adapting to user-preferred themes, or perhaps indicating a new feature. It’s not just about looking pretty – it’s about creating a dynamic interaction between your app and its users. Let’s dive into how you can make this happen.

Implement Icon Change Logic

Before we jump into the code, let’s clarify a few things to ensure everyone is on the same page. In the world of Android, your app’s front door is represented by its icon. It’s the first thing users interact with, so making it dynamic can significantly enhance their experience.

In this section, we’ll dive into the core of dynamic app icons in Android by implementing the logic responsible for changing the app’s icon dynamically. We’ll walk through the code step by step, explaining what each part does.

Setting the Stage in Your AndroidManifest.xml

There’s an essential step we need to address in your AndroidManifest.xml file. If you want your app to strut its stuff with dynamic icon changes, you’ve got to set up an activity alias for your main activity.

Understanding Activity Aliases

In Android, you can create activity aliases to the main activity in your manifest file to enable dynamic app icon changes. These aliases allow you to associate different icons with the same main activity, and you can enable or disable them programmatically to change the app’s icon dynamically.

Think of it as a decoy or a stand-in for your main app icon. It allows your app to switch between different icons under the same name.

Here’s an example of how you would define an activity alias in your AndroidManifest.xml file:

Kotlin
<application
    android:icon="icon"
    android:roundIcon="icon">
    <activity
       // ...
    </activity>

    <activity-alias
        android:name=".MainActivityAlias"
        android:icon="icon_2"
        android:roundIcon="icon_2"
        android:targetActivity=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity-alias>
</application>

In this example, .MainActivityAlias is the name of the alias, and .MainActivity is the target activity that the alias points to. The <intent-filter> is like telling your app, “Hey, this alias is also a way to launch the app!”

Remember, swap out MainActivityAlias in the code with the actual name you’ve christened your activity alias in your AndroidManifest.xml file. This ensures that your code and your configuration are singing the same tune when it comes to dynamic icon changes.

Now, to create dynamic app icons in Android, follow these steps:

1. Creating a BroadcastReceiver

We’ll start by creating a BroadcastReceiver that will listen for a specific broadcast event and take care of the icon switcheroo. Let’s create a new IconChangeReceiver class:

Kotlin
class IconChangeReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == "com.example.app.ACTION_CHANGE_ICON") {
            changeAppIcon(context)
        }
    }
    
    private fun changeAppIcon(context: Context?) {
        context?.let {
            // This is where the magic happens. We'll get to this in a bit!
        }
    }
}

In this code, IconChangeReceiver acts as your diligent listener, meanwhile eagerly awaiting the signal"com.example.app.ACTION_CHANGE_ICON". When it hears this, it calls changeAppIcon – that’s your cue to switch up the icon.

2. Register the BroadcastReceiver

In your AndroidManifest.xml file, be sure to register the IconChangeReceiver with an intent filter to listen for the custom action:

XML
<receiver
    android:name=".IconChangeReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="com.example.app.ACTION_CHANGE_ICON" />
    </intent-filter>
</receiver>

3. Implement Icon Change Logic

Inside the onReceive method of your IconChangeReceiver, implement the logic to change the app icon dynamically. You can use conditional statements to select different icons based on specific criteria. Here’s a simplified example:

Kotlin
class IconChangeReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context?, intent: Intent?) {
        if (intent?.action == "com.example.app.ACTION_CHANGE_ICON") {
            changeAppIcon(context)
        }
    }
    
    private fun changeAppIcon(context: Context?) {
        context?.let { ctx ->
            // Example: Conditionally select a different alias based on some criteria
            val aliasToEnable = when (someCondition) {
                true -> ctx.getString(R.string.alias_1)
                false -> ctx.getString(R.string.alias_2)
            }
            
            val aliasToDisable = when (aliasToEnable) {
                ctx.getString(R.string.alias_1) -> ctx.getString(R.string.alias_2)
                else -> ctx.getString(R.string.alias_1)
            }
            
            // Change the app icon by enabling one alias and disabling the other
            val packageManager = ctx.packageManager
            enableComponent(ctx, packageManager, aliasToEnable)
            disableComponent(ctx, packageManager, aliasToDisable)
        }
    }

    private fun enableComponent(
        context: Context, 
        packageManager: PackageManager, 
        componentNameString: String
    ) {
        val componentName = ComponentName(context, componentNameString)
        
        packageManager.setComponentEnabledSetting(
            componentName,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP
        )
    }

    private fun disableComponent(
        context: Context, 
        packageManager: PackageManager, 
        componentNameString: String
    ) {
        val componentName = ComponentName(context, componentNameString)
        
        packageManager.setComponentEnabledSetting(
            componentName,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP
        )
    }
}

Here we are first checking if the context (the current state of the app) is not null. We need the context because it gives us access to app-specific resources and classes.

Then we decide which icon to show based on certain conditions. This is where you can get creative. For example, you might change the icon based on the time of day, a holiday, or a special event in your app.

Lastly, with the chosen icon resource, we proceed to the crucial step: changing the app icon. We use the PackageManager to enable the activity alias representing the new icon and disable the current one. Think of it like telling Android, “Hey, stop using this icon and start using this one instead.”

We achieve this by calling setComponentEnabledSetting on our main activity and its alias. Enabling the alias with the new icon and disabling the current one effectively switches the icons.

4. Trigger Icon Change

To actually trigger the icon change, we send a broadcast with the specific action that our IconChangeReceiver is listening for. This is done by creating an Intent with the action "com.example.app.ACTION_CHANGE_ICON" and then calling sendBroadcast on our context. Here’s how it’s typically done:

If you’re calling it within an Activity or another component that holds a Context, you can use:

Kotlin
val iconChangeIntent = Intent("com.example.app.ACTION_CHANGE_ICON")
sendBroadcast(iconChangeIntent)

And if you’re in a different part of your app and have a reference to a Context, you’d do:

Kotlin
val iconChangeIntent = Intent("com.example.app.ACTION_CHANGE_ICON")
context.sendBroadcast(iconChangeIntent)

Remember, the broadcast will be received by our IconChangeReceiver, which will then proceed to change the app’s icon based on the logic we’ve set up.

Conclusion

In the ever-evolving world of Android app development, making your app stand out is all about engaging your users and sprinkling in some personal flair. Dynamic app icons are your ticket to an immersive, fresh user experience. They let your app’s icon evolve on the fly, no updates or reinstalls needed. The sky’s the limit: celebrate special occasions, switch themes, or show off new features, all with a dynamic twist!

Happy coding! 🚀


This post is also available on Medium.