表情符号兼容性

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 部分。

Groovy

dependencies {
    ...
    implementation "androidx.emoji:emoji:28.0.0"
}

Kotlin

dependencies {
    ...
    implementation("androidx.emoji: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. 在布局 XML 中使用 EmojiCompat 微件。如果您使用的是 AppCompat,请参阅将 EmojiCompat 与 AppCompat 微件搭配使用部分。
  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 中的单个 Unicode 代码点表示,从 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,则可以使用从 AppCompat widgets 扩展的 EmojiCompat 微件。

  1. 将支持库添加到依赖项部分。

    Groovy

    dependencies {
        ...
        implementation "androidx.emoji:emoji-bundled:$version"
    }

    Kotlin

          dependencies {
              implementation("androidx.emoji:emoji-appcompat:$version")
          }
          

    Groovy

          dependencies {
              implementation "androidx.emoji:emoji-appcompat:$version"
          }
          
  2. 在布局 XML 中使用 EmojiCompat AppCompat Widget 微件。
  3. <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 部分。

Groovy

dependencies {
    ...
    implementation "androidx.emoji:emoji:28.0.0"
}

Kotlin

dependencies {
    ...
    implementation("androidx.emoji:emoji:28.0.0")
}

使用捆绑式字体配置 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 支持库或其微件。但是,如果设备搭载的 Android 版本低于 API 级别 19,EmojiCompat 及其微件将处于“无操作”状态。这意味着 EmojiTextView 的行为会与常规 TextView.EmojiCompat 实例完全相同;当您调用 init() 方法时,它会立即进入 LOAD_STATE_SUCCEEDED 状态。

其他资源

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