Supporting Android v12+ Splash Screens in Xamarin.Forms

If you're an Android user, you may have noticed that, starting with Android v12.0, when you launch an app its Splash Screen now just looks like it's logo. Strange, right? Well that's apparently how Android wants it because that's what they're forcing us to do!

Here's an example of how the splash screen looks in my open-source Xamarin.Forms app, GitTrends, before and after Android v12.0. It's a subtle difference (once fixed), but you'll notice the new splash screen now exactly matches the GitTrends icon and is a smaller dpi due to Android's new splash screen restrictions:

Before Android v12.0 After Android v12.0 (broken) After Android v12.0 (Fixed)

Step 0: Target Android API 31+

AndroidManifest.xml

In AndroidManifest.xml, ensure the android:targetSdkVersion is 31 or higher (as of publishing this, the current stable release of Android is API Level 32).

Here's an example from GitTrends' AndroidMainifest.xml:

<uses-sdk android:minSdkVersion="23" android:targetSdkVersion="32" />

In the Android csproj file, eg MyApp.Android.csproj, ensure TargetFrameworkVersion is set to v12.0 or higher (as of publishing this, the current stable release of Android is v12.1).

Here's an example from GitTrends.Android.csproj:

<TargetFrameworkVersion>v12.1</TargetFrameworkVersion>

Step 1: Create New Images

I know...this is a pain. Android already makes us create multiple images for each screen density (mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi, etc), and we need to do it again for our new Splash Screen icon.

The splash screen icon should match our app's icon and it should reside inside of a 192dp circle centered inside of a 288dp png file. These are the steps I followed for GitTrends:

  1. For each display density, create a new .png file of your app icon, sized 288dp
  2. Inside each new file, for each display density, center the app icon inside of a 192dp-radius circle
  3. Add the new files to the corresponding drawable folder, eg /Resources/drawable-hdpi/, /Resources/drawable-xhdpi/, etc

For my app, GitTrends, I used the tool Sketch to create my new Splash Screen images. You're welcome to leverage the templates I used in my Icon.sketch file: https://github.com/brminnick/GitTrends/blob/main/Artwork/Icon.sketch

Step 2: Create a new adaptive-icon

The new splash screen requires an adaptive-icon resource, similar to how we create icon.xml and icon-round.xml.

However, the adaptive-icon API was added in Android API v26.

To maintain backwards compatibility with previous versions of Android (my GitTrends app currently supports Android API Levels 23+),  we'll create a /drawable-v26/ folder for our new splash screen xml resource. This tells Android to only include the resource in v26 and up. The rule is that files included in drawable-vXX will only be included for devices running Android API Level XX and up.

Here's the steps I followed

  1. Create a new folder, /Resources/drawable-v26/
  2. In /Resources/drawable-v26/ add a new file, splashscreenanimatedicon.xml
  3. In splashscreenanimatedicon.xml, create a new adaptive-icon:
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- Change this value to be any Hex value or to refer to a custom color from your colors.xml file, eg `@color/colorPrimary` -->
    <background android:drawable="#FFFFFF" />
    
    <!-- Change this value to point to the newly created images added above in Step 1; e.g. for /drawable-hdpi/newsplashscreenimage.png, set this value to `@drawablenewsplashscreenimage` -->
    <foreground android:drawable="@drawable/newsplashscreenimage" />
</adaptive-icon>

If you're curious, you can find the completed GitTrends' splashscreenanimatedicon.xml file here: https://github.com/brminnick/GitTrends/blob/main/GitTrends.Android/Resources/drawable-v26/SplashScreenAnimatedIcon.xml

Step 3: Update styles.xml

Splash Screen Style, Before Android v12.0

In the file /Resouces/values/styles.xml, you likely have defined a custom splash screen for your app that looks something like this:

<style name="LaunchTheme" parent="Theme.AppCompat">
    <item name="android:windowBackground">@drawable/splash_screen</item>
    <item name="android:windowNoTitle">true</item>
</style>

The android:windowBackground value points to my original splash screen, splash_screen.xml which I created using a layer-list. For example, here's what my original splash screen, splash_screen.xml, looked like before Android v12.0:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:opacity="opaque">
    <item android:drawable="@color/splash_screen_background"/>

    <item
        android:width="384dp"
        android:height="384dp"
        android:gravity="center">

        <bitmap
            android:src="@drawable/GitTrends"
            android:gravity="fill" />
    </item>
</layer-list>

Splash Screen Style, After Android v12.0

For Android v12.0+, we need to add two values to our Splash Screen Theme in styles.xml:

  • android:windowSplashScreenBackground
    • The background color of your splash screen
  • android:windowSplashScreenAnimatedIcon
    • The adaptive-icon xml file we created above in Step 2

Here's the final final result from my GitTrends app:

<style name="LaunchTheme" parent="Theme.AppCompat">
    <!-- The following values are used for Splash Screen Android API Level 30 and below; ignored on Android API Level 31 and above -->
    
    <item name="android:windowBackground">@drawable/splash_screen</item>
    <item name="android:windowNoTitle">true</item>

    <!-- The following values are used for Splash Screen Android API Level 31 and above; ignored on Android API Level 30 and below -->
    
    <!-- Change this value to point to the new adaptive-icon xml file created abbove in Step 2 -->
    <item name="android:windowSplashScreenAnimatedIcon">@drawable/splashscreenanimatedicon</item>
    <!-- Change this value to be any Hex value or to refer to a custom color from your colors.xml file, eg `@color/colorPrimary` -->
    <item name="android:windowSplashScreenBackground">#FFFFFF</item>
</style>

The best news is that we can keep the values for our previous splash screen, e.g. android:windowBackground, along side the new values for our Android API Level 30+ splash screen, android:windowSplashScreenAnimatedIcon and android:windowSplashScreenBackground!

When the app runs on Android API Level 31+, it checks the Launch Theme for two values:

Android uses these two values for the Splash Screen and ignores the other values in the style.

When the app runs on Android API Level 30 (and below), it doesn't know about the new APIs added in v31, so when it sees  android:windowSplashScreenAnimatedIcon and android:windowSplashScreenBackground, it ignores these values.

Android just checks the Launch Theme for android:windowBackground, which still points to my original launch screen, splash_screen.xml, which uses a layer-list.

Step 4: Set The Launch Theme

Now that we've updated our splash screen theme, we need to ensure Android knows that we want to use it when the app launches.

In Xamarin.Android, this may be set in multilple different places:

  • MainActivity.cs
  • AndroidManifest.xml
  • MainApplication.cs

MainActivity.cs

In MainActivity.cs, the launch theme can be set using the [Activity] attribute, eg [Activity(MainTheme = "@style/MainTheme")].

In your code, open MainActivity.cs and check to see if your MainActivity is using the [Activity] attribute (most Xamarin.Forms apps do, but some don't and that's ok).

If the [Activity] attribute is being used, ensure that its MainTheme property references the name of your launch theme.

For example, in MainActivity.cs for GitTrends, I used [Activity(MainTheme = "@style/LaunchTheme")] because I named the launch theme for my GitTrends app LaunchTheme:

<style name="LaunchTheme" parent="Theme.AppCompat">
    <!-- see above for complete LaunchTheme  -->
</style>

AndroidManifest.xml

In AndroidManifest.xml,  the launch theme can be set in the <android> tag, eg <application android:theme="@style/LaunchTheme">.

In your code, open AndroidManifest.xml and check to see if your Android Manifest is using the android:theme value inside of the <android> tag (some Xamarin.Forms apps do, but some don't and that's ok).

If the android:theme value is set, ensure that its MainTheme property references the name of your launch theme.

For example, I named the launch theme for my GitTrends app LaunchTheme, so I would thus use <application android:theme="@style/LaunchTheme"> in my AndroidManifest (I personally don't because I already defined the launch theme in my MainActivity).

MainApplication

In MainApplication.cs, the launch theme can be set using the [Application] attribute, eg [Application(MainTheme = "@style/MainTheme")].

In your code, open MainActivity.cs and check to see if your MainActivity is using the [Application] attribute (most Xamarin.Forms apps do, but some don't and that's ok).

If the [Application] attribute is being used, ensure that its MainTheme property references the name of your launch theme.

For example, I named the launch theme for my GitTrends app LaunchTheme, so I would thus use <application android:theme="@style/LaunchTheme"> in my MainApplication (I personally don't because I already defined the launch theme in my MainActivity).

Conclusion

Now we have a working Splash Screen on Andorid (again)!

This new splash screen format actually opens the door for us to explore really cool animated splash screens. For example check out the below splash screens by Jemma Slater.

If you're interested in learning more about how to continue to improve your new Android v12.0 splash screen, I highly recommend the following tutorials:

Icon Background Color Branding Image (bottom image) Animated Splash Screen