ITmob-Ly
发布于 2022-12-18 / 206 阅读
0

Jetpack Compose 怎样支持最新版本的 emoji 表情符号

🎄 Christmas Tree🫶 Heart Hands❤️ Red Heart😊 Smiling Face with Smiling Eyes
✨ Sparkles🎁 Wrapped Gift🎅 Santa Claus🥹 Face Holding Back Tears
🔥 Fire❄️ Snowflake😂 Face with Tears of Joy🎉 Party Popper

1. 简介

Emoji 表情符号是 Unicode 字符,Emoji 表情的国际标准在 2015 年出台,目前(2022年12月)已经是 **v15.0** 版本的标准了。Unicode 每年都会更新表情符号的标准集,用户对所有类型应用程序的表情符号使用量迅速增加。

如果我们的应用程序显示网络内容或提供文本输入,则我们需要支持最新的表情符号字体。否则,较新的表情符号可能会显示为 豆腐 (☐) 的小方框 或其他错误呈现的表情符号。

Android 11(API 级别 30)及更低版本不支持可下载的 Emoji 字体,无法更新表情符号字体,因此在这些较低版本的手机中不能正常显示最新的表情符,需要程序手动处理对 Emoji 的兼容,Android 官方提供了 androidx.emoji2:emoji2 兼容库。

但是 Jetpack Compose 默认的可组合函授 Text,只支持使用系统默认的字符集显示 emoji,根据 IssueTracker 中新功能的介绍,Compose 已经支持 EmojiCompat,但当我使用 Android 12 的设备按 官方建议方式检查对 emoji 的支持 时,v14.0 版本的 emoji 并不能正常显示。

本文主要介绍使用 appcompat, 和 emoji2 支持最新的表情符,这些是依赖与 GMS 提供的可下载字体的,关于没有 GMS 服务的手机怎样解决这个问题,将在接下来的文章介绍。

使用下面的表情符号示例来测试应用程序是否符合最新的 Unicode 版本:

ExamplesUnicode Version
🫠 🫱🏼‍🫲🏿 🫰🏽https://emojipedia.org/emoji-14.0/
😶‍🌫️ 🧔🏻‍♀️ 🧑🏿‍❤️‍🧑🏾https://emojipedia.org/emoji-13.1/
🥲 🥷🏿 🐻‍❄️https://emojipedia.org/unicode-13.0/
🧑🏻‍🦰 🧑🏿‍🦯 👩🏻‍🤝‍👩🏼https://emojipedia.org/emoji-12.1/
🦩 🦻🏿 👩🏼‍🤝‍👩🏻https://emojipedia.org/emoji-12.0/

emoji

所以我在 Jetpack Compose 中继续通过 androidx.emoji2:emoji2 库来兼容最新的表情符号,这就需要用到 AndroidView 来渲染 Android 传统控件。其中也会遇到多个问题,下文会介绍

emoji2 库提供了对 Android 4.4(API 级别 19)到 Android 10(API 级别 29)之间版本的最新表情符号的兼容。

调用 emoji2 的多种方式:

2. 使用 AppCompat 支持最新的 emoji

emoji2 库是 AppCompat 库的依赖项,使用 AppCompat 则无需其他配置即可工作。AppCompat 还提供了 AppCompatEditText AppCompatToggleButton AppCompatButton 等控件**。**

添加 appcompat 依赖(1.4.0-alpha01 或更高版本) :

// build.gradle
implementation 'androidx.appcompat:appcompat:1.4.1'

可组合函授:

@Composable
fun EmojiWithAppCompatTextView(textStr: String) {
    AndroidView(
        factory = { context ->
            AppCompatTextView(context).apply {
                setTextColor(Black.toArgb())
                text = textStr
                textSize = 24F
                textAlignment = View.TEXT_ALIGNMENT_CENTER
            }
        },
        update = {
            it.apply {
                text = textStr
            }
        }
    )
}

效果:

emojiwithappcompattextview1.jpg

如果应用使用的是传统的XML布局,使用 appcompat 时,也可用直接使用 AppCompatActivity 即可,它会自动使用 AppCompatTextView 代替 TextView,因此您无需更新 XML。

3. 使用 emoji2-views 支持最新的 emoji

// build.gradle
implementation "androidx.emoji2:emoji2:$emojiVersion"
implementation "androidx.emoji2:emoji2-views:$emojiVersion"
@Composable
fun EmojiWithEmojiTextView(textStr: String) {
    AndroidView(
        factory = { context ->
            EmojiTextView(context).apply {
                setTextColor(Black.toArgb())
                text = processedText
                textSize = 24F
                textAlignment = View.TEXT_ALIGNMENT_CENTER
            }
        },
        update = {
            it.apply {
                text = processedText
            }
        }
    )
}

emoji2-views 提供了 EmojiTextViewEmojiEditTextEmojiButtonEmojiCompatProcess 、等,可用使用相似的方式调用。

4. 不使用 EmojiCompat 控件的情况下支持最新的 emoji

// build.gradle
implementation 'androidx.emoji2:emoji2:1.2.0'
// AndroidManifest.xml
<application
    android:name=".MyApplication" >
...
<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>
...
// application class
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        EmojiCompat.init(this)
    }
}
@Composable
fun EmojiCompatProcess(
    textString: String
) {
    val processedText = EmojiCompat.get().process(textString)
    AndroidView(
        factory = { context ->
            EmojiTextView(context).apply {
                setTextColor(Black.toArgb())
                text = processedText
                textSize = 24F
                textAlignment = View.TEXT_ALIGNMENT_CENTER
            }
        },
        update = {
            it.apply {
                text = processedText
            }
        }
    )
}

EmojiCompat 类提供了 process() 方法来将 CharSequences 转换为 Spanned 实例。

可以使用此方法,在后台调用 process() 并缓存结果,从而提高应用程序的性能。

5. 问题

  1. emoji 图标显示为半透明

    emoji half alpha

    这是因为 AppCompatTextView 有一个默认的半透明文本颜色。

    上面代码中的 setTextColor(*Black*.*toArgb*()) 就是为了解决这个问题。

  2. 无法显示最新的图标

    使用了 appcompat 或 emoji2 扩展库后仍然不能显示最新的 emoji 可能的原因:

    1. 最新的字体文件还未下载成功
    2. 谷歌的 GMS 服务版本太低
    3. 系统依赖谷歌的 GMS 服务下载 emoji 字体文件,系统没有 GMS 服务

    我们可以考虑使用 emoji2-bundled 扩展库,使用离线的 emoji 字体文件显示,该文件 10M 左右,会增加安装包大小,并且版本发布后用于已经使用的版本不能再次获得最新的字体文件。

    emoji2-bundled 的用法与 4. 不使用 EmojiCompat 控件的情况下支持最新的 emoji 章节的用法类似,只是将依赖项 emoji2 改为 emoji2-bundled

    // build.gradle
    implementation 'androidx.emoji2:emoji2-bundled:1.2.0'