Exploring the Android EmojiCompat Library

Emojis are everywhere — it’s hard to visit a website, app or have a conversation without emojis popping up somewhere along the line 😀 Because of this, it’s important that all users who are involved in these kind of activities are able to see the emojis being used. If not, textual content can be misunderstood or misinterpreted. Luckily for us on Android, Google have released a new library known as the EmojiCompat library to help solve this issue and bring a better experience for both ends of the conversation.


In a nutshell, the aim of the EmojiCompat library is to try and ensure that older devices (with older OS versions) are kept up to date with the latest emojis. It’s quite common for older OS versions to be unable to display certain Emojis because of newer versions of Emojis are not backwards compatible. This can result in these kind of situations occurring:

Not great right? How will the receiver of that message know what they’re to buy on the way home? And this is just one example — the same problems can occur in other situations, causing confusion and annoyance for the user.

With EmojiCompat, we get something more like this:

Now I know what to buy on the way home and we won’t have to go 🥑-less when it comes to dinner.


The EmojiCompat library

The EmojiCompat library contains a bunch of useful components which we can utilise to ensure this consistent experience across devices. These include the EmojiTextView, EmojiEditText and EmojiButton — which when used to display unsupported emojis, in comparison to a regular textview, look like so:

But how does this work? Well, the library takes the given Unicode from the given CharSequence that is representing an Emoji and if the Emoji isn’t one that is recognised on the given device, then the library replaces it with EmojiSpan instances. Once this is all complete, EmojiCompat renders the required Glyphs into view.

The EmojiCompat library takes unrecognised unicodes and converts them to recognisable emojis.

An EmojiSpan is a new class available as of API 26.0.0 (it’s an extension of the ReplacementSpan class which you may have come across before). When an Emoji needs to be replaced into a CharSequence, a new instance is instantiated from this base class and added to to sequence — this is the process which ensures that the device will display the given Emoji.


Components of the EmojiCompat library

It’s clear that there’s a little bit going on behind the scenes for this to all work. When this process takes place, there are several different library components involved in the conversion of unrecognisable characters to the display of Emoji glyphs:

  • The Widgets component consists of the view components that we have available to use in our application — this includes the EmojiEditText, EmojiTextView and EmojiButton. We’ll get more into these in a bit, but essentially they are default implementations that we can use to display EmojiCompat Glyphs in our application.
  • The EmojiCompat component is responsible for handling all communication that takes place between the application and external entities. And in turn with this, the Config component is used to set configuration details for our instantiated EmojiCompat instance.

There are several different configuration properties that we can set for this Config component:

setReplaceAll — The default behaviour for EmojiCompat is to only replace emojis that it can render. We can use this configuration to replace all emojis it finds with EmojiSpan instances.

setEmojiSpanIndicatorEnabled — This allows you to set an indicator to display whether or not an Emoji has been replaced by an EmojiSpan — if set to true then a background will be drawn for the EmojiSpan.

setEmojiSpanIndicatorColor — This sets the color to be used for indicating an EmojiSpan. If this value sin’t set then the Color.GREEN property is used by default.

registerInitCallback — This callback can be used to receive events within our application regarding the state of the EmojiCompat initialisation

unregisterInitCallback — this can be used to remove the previously set callback from the Config instance

Creating an instance of this Config class just requires instantiating the relevant Config class (here we are using the FontRequestEmojiCompatConfig class, if you are using bundled fonts then this would be the BundledEmojiCompatConfig class) and using the provided methods from the Emoji.Compat class that it extends to set these given properties.

EmojiCompat.Config config = new FontRequestEmojiCompatConfig(...)
.setReplaceAll(true)
.setEmojiSpanIndicatorEnabled(true)
.setEmojiSpanIndicatorColor(Color.GREEN)
.registerInitCallback(new SomeCallback())

Once we have done so, we can then set the configuration for our EmojiCompat instance during initialisation:

EmojiCompat.init(config);
  • The EmojiSpan class is the subclass of the ReplacementSpan which replaces the relevant character sequences in our application and renders the required glyphs to display our emojis in our app.
  • Finally, the EmojiCompat component uses a font in-order to display the required emojis. The font which is used is a slightly modified version of the Android Emoji Font that allows the library to provide backward compatibility for older OS versions.

EmojiCompat Fonts

When it comes to the fonts used for our EmojiCompat instance, there are two ways in which EmojiCompat can be configured, this can be done by using either:

  • Bundled fonts — Fonts are bundled into the APK
  • Downloadable fonts — Fonts are downloaded at runtime as required

Bundled Fonts

If we wish to have the required font bundled with our APK, then we need to add the dependancy to our app-level build.gradle file that includes the font resource required for the EmojiCompat functionality:

compile "com.android.support:support-emoji-bundled:$version"

Next, we simply just configure our EmojiCompat instance with an instance of the BundledEmojiCompatConfig class which handles the loading of the font metadata for us from the bundled resources.

EmojiCompat.Config config = new BundledEmojiCompatConfig(this);
EmojiCompat.init(config);

Downloadable Fonts

Using Downloadable fonts means that the fonts we need are downloaded at runtime. You can read more about Downloadable Fonts here, but this approach essentially allows us to reduce our APK size and allow multiple APKs access to these downloaded font resources. All devices running API version 14 above that are using version 26.0.0 of the support library have access to the Downloadable fonts api.

To begin with, we need to add the dependancy to our app-level build.gradle file — this dependency is different from the previous as it does not contain the bundled font:

compile "com.android.support:support-emoji:26.0.1"

We next need to initialise EmojiCompat with a font configuration — here, we create an instance of the FontRequest and pass in the required parameters for its initialisation. There is more information on this process and the parameters used here.

FontRequest fontRequest = new FontRequest(
"com.google.android.gms.fonts",
"com.google.android.gms",
"Noto Color Emoji Compat",
R.array.com_google_android_gms_fonts_certs);

Now that we have this FontRequest instance, we can go ahead and pass it in as a parameter when creating our EmojiCompat Config instance. This is letting our configuration know the details about what font to use and where it is accessible from.

EmojiCompat.Config config = new FontRequestEmojiCompatConfig(this, fontRequest);
EmojiCompat.init(config);

EmojiCompat View Components

Once we’ve configured our fonts, we just simply need to switch out the views that we’re using in our layouts for the corresponding EmojiCompat-View. The EmojiCompat library provides three widgets for us — the EmojiTextView, EmojiEditText and EmojiButton:

<android.support.text.emoji.widget.EmojiTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<android.support.text.emoji.widget.EmojiEditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<android.support.text.emoji.widget.EmojiButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

When using these, the views will automatically handle the display of the emojis for us - that means it’s just a simple case of setting the text of the view and the rest is handled for us! However, if for whatever reason you can’t or don’t want to use one of the above views then it is still possible to use EmojiCompat with standard views — we just have to handle the processing manually:

EmojiCompat.get().registerInitCallback(object : EmojiCompat.InitCallback() {
override fun onInitialized() {
val compat = EmojiCompat.get()
regularTextView.text = compat.process(getString(
R.string.regular_text_view, EMOJI))
}
})

To begin with, we fetch our EmojiCompat instance and use the registerInitCallback() method to register a callback for when our EmojiCompat instance is ready to use. Once ready, we can use this instance of our EmojiCompat class to manually call its process() method. This method checks the given CharSequence for any Emoji instances and adds the required EmojiSpans if any are found. This is essentially the same process that goes on behind the scenes for the EmojiCompat-Views.

Note: It’s important to remember to make use of the unregisterInitCallback() method when you are finished with the listener.

App Compat Support

If you’re using classes from AppCompat then good news, EmojiCompat is also supported in these setups too! You’ll have to add a different dependancy for this:

compile "com.android.support:support-emoji-appcompat:$version"

Once you’ve added the dependancy, you’ll have access to the AppCompat versions of the Emoji-View classes that we previously looked at.

<android.support.text.emoji.widget.EmojiAppCompatTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<android.support.text.emoji.widget.EmojiAppCompatEditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

<android.support.text.emoji.widget.EmojiAppCompatButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

I’m not using Widgets though!

Even if you’re not using widgets, you can still use the EmojiCompat library to convert CharSequences to fully support Emojis. Because the process() method returns a CharSequence with the conversion result, we can simply use it like so:

CharSequence processed = EmojiCompat.get().process("neutral face \uD83D\uDE10");

At this point we have a CharSequence with our passed in text now containing our EmojiCompat-ified content.


As you can see, add backward compatibility for emojis in your applications isn’t much of a task to carry out. The benefits from doing so includes a more consistent experience for your user and a better overall experience from both parties at each end of the conversation.

Are you using EmojiCompat already? Have any questions or suggestions? Leave a response below or drop me a tweet 🙂