Xamarin - App Icons (Android Update)

Alternate app icons with Xamarin

This is an update to my previous post Xamarin - Alternate App Icons. In that I described how to switch between different icons for your app. For iOS the process is relatively simple using a native API, however, the solution I had for Android was a little janky with the following drawbacks,

  1. Your app’s state is reset
  2. The icon is not updated instantly (you may notice the old icon in the drawer for a few seconds)
  3. The previous launcher activity is disabled, so if the user had a shortcut on their home screen it will disappear
  4. Xamarin cannot attach the debugger if any of the aliases are enabled (you’ll have to uninstall or change back to the default icon)

I recently took another look at how I did this and have achieved a 50% improvement by solving problems 1 & 4.

Problem 1: app’s state is reset

The app getting killed when enabling/disabling activities is fixed by creating an alias for each icon you plan to include. Essentially, modifying the enabled setting of aliases is fine, but for actual activities can cause unexpected results. The benefit is that you don’t have to relaunch the main activity and if you’re using Xamarin Forms you avoid newing up the Application.

Application Manifest with activity aliases defined for each icon.

<application android:label="Alternate Icon">
    <activity-alias android:label="Alternate Icon"
                    android:icon="@mipmap/chicken"
                    android:roundIcon="@mipmap/chicken_round"
                    android:name="com.dgatto.alternateicon.SplashActivity.Chicken"
                    android:targetActivity="com.dgatto.alternateicon.SplashActivity"
                    android:enabled="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity-alias>
    <activity-alias android:label="Alternate Icon"
                    android:icon="@mipmap/cactus"
                    android:roundIcon="@mipmap/cactus_round"
                    android:name="com.dgatto.alternateicon.SplashActivity.Cactus"
                    android:targetActivity="com.dgatto.alternateicon.SplashActivity"
                    android:enabled="false">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity-alias>
</application>

Now in MainActivity.cs we can remove the code that relaunched the activity.

var intent =
    new Android.Content.Intent(
        this,
        typeof(MainActivity));
intent.AddFlags(Android.Content.ActivityFlags.ClearTop);
intent.SetFlags(
        Android.Content.ActivityFlags.NewTask |
        Android.Content.ActivityFlags.ClearTask);
Finish();
StartActivity(intent);

Problem 4: debugger will not attach

This one was pretty easy to get around once you start using aliases for each icon. Just add a preprocessor directive to make the splash activity the main launcher when in debug. This means there will be two launcher shortcuts, one for the SplashActivity and one for the enabled alias (only the alias will show in release).

    [Activity(
#if DEBUG
        MainLauncher = true,
#endif
        Name = "com.dgatto.alternateicon.SplashActivity",
        Label = "Alternate Icon",
        Theme = "@style/SplashTheme")]

The GitHub repo with the updated code can be found here

Resources

comments powered by Disqus