Android adaptive icons with React Native and Cordova

Adaptive icons were introduced in Android 8 (API level 26). They allow you to define an icon as two parts - a background and foreground. This separation allows for more flexible resizing, as well as animation of app icons in certain launchers.

Icon sizes

Adaptive icons are 108dp in size. However, for the foreground, the safe area size is only 72dp in size. This is because many launchers will do some sort of animation when the icon is moved, which is achieved by moving the foreground of the icon around. I recommend still making the foreground image 108dp in size and just ensuring that its main content is contained within a 72dp square in its centre.

Screen Density Scaling Ratio Icon size Safe area
xxxhdpi 4 432x432 288x288
xxhdpi 3 324x324 216x216
xhdpi 2 216x216 144x144
hdpi 1.5 162x162 108x108
mdpi 1 108x108 72x72
ldpi 0.75 81x81 54x54

Generating adaptive icons with Photoshop

If you have your icon in a PSD file, you can use the Generate Image Assets feature to automatically generate the two layers for you.

The way this works is that every layer or group which has a name which is a file name will be automatically exported in the folder in which the PSD folder is located. For example, if you have a group called background.png, then this group will be exported as a separate PNG file every time you save the PSD. You can also comma-separate these values to export multiple files in different sizes, which is how we will do it for the adaptive icons.

Create two groups in your PSD, one with the icon background, and the other with the foreground. Then name the groups as below:

Background:

432x432 mipmap-xxxhdpi/bg.png, 324x324 mipmap-xxhdpi/bg.png, 216x216 mipmap-xhdpi/bg.png, 162x162 mipmap-hdpi/bg.png, 108x108 mipmap-mdpi/bg.png

Foreground:

432x432 mipmap-xxxhdpi/fg.png, 324x324 mipmap-xxhdpi/fg.png, 216x216 mipmap-xhdpi/fg.png, 162x162 mipmap-hdpi/fg.png, 108x108 mipmap-mdpi/fg.png

Now, enable asset generation by checking File > Generate > Image Assets. Photoshop will now generate the background and foreground PNGs every time your save the PSD.

Using with React Native

Now that we have our background and foreground images, we need to tell Android how these fit together to make the adaptive icon. This is done using an XML file, which we’ll call ic_launcher.xml. The name is important, as by default React Native names icons ic_launcher.png, so we can drop in this adaptive icon smoothly if we name it the same way. If your app uses a different name for its icons, rename the .xml file to match your .pngs.

Create the folder android/app/src/main/res/mipmap-anydpi-v26, where we will save this new icon file. The folder name is important. The anydpi part means that this XML file defines the icon for all screen densities. The v26 means that this should only be used for Android 8 (API level 26) and above, which is the version that added adaptive icons.

Here’s what the contents of the ic_launcher.xml file should look like:

<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
	<background android:drawable="@mipmap/bg" />
	<foreground android:drawable="@mipmap/fg" />
</adaptive-icon>

Finally, copy the bg.png and fg.png files you generated earlier into their corresponding mipmap folders. Since this is a native change, you will need to re-build the project (npm run android). Once that is done you should see your new icon!

Using with Cordova

Since Cordova 9 (which includes cordova-android@8), adaptive icons are supported out of the box, using the same <icon> tag you would use for normal icons. I tend to put my Android icons in a folder called icons/android, in which I have two folders, one for adaptive, and another for legacy or normal icons.

When using the <icon> tag, use background and foreground to define the two parts of your adaptive icon. The src attribute works the same way as before, defining the normal icon, which will be used on devices which don’t support adaptive icons (below Android 8).

<platform name="android">
  <icon density="mdpi" background="icons/android/adaptive/mipmap-mdpi/bg.png" foreground="icons/android/adaptive/mipmap-mdpi/fg.png" src="icons/android/legacy/48.png" />
  <icon density="hdpi" background="icons/android/adaptive/mipmap-hdpi/bg.png" foreground="icons/android/adaptive/mipmap-hdpi/fg.png" src="icons/android/legacy/72.png" />
  <icon density="xhdpi" background="icons/android/adaptive/mipmap-xhdpi/bg.png" foreground="icons/android/adaptive/mipmap-xhdpi/fg.png" src="icons/android/legacy/96.png" />
  <icon density="xxhdpi" background="icons/android/adaptive/mipmap-xxhdpi/bg.png" foreground="icons/android/adaptive/mipmap-xxhdpi/fg.png" src="icons/android/legacy/144.png" />
  <icon density="xxxhdpi" background="icons/android/adaptive/mipmap-xxxhdpi/bg.png" foreground="icons/android/adaptive/mipmap-xxxhdpi/fg.png" src="icons/android/legacy/192.png" />
</platform>

Build your project using cordova build android, and that’s it!

Testing that it worked

The easiest way to test that your app is using your new adaptive icons is to drag the icon around your home screen. Most launchers have a parallax animation which causes the foreground image to move around faster than the background image.