表情符号兼容性

EmojiCompat 支持库旨在让 Android 设备及时兼容最新的表情符号。它可防止您的应用以 ☐ 的形式显示缺少的表情符号字符,该符号表示您的设备没有用于显示文字的相应字体。通过使用 EmojiCompat 支持库,您的应用用户无需等到 Android OS 更新即可获取最新的表情符号。

显示表情符号的设备
图 1. 表情符号比较

请参阅以下相关资源:

EmojiCompat 的工作原理是怎样的?

EmojiCompat 支持库提供用于在搭载 Android 4.4(API 级别 19)及更高版本的设备上实现向后兼容表情符号支持的类。您可以为 EmojiCompat 配置捆绑式字体或可下载字体。如需详细了解配置,请参阅以下部分:

EmojiCompat 标识给定 CharSequence 的表情符号,根据需要将它们替换为 EmojiSpans,并最后呈现表情符号字形。图 2 演示了该流程。

EmojiCompat 流程
图 2. EmojiCompat 流程

可下载字体配置

可下载字体配置使用可下载字体支持库功能来下载表情符号字体。它还会更新必要的 EmojiCompat 表情符号元数据,以备支持库及时兼容最新版本的 Unicode 规范之需。

添加支持库依赖项

要使用 EmojiCompat 支持库,您必须在开发环境中修改应用项目的类依赖项。

要将支持库添加到应用项目中,请执行以下操作:

  1. 打开应用的 build.gradle 文件。
  2. 将支持库添加到 dependencies 部分。
    dependencies {
        ...
        implementation "com.android.support:support-emoji:28.0.0"
    }
    

初始化可下载字体配置

您需要初始化 EmojiCompat 才能加载元数据和字体。由于初始化可能需要一些时间,初始化进程会在后台线程上运行。

要使用可下载字体配置来初始化 EmojiCompat,请执行以下步骤:

  1. 创建 FontRequest 类的实例,并提供字体提供程序授权、字体提供程序包、字体查询以及证书的哈希集列表。要详细了解 FontRequest,请参阅可下载字体文档中的以编程方式使用可下载字体部分。
  2. 创建 FontRequestEmojiCompatConfig 的实例并提供 ContextFontRequest 的实例。
  3. 通过调用 init() 方法初始化 EmojiCompat 并传递 FontRequestEmojiCompatConfig 的实例。
  4. Kotlin

        class MyApplication : Application() {
    
            override fun onCreate() {
                super.onCreate()
                val fontRequest = FontRequest(
                        "com.example.fontprovider",
                        "com.example",
                        "emoji compat Font Query",
                        CERTIFICATES
                )
                val config = FontRequestEmojiCompatConfig(this, fontRequest)
                EmojiCompat.init(config)
            }
        }
        

    Java

        public class MyApplication extends Application {
          @Override
           public void onCreate() {
             super.onCreate();
             FontRequest fontRequest = new FontRequest(
               "com.example.fontprovider",
               "com.example",
               "emoji compat Font Query",
               CERTIFICATES);
             EmojiCompat.Config config = new FontRequestEmojiCompatConfig(this, fontRequest);
             EmojiCompat.init(config);
           }
        }
        
  5. 在布局 XM 中使用 EmojiCompat 微件。如果您使用的是 AppCompat,请参阅通过 AppCompat 微件使用 EmojiCompat 部分。
  6.     <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"/>
        

要详细了解如何为 EmojiCompat 配置可下载字体,请转到表情符号兼容性示例 Java | Kotlin

库组件

EmojiCompat 流程中的库组件
图 3. EmojiCompat 流程中的库组件
微件:EmojiEditTextEmojiTextViewEmojiButton
EmojiCompatTextViewEditTextButton 搭配使用的默认微件实现。
EmojiCompat
支持库的主要公开 Surface。它执行所有外部调用并与系统的其他部分协调。
EmojiCompat.Config
配置要创建的单例实例。
EmojiSpan
替换字符(序列)并呈现字形的 ReplacementSpan 子类。
EmojiCompat 字体
EmojiCompat 使用一种字体显示表情符号。该字体是 Android 表情符号字体的修改版,修改方式如下所示:
  • 为了提供向后兼容性以呈现表情符号字符,所有表情符号字符都通过 Unicode 的补充专用区-A 中的单个代码点表示,从 U+F0001 开始。
  • 额外的表情符号元数据以二进制格式插入到字体中,并在运行时由 EmojiCompat 解析。数据嵌入到字体的 meta 表格中,并带有专用标记“Emji”

配置选项

您可以使用 EmojiCompat 实例修改 EmojiCompat 行为。您可以使用基类中的以下方法来设置配置:

Kotlin

    val config = FontRequestEmojiCompatConfig(...)
            .setReplaceAll(true)
            .setEmojiSpanIndicatorEnabled(true)
            .setEmojiSpanIndicatorColor(Color.GREEN)
            .registerInitCallback(object: EmojiCompat.InitCallback() {
                ...
            })
    

Java

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

    

添加初始化监听器

EmojiCompatEmojiCompat 类提供 registerInitCallback()unregisterInitCallback() 方法以注册初始化回调。要使用这些方法,请创建 EmojiCompat.InitCallback 类的实例。调用这些方法并传递 EmojiCompat.InitCallback 类的实例。当 EmojiCompat 支持库的初始化成功时,EmojiCompat 类会调用 onInitialized() 方法。如果库初始化失败,则 EmojiCompat 类会调用 onFailed() 方法。

要随时检查初始化状态,请调用 getLoadState() 方法。它会返回以下某个值:LOAD_STATE_LOADINGLOAD_STATE_SUCCEEDEDLOAD_STATE_FAILED

将 EmojiCompat 与 AppCompat 微件搭配使用

如果您使用的是 AppCompat widgets,则可以使用从 扩展的 EmojiCompat 微件。

  1. 将支持库添加到 dependencies 部分。
  2.     dependencies {
              implementation "com.android.support:support-emoji-appcompat:$version"
        }
        
  3. 在布局 XML 中使用 EmojiCompat AppCompat Widget 微件。
  4.     <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"/>
        

捆绑式字体配置

EmojiCompat 支持库也提供捆绑式字体版本。这个包中包含具有嵌入式元数据的字体,还包含一个使用 AssetManager 加载元数据和字体的 BundledEmojiCompatConfig

注意:字体的大小达多个兆字节。

添加支持库依赖项

要通过捆绑式字体配置使用 EmojiCompat 支持库,您必须在开发环境中修改应用项目的类路径依赖项。

要将支持库添加到应用项目中,请执行以下操作:

  1. 打开应用的 build.gradle 文件。
  2. 将支持库添加到 dependencies 部分。
    dependencies {
        ...
        implementation "com.android.support:support-emoji-bundled:$version"
    }
    

使用捆绑式字体配置 EmojiCompat

要使用捆绑式字体配置 EmojiCompat,请执行以下步骤:

  1. 使用 BundledEmojiCompatConfig 创建 EmojiCompat 的实例并提供 Context 的实例。
  2. 调用 init() 方法以初始化 EmojiCompat 并传递 BundledEmojiCompatConfig 的实例。

Kotlin

    class MyApplication : Application() {

        override fun onCreate() {
            super.onCreate()
            val config = BundledEmojiCompatConfig(this)
            EmojiCompat.init(config)
        }
    }
    

Java

    public class MyApplication extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            EmojiCompat.Config config = new BundledEmojiCompatConfig(this);
            EmojiCompat.init(config);
            ...
        }
    }
    

不通过微件使用 EmojiCompat

EmojiCompat 使用 EmojiSpan 呈现正确的图片。因此,它必须使用 EmojiSpans 将任意给定的 CharSequence 转换为 Spanned 实例。EmojiCompat 类提供了一种通过 EmojiSpansCharSequences 转换为 Spanned 实例的方法。使用此方法,您可以处理和缓存已处理的实例,而不是原始字符串,从而提高应用的性能。

Kotlin

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

Java

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

将 EmojiCompat 用于 IME

使用 EmojiCompat 支持库,键盘可以呈现与其互动的应用所支持的表情符号。IME 可以使用 hasEmojiGlyph() 方法检查 EmojiCompat 是否能够呈现表情符号。此方法采用表情符号的 CharSequence,如果 EmojiCompat 可检测并呈现表情符号,则返回 true

键盘还可以检查应用支持的 EmojiCompat 支持库版本,以确定要在调色板中呈现的表情符号。要检查版本(如果可用),键盘需要检查 EditorInfo.extras 软件包中是否存在以下键:

收到 EditorInfo.extras 软件包中的键后,键盘可以使用 hasEmojiGlyph() 方法,其 metadataVersion 值供 EDITOR_INFO_METAVERSION_KEY 用来检查应用是否可以呈现特定的表情符号。

将 EmojiCompat 与自定义微件搭配使用

您始终可以使用 process() 方法对应用中的 CharSequence 进行预处理,并将其添加到任何可呈现 Spanned 实例的微件;例如,TextView。此外,EmojiCompat 还提供了以下微件辅助类,帮助您轻松地让支持表情符号的自定义微件丰富起来。

示例 TextView

Kotlin

    class MyTextView(context: Context) : AppCompatTextView(context) {

        private val emojiTextViewHelper: EmojiTextViewHelper by lazy(LazyThreadSafetyMode.NONE) {
            EmojiTextViewHelper(this).apply {
                updateTransformationMethod()
            }
        }

        override fun setFilters(filters: Array<InputFilter>) {
            super.setFilters(emojiTextViewHelper.getFilters(filters))
        }

        override fun setAllCaps(allCaps: Boolean) {
            super.setAllCaps(allCaps)
            emojiTextViewHelper.setAllCaps(allCaps)
        }
    }
    

Java

    public class MyTextView extends AppCompatTextView {
       ...
       public MyTextView(Context context) {
           super(context);
           init();
       }
       ...
       private void init() {
           getEmojiTextViewHelper().updateTransformationMethod();
       }

       @Override
       public void setFilters(InputFilter[] filters) {
           super.setFilters(getEmojiTextViewHelper().getFilters(filters));
       }

       @Override
       public void setAllCaps(boolean allCaps) {
           super.setAllCaps(allCaps);
           getEmojiTextViewHelper().setAllCaps(allCaps);
       }

       private EmojiTextViewHelper getEmojiTextViewHelper() {
           ...
       }
    }
    
示例 EditText

Kotlin

    class MyEditText(context: Context) : AppCompatEditText(context) {

        private val emojiEditTextHelper: EmojiEditTextHelper by lazy(LazyThreadSafetyMode.NONE) {
            EmojiEditTextHelper(this).also {
                super.setKeyListener(it.getKeyListener(keyListener))
            }
        }

        override fun setKeyListener(input: KeyListener?) {
            input?.also {
                super.setKeyListener(emojiEditTextHelper.getKeyListener(it))
            }
        }

        override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
            val inputConnection: InputConnection = super.onCreateInputConnection(outAttrs)
            return emojiEditTextHelper.onCreateInputConnection(
                    inputConnection,
                    outAttrs
            ) as InputConnection
        }
    }
    

Java

    public class MyEditText extends AppCompatEditText {
       ...
       public MyEditText(Context context) {
           super(context);
           init();
       }
       ...
       private void init() {
           super.setKeyListener(getEmojiEditTextHelper().getKeyListener(getKeyListener()));
       }

       @Override
       public void setKeyListener(android.text.method.KeyListener keyListener) {
           super.setKeyListener(getEmojiEditTextHelper().getKeyListener(keyListener));
       }

       @Override
       public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
           InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
           return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
       }

       private EmojiEditTextHelper getEmojiEditTextHelper() {
           ...
       }
    }
    

常见问题解答

  • 如何启动字体下载?
  • 如果设备上不存在表情符号字体,会在首次请求时下载这些字体。下载调度对应用是透明的。

  • 初始化需要多长时间?
  • 下载字体后,初始化 EmojiCompat 大约需要 150 毫秒。

  • EmojiCompat 支持库会使用多少内存?
  • 目前,用于查找表情符号的数据结构加载到应用的内存中,约占 200KB。

  • 我可以将 EmojiCompat 用于自定义 TextView 吗?
  • 可以。EmojiCompat 为自定义微件件提供辅助类。也可以对给定字符串进行预处理并将其转换为 Spanned。要详细了解微件辅助类,请参阅将 EmojiCompat 与自定义微件搭配使用部分。

  • 如果我在搭载 Android 4.4(API 级别 19)或更低版本的设备上的布局 XML 中添加微件,会出现什么情况?
  • 您可以在支持搭载 Android 4.4(API 级别 19)或更低版本的设备的应用中添加 EmojiCompat 支持库或其微件。但是,如果设备搭载 API 级别 19 以下的 Android 版本,EmojiCompat 及其微件将处于“无操作”状态。这意味着 EmojiTextView 的行为会与常规 TextView.EmojiCompat 实例完全相同;当您调用 init() 方法时,它会立即进入 LOAD_STATE_SUCCEEDED 状态。

其他资源

要详细了解如何使用 EmojiCompat 库,请观看 EmojiCompat