近期在项目中遇到这么一个需求,使用颜文字替换按键图标。

之前对于颜文字有了解,微信,QQ中也经常使用,但是如何实现的呢?一无所知……

对于这块突然有了一点兴趣,所以做这么一个分享,与其说分享,不如说探索更为准确一点。

为何做这个分析探索,主要说来以下原因:

使用颜文字替换按键图标能减少本身apk中图片资源的使用,从而达到减少apk包大小。

做定制化系统的时候,使用颜文字能使代码优雅简洁,图文混排一句代码解决,多语言翻译简单化。

做聊天社交,论坛咨询类APP时,颜文字(Emoji)能使聊天,评论,增强用户体验,也是这类app必不可少的一部分内容。

一、什么是Emoji?

既然要用到 Emoji ,我们先来了解一下什么是 Emoji。

Emoji 是可以被插入文字中的图形符号。它是一个日本语,e 表示"绘",moji 表示 "文字" ,连在一起就是 “绘文字”。

Emoji 最早是上个世纪 90 年代的时候,又日本电信商率先支持,就是为了在短信中,插入表情,来增强短信的体验。2007 年,Apple 在 iPhone 中支持了 Emoji,才让它在全球范围内流行起来。

早期的时候,Emoji 的实现是将一些特殊的符号组合替换成图片表情,例如 :) 替换成 

,这样的解决方案会导致很难将 Emoji 的表情标准化,而且表达的范围也有限。

2010年开始,Unicode 开始为 Emoji 分配码点,也就是说,在那之后的 Emoji 符号,就是一个字体,它会被渲染为图片显示。

Emoji 由于其表达情绪的特点,被广受欢迎。Emoji 的国际标准在 2015 年出台,现在已经是 5.0 版本了,而在 2018 年,将发布 Emoji 6.0(之后会重命名为 Emoji 11,其实就是 Emoji 5.0 的升级版) 版本的标准。

截止到现在,Emoji 5.0 中,被列入 Unicode 的已经有 2623 个了。

具体细节可以在这个网站中查询到:

http://www.unicode.org/emoji/charts/full-emoji-list.html

到这里大家应该清楚,Emoji 在标准化后,其实就是一个字体,它被 Unicode 分配了固定的码点,一般我们就用标准的 Unicode 来标识一个唯一的 Emoji。

虽然 Emoji 已经被标准化了,但是不同平台因为使用的字体不同,导致同样的 Unicode 代表的 Emoji,被渲染显示出不同的效果。

二、Emoji 在 Android 中的现状

2.1如何使用Emoji

emoji表情是一种表情符号,在代码中它现在其实是一组遵循Unicode的编码,即每一个表情符号都对应了一个Unicode编码。更进一步说,emoji表情实际上是一组Unicode编码与一组表情描述之间的一一对应。注意,这里所说的不是表情图片,而是表情描述。那么图片的实现是由谁来负责的呢?图片是由各个系统或者软件针对统一的表情描述来各自实现的,他们都遵循统一的Unicode编码规范。也就是说Unicode编码其所对应的表情描述是统一的,是所有人都要共同遵守的一套标准或者规范,而具体的表情图片则可能因平台的不同而产生差异,比如Android和ios。

在android中,我们可以只用go输入法或者搜狗输入发来输入emoji表情,对于用户这没有任何问题。但是对于程序员来说如何在程序中输入或者得到一个emoji表情呢?比如我们想通过textview.setText()方法来输入一个emoji表情。

其实通过emoji表情的通用Unicode编码就可以实现,直接使用Character.toChars()方法将unicode编码转换为一个char数组,再将这个char数组转换成为字符串就可以直接操作了,系统会自动将其解析为表情图片,可以直接显示在textview组件当中,不需要我们做任何其他的事情。

代码实现:

private void setEmojiToTextView() {

    int unicodeJoy = 0x1F602;

    String emojiString = getEmojiStringByUnicode(unicodeJoy);

    tvTest.setText(emojiString);

}

private String getEmojiStringByUnicode(int unicode) {

    return new String(Character.toChars(unicode));

}

然而…………………………….

上面的方法是没有做任何特殊处理的,完全是以来设备自己的字体库来进行 Emoji 渲染的,这就会导致有一些 Emoji 在某些设备上显示不出来的情况。

Emoji 无法显示,会被显示成一个豆腐块 “☐” ,而这并不是我们想要的。如何处理它,这里就必须提到下面这个EmojiCompat.

三、使用 EmojiCompat(官方库)

3.1 什么是 EmojiCompat

根据官方文档描述,EmojiCompat 支持库主要是为了让 Android 设备,达到最新的 Emoji 符号的显示效果,它可以防止应用中,出现以豆腐块 “☐” 的形式来显示 Emoji,虽然它仅仅只是因为你当前的设备没有这个字体而已。通过 EmojiCompat ,你的设备无需等待 Android 系统更新,就可以获得最新的 Emoji 表情显示效果。

3.2如何使用 EmojiCompat

EmojiCompat 支持库,最低支持到 Android 4.4(Api Level 19) 的系统设备。

EmojiCompat 提供两种字体的支持方式,它们分别是:

1.可下载的字体配置。(残废状态)

本地捆绑的字体配置。

这两种使用方式,除了引用的库不同之外,最根本的原因在于,可下载的字体的方式,会在首次启动的时候检查本地是否有该字体,没有的话会从网上下载最新的 Emoji 字体;而本地捆绑的方式,会在 App 打包的过程中,植入一个最新的 Emoji 字体文件,然后遇到不能支持的 Emoji,就会从这个字体文件中,加载资源并且渲染。

目前官方使用的是 NotoColorEmojiCompat.ttf 字体文件(其实这里也可以手动加载其他的ttf字体文件,操作流程见文后)

本地捆绑的方式会嵌入一个字体文件,无形中增大了 Apk 安装包的体积,但是可下载字体的方式,又完全依赖 Google 服务,所以在国内基本上是处于残废状态,在这个大环境下,我们这里只能选择本地捆绑的方式来使用 EmojiCompat。

无论使用哪种方式配置字体,对于 EmojiCompat 而言,其实是不关心的,它只需要判断当前设备是否支持这个 Emoji,支持就使用系统内置的,不支持的话,就使用 EmojiSpans 来替换 CharSequence,来达到替换渲染的效果。

EmojiCompat 的运行原理如下图所示。

3.3 本地捆绑的字体配置方式

既然可下载的 Emoji 字体,需要配合 Google 服务,那这里就不再过多介绍了。

本文主要讲解如何使用本地捆绑的方式,使用 EmojiCompat。

第一步,需要添加 Gradle 依赖。

展开源码

第二步,初始化 EmojiCompat。

初始化 EmojiCompat ,需要两个步骤。

首先需要生成一个 BundledEmojiCompatConfig 对象,它的构造方法接收一个 Context。

再调用 EmojiCompat.init() 方法,将前面生成的 config 传递给它进行初始化。

这个过程越早越好,因为初始化是耗时的,它会去加载打包的时候,嵌入的 Emoji 字体文件,所以大概需要消耗 150ms 的时间,并且占用大概 200kb 的内存。

public class MyApplication extends Application {

@Override

    public void onCreate() {

       super.onCreate();

       EmojiCompat.Config config = new BundledEmojiCompatConfig(this);

       EmojiCompat.init(config);

    }

}

第三步,使用 EmojiCompat。

初始化完成之后,就剩下如何使用它了。

EmojiCompat 的处理逻辑,前面已经使用图片描述清楚了。它会加载一个 Emoji 字体,然后判断当前设备是否支持需要显示的 Emoji,如果不支持,则使用 EmojiSpans 替换它,最终将处理过的 CharSequence 设置到 TextView 上。

而这个过程,EmojiCompat 提供了非常简单的方法,process()。从它的签名可以看出,它接受一个 CharSequence 并处理它,然后返回一个 CharSequence。

举个例子:这里转换一个笑脸的表情。EmojiCompat.get().process("\uD83D\uDE01")

process() 需要接受一个 Unicode 的字符,所以如果得到的数据是前面提到的 Emoji Code 的话,就需要一步单独的转换。process() 内部已经帮我们完成了转换,这些细节都无需我们关心,我们只需要将它返回的 CharSequence 设置给 TextView 就可以了。

3.4 Emoji AppCompat Widgets

在实际项目中,如果每次都需要通过 EmojiCompat.get().process() 对字符串进行处理,其实也挺麻烦的。为此 Google 还为开发者提供了对应控件支持。

如果需要使用它,就需要引入新的依赖库。

dependencies {

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

}

引入之后,就可以直接在 XML 中使用 EmojiAppCompat 提供的控件。

使用 support-emoji-appcompat 只是节省了我们 process() 的步骤,但是依然需要 init() 。

3.5 自定义控件支持 Emoji

你可以一直使用 progress() 或者使用 EmojiAppCompatXxx 控件,但是如果你想要自定义一个控件来显示 Emoji,就需要使用 EmojiCompat 提供的另外两个帮助类。

EmojiTextViewHelper

EmojiEditViewHelper

这两个使用起来非常简单,一个用于处理纯展示的控件,一个用于处理有输入的状态的控件,非常的简洁明了。

哪怕不记得了,看看 EmojiAppCompatTextView 和 EmojiAppCompatEditView 中的实现方式就可以了。

这里拿 EmojiAppCompatTextView 举例子,只需要在几个关键的位置上,使用 EmojiTextViewHelper 的对应方法即可。

3.6 EmojiCompat面临的问题

整体来说 EmojiCompat 还是很好用的,无论使用哪种方式加载它,实际上我们都不需要做过多的干预。

这里参考官方文档,列举最常见的几个问题。

1、下载字体的下载策略是怎么样的?

Emoji 字体在第一次使用的时候,会检测是否存在于当前设备,如果不存在则在子线程中进行下载。

2、初始化需要多长时间?

当本地已经有字体之后,初始化 EmojiCompat 大约需要 150 毫秒。

3、EmojiCompat 支持库,会使用多少内存?

目前,Emoji 字体被完全加载之后,会使用大约 200kb 的内存。

4、在 Android 4.4 以下的设备上,使用 EmojiAppCompatXxx 控件会发生什么情况?

EmojiCompat 内部已经做了兼容处理,在低版本上就和使用普通的 AppCompatXxx 控件一样。

5、本地捆绑的 Emoji 字体文件,大约有多大?

本地捆绑的 Emoji 字体文件 NotoColorEmojiCompat.ttf,会在打包的时候嵌入到 assets 目录下,现在实际情况来看大小有 7.4MB,这会直接造成 Apk 的增大。

更多的细节,还是建议大家阅读官方文档。

https://developer.android.google.cn/guide/topics/ui/look-and-feel/emoji-compat.html

四、EmojiCompat 的缺陷?

在实际使用 EmojiCompat 的过程中,还遇到了一个不能算缺陷的缺陷。

它只有在当前设备遇到不被支持的 Emoji 的时候,才会从 Support Font 中加载字体,如果有,它会使用 System Font 。

这也不能怪 EmojiCompat 的设计者,它的出发点,是为了解决 Emoji 在某些设备中,显示豆腐块 “☐” 的问题,而不关心它到底是不是显示最新的 Emoji,是在解决有无的问题。

这就很尴尬了,其实有时候 Android 设备内置支持的字体,显示的效果并不好,我们先来看看使用 EmojiCompat 前后的对比效果。

很清晰的可以看到 EmojiCompat 帮我补齐了我当前设备部支持的那些 Emoji 表情,但是并没有将 Android 的果冻表情替换为标准的 Emoji 表情。

那么,如果我们想要让它显示最新的 Emoji ,我们需要这么办呢?

前面提到,自从 Emoji 开始被标准化之后,其实就是一个字体,并且 EmojiCompat 也是帮我们捆绑嵌入了一个字体包在 assets 目录下,那我们只需要让我们显示的 TextView 加载这个 Emoji 字体,就可以解决这个问题。

五、项目定制化颜文字应用举例

按“设置键”编辑,这里面的“设置键”就是图标的形式展示的,但是和我们正常开发中使用的图标不一样,UX并没有给我们提供任何的图片素材,不需要我们将图片实体打进我们的apk包中。颜文字实际上就是一套预制的编码规范,将Unicode编码对应一套图标展示,

注意到了关键点,“预制的编码规范”,emm~~局限性太大,太依赖系统和编码规范了(定制化系统)

目前颜文字的实现的方式主要有两种大致可以分为两类:

系统支持的Emoji图标

自定义Emoji图标

这是目前Github上使用最广泛的emoji开源表情库:https://github.com/rockerhieu/emojicon

做法上,实质是用富文本去替换代码中的Unicode从而达到图文混排的效果,从表现效果上看,就是颜文字。(富文本做图文混排后续补充)

六、Emojicon数据库中的存取问题

Emojicon表情在数据库中的存取方法在使用过程中出现了问题,出现了表情存到数据库之后变为空白,取出后也是空白的问题。

emoji分为 softbank emoji 和 unicode emoji,由于目前 softbank emoji 已停止更新,所以大多数 emoji 为 unicode emoji,emojicon 也是如此。unicode emoji 是四个字节长度,格式类似于 \uD83D 之类。由于项目和数据库都是UTF-8编码,UTF-8 是变长编码,可能是2-4个字节,而 MySQL 数据库的普通 UTF-8 编码只有三个字节,所以会出现无法解析的情况。

解决方案大致有以下几种方法解决:

1.更改数据库编码

  MySQL 版本 5.5.3 以上可以使用utf8mb4编码来进行存储,此编码支持4字节的 UTF-8 字符。但是这样做很可能会在其他地方出现不兼容的问题,且更改数据库编码对系统整体改动太大,不推荐使用。

2.转化为三个字节的 softbank emoji

  如果要转化为 softbank emoji 的话,需要通过对照表将 unicode emoji 转化为 softbank emoji,工作量不小,而且新的表情并不支持,不推荐使用。

3.对 unicode 字符串进行加密解密

  采用了 Apache 的 commons-lang (见附件二)包中的 StringEscapeUtils 类来对字符串进行加密解密:

//加密

mContent = StringEscapeUtils.escapeJava(emojiEditText.getText().toString());

//解密

mComment.setContent(StringEscapeUtils.unescapeJava(json.getJSONObject(i).getString("content")));

附一:替换手机emoji表情库操作流程(需要root权限):

方式一:通过adb命令替换

adb root

adb remount

//push文件到 system/fonts

adb push C:\Users\jjj\Desktop\emojittf\ios12\NotoColorEmoji.ttf  system/fonts

//修改权限

adb shell chmod 644 /system/fonts/NotoColorEmoji.ttf

//同步

adb shell sync

//最后重启一下设备

adb reboot

方式二:手动替换ttf字体文件

手机已经root,下载ES文件夹,进入根目录,找到/system/fonts,用需要的NotoColorEmoji.ttf替换掉之前的就行。

附:各版本NotoColorEmoji.ttf文件

ios12
https://download.csdn.net/download/geniushorse/11329664

ios11
https://download.csdn.net/download/geniushorse/11329683

ios10
https://download.csdn.net/download/geniushorse/11329687

android 9.0
https://download.csdn.net/download/geniushorse/11329693

android 8.0
https://download.csdn.net/download/geniushorse/11329698

附件二:commons-lang3-3.11.jar(阿帕奇的一个通用包)

浅谈emoji(分析与使用)相关推荐

  1. 浅谈富集分析的Pvalue

    浅谈富集分析的Pvalue 引言 超几何分布 Python计算超几何分布 引言 今天给大家带来一个关于"撒币"的问题,说起"撒币",最经典就是二项分布,也就是你 ...

  2. 浅谈GWAS分析后的富集分析操作(GO/KEGG)

    浅谈GWAS分析后的富集分析操作(GO/KEGG) 作者:刘济铭 ######################## 在我们完成全基因组关联分析后,常常筛选得到特定性状的基因集,接下来,通常我们需要开展 ...

  3. 浅谈图分析商业化的机遇与挑战,你注意到了吗?

    前言 本篇文章中,小普将以图分析这一技术栈为线索,站在行业的高度,抽丝剥茧,思考图分析的产品应用与用户体验,在整个介绍中,我们可以很清晰的看到,在图分析领域,机遇与挑战并存. 再上征"图&q ...

  4. 浅谈恶意软件分析工程师的职业发展路线

    这里以Windows病毒分析师为例,讲解病毒分析师的职业发展路线和应该具有的专业能力.图中有的模块被分为红色和黄色,其中红色代表最重要,黄色代表相对重要. 病毒分析工程师,是在未来无法被人工智能取代. ...

  5. 浅谈API安全的应用

    理论基础 API它的全称是Application Programming Interface,也叫做应用程序接口,它定义了软件之间的数据交互方式.功能类型.随着互联网的普及和发展,API 从早期的软件 ...

  6. 浅谈软件性能测试中关键指标的监控与分析(转)

    浅谈软件性能测试中关键指标的监控与分析 一.软件性能测试需要监控哪些关键指标? 软件性能测试的目的主要有以下三点: Ø  评价系统当前性能,判断系统是否满足预期的性能需求. Ø  寻找软件系统可能存在 ...

  7. 浅谈:Spring Boot原理分析,切换内置web服务器,SpringBoot监听项目(使用springboot-admin),将springboot的项目打成war包

    浅谈:Spring Boot原理分析(更多细节解释在代码注释中) 通过@EnableAutoConfiguration注解加载Springboot内置的自动初始化类(加载什么类是配置在spring.f ...

  8. 浅谈 Linux 高负载的系统化分析

    简介: 浅谈 Linux 高负载的系统化分析,阿里云系统组工程师杨勇通过对线上各种问题的系统化分析. 讲解 Linux Load 高如何排查的话题属于老生常谈了,但多数文章只是聚焦了几个点,缺少整体排 ...

  9. Android 系统(104)---浅谈ANR及log分析ANR

    浅谈ANR及log分析ANR 一:什么是ANR ANR:Application Not Responding,即应用无响应 二:ANR的类型 ANR一般有三种类型: 1:KeyDispatchTime ...

最新文章

  1. 每日一皮:资深程序员调试代码的样子...
  2. 6.28 头像预览:form方法和ajax方法
  3. Android源码分析--MediaServer源码分析(一)
  4. spring boot基础教程:入门程序Hello World的编写
  5. boost::local_time模块实现自纪元以来的秒数的测试程序
  6. java cookie secure_Cookie的Secure属性
  7. 成员/方法/属性/私有
  8. html语言amp,第二amp;三讲HTML语言.ppt
  9. GStreamer 编写一个简单的MP3播放器
  10. STM103单片机串口输出函数printf重映射
  11. 浮动float的一些规则
  12. 第2节 mapreduce深入学习:15、reduce端的join算法的实现
  13. 写好PPT的四大要点
  14. Java自学路线图之Java进阶自学
  15. java实现斐波那契数列求和_Java递归实现斐波那契数列
  16. SmartSVN使用
  17. 心电信号越界怎么回事_心电信号的分析
  18. 电脑每次开机都出现check file system on:C 的解决办法
  19. 【优雅编程之道】之IO流,序列化的4点建议
  20. 电脑任务栏应用图标变成白色怎么恢复

热门文章

  1. 13.1-自己开发一个“单片机烧写工具”!不是开玩笑吧?原来如此^~^(OTA升级)
  2. WIN二种安装方式UEFI和BIOS方式引导修复
  3. 整理C语言和C++中常用输入输出函数
  4. codeblocks20版本无法找到编译器的解决方法!
  5. 吐血分享!这几个在线网站超劲爆,福利满满
  6. Pathos: Nethack Codex 游戏指南
  7. Android wifi开发包含列表获取点击连接wifi
  8. js实现web汉字笔画教学
  9. Redis开启远程访问及密码认证
  10. 微信公众号及小程序开发入门(二)