Support modern emoji

The standard set of emoji is refreshed annually by Unicode, with usage of emoji by users increasing rapidly for all types of apps.

If your app displays Internet content or provides text input, we strongly recommend supporting the latest emoji fonts. Otherwise, newer emoji may be displayed as a small square box called tofu (☐) or other incorrectly rendered emoji sequences.

Versions of Android 11 (API level 30) and lower don't have the ability to update the emoji font, so any app that displays them on those lower versions must be updated manually.

The following are some examples of modern emoji.

Examples Version
😶‍🌫️ 🧔🏻‍♀️ 🧑🏿‍❤️‍🧑🏾 13.1 (September 2020)
🥲 🥷🏿 🐻‍❄️ 13.0 (March 2020)
🧑🏻‍🦰 🧑🏿‍🦯 👩🏻‍🤝‍👩🏼 12.1 (October 2019)
🦩 🦻🏿 👩🏼‍🤝‍👩🏻 12.0 (February 2019)

The androidx.emoji2:emoji2 library provides simpler backward-compatibility with lower versions of Android. The emoji2 library is a dependency of the AppCompat library and requires no further configuration to work.

Prerequisites

To confirm that your app properly displays newer emoji, launch it on a device running a version between Android 4.4 (API level 19) and Android 10 (API level 29) inclusive. This page includes modern emoji you can display for testing.

Use AppCompat to support the latest emoji

AppCompat 1.4 includes support for emoji back to Android 4.4.

To use AppCompat to support the latest emoji:

  1. Check that your module depends on the appcompat library version 1.4.0-alpha01 or higher.

    build.gradle
    
    // Ensure version is 1.4.0-alpha01 or higher.
    implementation "androidx.appcompat:appcompat.$appcompatVersion"
    
  2. Ensure all activities that display text extend the AppCompatActivity class.

    Kotlin

    MyActivity.kt
    
    class MyActivity: AppCompatActivity {
       …
    }
    

    Java

    MyActivity.java
    
    class MyActivity extends AppCompatActivity {
       …
    }
    
  3. To test your integration, launch your app on a device running Android 10 or lower, and display the following test string. Make sure that all characters render correctly.

    • 13.1: 😶‍🌫️, 🧔🏻‍♀️, 🧑🏿‍❤️‍🧑🏾
    • 13.0: 🥲, 🥷🏿, 🐻‍❄️
    • 12.1: 🧑🏻‍🦰, 🧑🏿‍🦯, 👩🏻‍🤝‍👩🏼
    • 12.0: 🦩, 🦻🏿, 👩🏼‍🤝‍👩🏻

That's it! Your app automatically displays backward-compatible emoji on all devices that provide an emoji2-compatible downloadable fonts provider, such as devices powered by Google Play services.

If your app is using AppCompat but displays tofu (☐)

In some cases, your app may display tofu (☐) instead of the proper emoji, even though you've added the AppCompat library. The following are some possible explanations and solutions.

You're running the app on a recently-flashed device or a brand new emulator

Clear the app data for Google Play services to clear any font caching that may have happened during startup. Once you do so, this situation typically resolves itself after a few hours.

To clear the app data:

  1. On your Android device, open Settings.

  2. In Settings, tap Apps & notifications.

  3. Tap See all apps or App info.

  4. Scroll through the apps, and tap Google Play services.

  5. Tap Storage & cache.

  6. Tap Clear cache.

Your app isn't using an AppCompat text-related class

This can happen if you don't extend AppCompatActivity, or if you instantiate a view in code such as TextView. Make sure that you do the following:

  • The activity extends AppCompatActivity.
  • If creating the view in code, use the correct appcompat subclass.

AppCompatActivity automatically inflates AppCompatTextView in place of TextView when inflating XML, so you don't need to update your XML.

The test phone doesn't support downloadable fonts

Verify that DefaultEmojiCompatConfig.create returns a non-null configuration.

An emulator on an older API level hasn't upgraded Google Play services

When using an emulator on an older API level, the bundled Google Play services may need to be upgraded for emoji2 to find the font provider. To do this, log in to the Google Play Store on the emulator.

To verify that a recent enough version has been installed, do the following:

  1. Running the following command:

    adb shell dumpsys package com.google.android.gms | grep version
    
  2. Check that the versionCode is higher than 211200000.

Support emoji without AppCompat

If your app doesn't include appcompat, it can use emoji2 directly. This requires more work, so use this method only if your app cannot use appcompat.

To support emoji without the AppCompat library, do the following:

  1. In your app's build.gradle file, include emoji2 and emoji2-views.

    build.gradle
    
    def emojiVersion = "1.0.0-alpha03"
    implementation "androidx.emoji2:emoji2:$emojiVersion"
    implementation "androidx.emoji2:emoji2-views:$emojiVersion"
    

    The emoji2-views module provides subclasses of TextView, Button, and EditText that implement EmojiCompat, and should not be used in an app that includes appcompat because it already implements EmojiCompat.

  2. In XML or code (wherever you would use TextView, EditText, or Button), use EmojiTextView, EmojiEditText, or EmojiButton instead.

    activity_main.xml
    
    <androidx.emoji2.widget.EmojiTextView … />
    <androidx.emoji2.widget.EmojiEditText … />
    <androidx.emoji2.widget.EmojiButton … />
    

    By including the emoji2 module, the system uses the default downloadable fonts provider to load the emoji font automatically shortly after app startup, and no further configuration is needed.

  3. To test your integration, launch your app on a device running Android 10 or lower, and display the following test strings. Make sure that all characters render correctly.

    • 13.1: 😶‍🌫️, 🧔🏻‍♀️, 🧑🏿‍❤️‍🧑🏾
    • 13.0: 🥲, 🥷🏿, 🐻‍❄️
    • 12.1: 🧑🏻‍🦰, 🧑🏿‍🦯, 👩🏻‍🤝‍👩🏼
    • 12.0: 🦩, 🦻🏿, 👩🏼‍🤝‍👩🏻

Use EmojiCompat without widgets

EmojiCompat uses EmojiSpan to render correct images. Therefore, it has to convert any given [CharSequence] object into a Spanned object with EmojiSpan objects. The EmojiCompat class provides the process() method to convert CharSequences into Spanned instances. Using this method, you can call process() in the background and cache results, which improves the performance of your app.

Kotlin

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

Java

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

Use EmojiCompat for input method editors

The EmojiCompat class allows keyboards to render the emoji supported by the app they are interacting with. Input method editors (IMEs) can use the hasEmojiGlyph() method to check whether an instance of EmojiCompat is capable of rendering an emoji. This method takes a CharSequence of an emoji and returns true if EmojiCompat can detect and render the emoji.

The keyboard can also check the version of EmojiCompat that the app supports to determine which emoji to render in the palette. To check the version, if available, the keyboard can look for the following keys in the EditorInfo.extras bundle:

  • EDITOR_INFO_METAVERSION_KEY: Represents the version of the emoji metadata that the app uses. If this key doesn't exist, then the app isn't using EmojiCompat.
  • EDITOR_INFO_REPLACE_ALL_KEY: If the key exists and is set to true, then the app has configured EmojiCompat to replace all emoji, even if they are present in the system.

Learn more about how to configure an instance of EmojiCompat.

Use emoji in custom views

If your app has custom views that are direct or indirect subclasses of TextView (for example, Button, Switch, or EditText) and can display user-generated content, they should each implement EmojiCompat.

The process is different depending on whether your app uses the appcompat library.

Add custom views for apps with AppCompat

If your app uses AppCompat, extend the AppCompat implementation instead of the platform implementation. Use the following table as a guide for how to extend your views in AppCompat:

Instead of extending... Extend
TextView AppCompatTextView
EditText AppCompatEditText
ToggleButton AppCompatToggleButton
Switch SwitchCompat
Button AppCompatButton
CheckedTextView AppCompatCheckedTextView
RadioButton AppCompatRadioButton
CheckBox AppCompatCheckBox
AutoCompleteTextView AppCompatAutoCompleteTextView
MultiAutoCompleteTextView AppCompatMultiAutoCompleteTextView

Add custom views for apps without AppCompat

If your app doesn't use appcompat, use the view integration helpers in the emoji2-views-helper module that are designed for use in custom views. These are the helpers that the appcompat library uses to implement emoji support.

Complete the following steps to support custom views for apps that don't use appcompat.

  1. Add the emoji2-views-helper library.

    implementation "androidx.emoji2:emoji2-views-helper:$emojiVersion"
    
  2. Follow the instructions to include EmojiTextViewHelper or EmojiEditTextHelper in your app's custom views.

  3. To test your integration, launch your app on a device running Android 10 or lower, and display the following test string. Make sure that all characters render correctly.

    • 13.1: 😶‍🌫️, 🧔🏻‍♀️, 🧑🏿‍❤️‍🧑🏾
    • 13.0: 🥲, 🥷🏿, 🐻‍❄️
    • 12.1: 🧑🏻‍🦰, 🧑🏿‍🦯, 👩🏻‍🤝‍👩🏼
    • 12.0: 🦩, 🦻🏿, 👩🏼‍🤝‍👩🏻

Optional features for handling emoji2

After you include the emoji2 library in your app, you can choose to add the optional features that are described in this section.

Configure emoji2 to use a different font or downloadable font provider

To configure emoji2 to use a different font or downloadable font provider, do the following:

  1. Disable the EmojiCompatInitializer by adding the following to your manifest.

    <provider
        android:name="androidx.startup.InitializationProvider"
        android:authorities="${applicationId}.androidx-startup"
        android:exported="false"
        tools:node="merge">
    <meta-data android:name="androidx.emoji2.text.EmojiCompatInitializer"
               tools:node="remove" />
    </provider>
  2. Do one of the following:

Modify your EmojiCompat behavior

You can use an instance of EmojiCompat.Config to modify EmojiCompat behavior.

The most important configuration option is setMetadataLoadStrategy(), which controls when EmojiCompat loads the font. Font loading begins as soon as EmojiCompat.load() is called, and this will trigger any necessary downloads. The system creates a thread for font downloading unless your app provides one.

LOAD_STRATEGY_MANUAL allows you to control when EmojiCompat.load() is called, and LOAD_STRATEGY_DEFAULT causes loading to start synchronously in the call to EmojiCompat.init().

Most apps should use LOAD_STRATEGY_MANUAL to allow control over the thread and timing of font loading. In particular, your app should defer until after the first screen displays to avoid introducing startup latency. EmojiCompatInitializer follows this practice and defers loading the emoji font until after the first screen has resumed.

You can use the following methods from the base class to set other aspects of the configuration:

  • setReplaceAll(): Determines whether EmojiCompat should replace all emoji it finds with instances of EmojiSpan. By default, when EmojiCompat infers that the system can render an emoji, it doesn't replace that emoji. When set to true, EmojiCompat replaces all emoji with EmojiSpan objects.
  • setEmojiSpanIndicatorEnabled(): Indicates whether EmojiCompat has replaced an emoji with an EmojiSpan object. When set to true, EmojiCompat draws a background for the EmojiSpan. This method is mainly used for debugging purposes.
  • setEmojiSpanIndicatorColor: Sets the color to indicate an EmojiSpan. The default value is GREEN.
  • registerInitCallback(): Informs an app about the state of the EmojiCompat initialization.

Add initialization listeners

EmojiCompat and EmojiCompat.Config classes provide the registerInitCallback() and unregisterInitCallback() methods to register and unregister initialization callbacks. Your app uses these callbacks to wait until EmojiCompat is initialized before you process emoji on a background thread or in a custom view.

To use these methods, create an instance of the EmojiCompat.InitCallback class. Call these methods and pass in the instance of the EmojiCompat.InitCallback class. When the initialization is successful, the EmojiCompat class calls the onInitialized() method. If the library fails to initialize, the EmojiCompat class calls the onFailed() method. To check the initialization state at any point, call the getLoadState() method. This method returns one of the following values: LOAD_STATE_LOADING, LOAD_STATE_SUCCEEDED, or LOAD_STATE_FAILED.

Support bundled fonts with emoji2

You can use the emoji2-bundled artifact to bundle an emoji font into your app. However, because the current NotoColorEmoji font is over 10 MB, we strongly recommend that your app uses downloadable fonts when possible. The emoji2- bundled artifact is intended for use for apps on devices that don't support downloadable fonts.

To use the emoji2-bundled artifact, do the following:

  1. Include emoji2-bundled and emoji2 artifacts.

    implementation "androidx.emoji2:emoji2:$emojiVersion"
    implementation "androidx.emoji2:emoji2-bundled:$emojiVersion"
    
  2. Configure emoji2 to use the bundled configuration.

    Kotlin

    EmojiCompat.init(BundledEmojiCompatConfig(context))
    

    Java

    EmojiCompat.init(new BundledEmojiCompatConfig(context));
    
  3. Test the integration by following the steps above for including emojicompat with or without appcompat, then ensuring the test string displays correctly.

    • 13.1: 😶‍🌫️, 🧔🏻‍♀️, 🧑🏿‍❤️‍🧑🏾
    • 13.0: 🥲, 🥷🏿, 🐻‍❄️
    • 12.1: 🧑🏻‍🦰, 🧑🏿‍🦯, 👩🏻‍🤝‍👩🏼
    • 12.0: 🦩, 🦻🏿, 👩🏼‍🤝‍👩🏻

Impact of automatic EmojiCompat configuration

The system applies default configuration using the startup library, EmojiCompatInitializer, and DefaultEmojiCompatConfig.

Shortly after the first activity resumes in your app, the initializer schedules emoji font loading. This brief delay allows your app to display its initial content without any potential latency due to font loading in a background thread.

DefaultEmojiCompatConfig looks for a system-installed downloadable font provider that implements the EmojiCompat interface, such as Google Play services. On devices powered by Google Play services, this loads the font using Google Play services.

The initializer creates a background thread to load the emoji font, and font download may take up to 10 seconds before timing out. After the font is downloaded, it takes approximately 150 milliseconds on a background thread to initialize EmojiCompat.

Defer the initialization of EmojiCompat, even if you disable EmojiCompatInitializer. If you manually configure EmojiCompat, call EmojiCompat.load() after the first screen of your app displays to avoid background contention with first screen load.

After loading, EmojiCompat uses about 300KB of RAM to hold the emoji metadata.