Emoji兼容性

我们经常会遇到这样的问题: 给朋友发的emoji表情, 在自己手机上展示是正常的, 但是到朋友手机上, 却没有展示出来, 或者展示出来了, 但是也跟自己手机上展示的不一样. 所以, 这是什么原因呢?

要避免这种情况, 就需要使用Android Emoji的兼容包了.

Emoji兼容包目的在于保持Android设备拥有最新的Emoji. 它防止应用使用☐展示丢失的Emoji字符, 而☐意味着设备没有字体支持相应的文本. 通过使用EmojiCompat支持包, 应用的用户不必等候Android系统更新就可以获得最新的Emoji.

EmojiCompat工作原理

EmojiCompat支持包向运行Android 4.4(API 19)+的设备提供类以实现向后兼容的Emoji支持. 你可以配置EmojiCompat使用绑定的或者可下载的字体.

EmojiComat识别指定的CharSequence, 如果必要的话, 会使用EmojiSpans代替它们, 并最终渲染成emoji符号.

可下载字体配置

可下载字体配置使用Downloadable Fonts支持包特性来下载emoji字体. 该支持包也更新必要的emoji元数据, EmojiCompat支持包需要与最新的Unicode版本保持一致.

添加支持包依赖

要使用EmojiCompat支持包, 必要要修改开发环境的应用工程路径依赖.
要在应用中添加支持包, 需要:

  1. 打开应用build.gradle文件.
  2. 将依赖包添加到dependencies区域

dependencies { ... compile "com.android.support:support-emoji:27.1.1" }

初始化可下载字体配置

你需要初始化EmojiCompat来下载元数据和字样. 因为初始化会花费一些时间, 所以初始化进程要运行在后台线程.

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

  • 创建FontRequest类实例并提供字体提供者权限, 字体提供者包, 字体查询以及认证的hash集列表.
  • 创建FontRequestEmojiCompatConfig实例并提供Context实例和FontRequest.
  • 调用init()方法初始化EmojiCompat并传递FontRequestEmojiConfig实例
  1. public class MyActivity extends Activity {
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. FontRequest fontRequest = new FontRequest(
  6. "com.example.fontprovider",
  7. "com.example",
  8. "emoji compat Font Query", CERTIFICATES);
  9. EmojiCompat.Config config = new FontRequestEmojiCompatConfig(this, fontRequest);
  10. EmojiCompat.init(config);
  11. ...
  12. }
  13. }
  • 在布局文件中使用EmojiCompat控件.
  1. <android.support.text.emoji.widget.EmojiTextView
  2. android:layout_width="wrap_content"
  3. android:layout_height="wrap_content"/>
  4.  
  5. <android.support.text.emoji.widget.EmojiEditText
  6. android:layout_width="wrap_content"
  7. android:layout_height="wrap_content"/>
  8.  
  9. <android.support.text.emoji.widget.EmojiButton
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content"/>

包构件

构件: EmojiEditText, EmojiTextView, EmojiButton. 这些构件是在TextView, EditText和Button上实现EmojiCompat的默认控件实现.

  • EmojiCompat: 支持包的主要公共接口. 它执行了所有的外部调用, 并与系统的其它部分协调.
  • EmojiCompat.Config: 配置要创建的单例.
  • EmojiSpan: ReplacementSpan子类, 取代字符(序列)并渲染字符.
  • EmojiCompat Font: EmojiCompat使用字体展示emoji. 字体是Android Emoji Font的修改版本. 字体接如下规则修改:
  1. 要提供向后兼容性来渲染emoji, 所有的emoji字符用单个Unicode码点表示, 这个码点位于Unicode Supplement Private Use Area-A, 从U+F001开始的
  2. 额外的emoji元数据以二进制格式插入字体, 并在运行时被EmojiCompat解析. 这些数据嵌套在字体的meta表中, 并含有私有标签Emji.

配置选项

你能够使用EmojiCompat实例修改EmojiCompat行为. 你可能使用源于基数的如下方法设置配置:

  • setReplaceAll(): 决定了EmojiCompat是否应该取代它用EmojiSpans找到的所有emoji. 默认情况下, EmojiCompat尽已所能理解系统是否能够渲染emoji, 但并不取代它们. 设置成true的时候, EmojiCompat会取代它用EmojiSpans找到的所有emoji.
  • setEmojiSpanIndicatorEnabled(): 指明EmojiCompat是否用EmojiSpan取代emoji. 设置成true的时候, EmojiCompat为EmojiSpan绘制背景. 但这个方法主要用于debug.
  • setEmojiSpanIndicatorColor(): 设置指明EmojiSpan的颜色. 默认值是GREEN.
  • registerInitCallback(): 告知应用EmojiCompat初始化的状态.
  1. EmojiCompat.Config config = new FontRequestEmojiCompatConfig(...)
  2. .setReplaceAll(true)
  3. .setEmojiSpanIndicatorEnabled(true)
  4. .setEmojiSpanIndicatorColor(Color.GREEN)
  5. .registerInitCallback(new InitCallback() {...})

添加初始化监听器

EmojiCompat类提供了registerInitCallback()和unregisterInitCallback()方法注册初始化回调. 要使用这些方法, 先创建EmojiCompat.InitCallback类, 调用这些方法, 然后传入EmojiCompat.InitCallback实例. 在EmojiCompat支持包初始化成功的时候, EmojiCompat类调用了onInitialized()方法. 如果库初始化失败了, EmojiCompat类调用onFailed()方法.

要想在任何时刻查看初始化状态, 调用getLoadState()方法. 它返回下列值之一: LOAD_STATE_LOADING, LOAD_STATE_SUCCEED或者LOAD_STATE_FAILED.

用AppCompat控件使用EmojiCompat

如果你在使用AppCompat控件, 那么你可能使用继承自AppCompat控件的EmojiCompat控件.
1, 添加如下依赖包.
  dependencies { compile "com.android.support:support-emoji-appcompat:$version" } 
2, 在布局文件中使用EmojiCompat AppCompat Widget.

  1. <android.support.text.emoji.widget.EmojiAppCompatTextView
  2. android:layout_width="wrap_content"
  3. android:layout_height="wrap_content"/>
  4.  
  5. <android.support.text.emoji.widget.EmojiAppCompatEditText
  6. android:layout_width="wrap_content"
  7. android:layout_height="wrap_content"/>
  8.  
  9. <android.support.text.emoji.widget.EmojiAppCompatButton
  10. android:layout_width="wrap_content"
  11. android:layout_height="wrap_content"/>

绑定字体配置

EmojiCompat支持包绑定字体版本也是可用的. 这个包包含了嵌套元数据的字体. 也包含了使用AssetManager加载元数据和字体的BundledEmojiCompatConfig.
备注: 字体大小有好几MB.

添加支持包依赖

要想使用EmojiCompat支持包的绑定字体配置, 你必须修改开发环境中应用工程的类路径依赖.
  dependencies { ... compile "com.android.support:support-emoji-bundled:$version" }

使用绑定字体配置EmojiCompat

要使用绑定字体配置EmojiCompat, 执行下列步骤:
1, 使用BundledEmojiCompatConfig创建EmojiCompat实例并提供Context.
2, 调用init()方法初始化EmojiCompat, 并传入BundledEmojiCompatConfig实例.

  1. public class MyActivity extends Activity {
  2. @Override
  3. public void onCreate() {
  4. super.onCreate();
  5. EmojiCompat.Config config = new BundledEmojiCompatConfig(this);
  6. EmojiCompat.init(config);
  7. ...
  8. }
  9. }

没有控件的情况下使用EmojiCompat

EmojiCompat使用EmojiSpan渲染正确的图片. 由此, EmojiCompat必须使用EmojiSpans将给定CharSequence转化成Spanned. EmojiCompat类提供了方法通过EmojiSpans将CharSequence转化成Spanned对象. 通过这个方法, 你能够处理和缓存已处理实例, 而不是原生字符串, 由此提供了应用的性能.
  CharSequence processed = EmojiCompat.get().process("neutral face \uD83D\uDE10");

IME使用EmojiCompat

使用EmojiCompat支持包, 键盘通过渲染用户正在交互的应用支持的emoji. IME能够使用hasEmojiGlyph()方法检测EmojiCompat是否有能力渲染emoji. 这个方法将一个emoji CharSequence作为形参, 如果EmojiCompat能够检测和渲染这个emoji的话, 会返回true.

键盘也能够检测应用支持的EmojiCompat支持包的版本, 以决定在画板中渲染哪个emoji. 要想检测这个版本, 如果可以的话, 键盘需要检测下列keys是否存在于EditorInfo.extras:

  • EDITOR_INFO_METAVERSION_KEY: 如果这个键存在, 这个值表示了应用使用的emoji元数据的版本. 如果这个键不存在, 应用不会使用EmojiCompat.
  • EDITOR_INFO_REPLACE_ALL_KEY: 如果该键存在且设置为true, 这表示应用调用了setReplaceAll()方法.

在EditorInfo.extras中接收到键之后, 键盘能够使用hasEmojiGlyph()方法, 在这个方法里面, metadataVersion是键EDITOR_INFO_METAVERSION_KEY的值, 来检测应用是否能够渲染特定的emoji.

在自定义控件中使用EmojiCompat

在应用中, 你总是能够使用process()方法来预处理CharSequence并把它添加到任何能够渲染Spanned实例的控件中. 比如, TextView. 此外, EmojiCompat提供如下控件帮助类让你花费最小的代价就能使用emoji支持丰富自定义控件.

  • EmojiTextViewHelper
  • EmojiEditTextHelper

Sample TextView:

  1. public class MyTextView extends AppCompatTextView {
  2. ...
  3. public MyTextView(Context context) {
  4. super(context);
  5. init();
  6. }
  7. ...
  8. private void init() {
  9. getEmojiTextViewHelper().updateTransformationMethod();
  10. }
  11.  
  12. @Override
  13. public void setFilters(InputFilter[] filters) {
  14. super.setFilters(getEmojiTextViewHelper().getFilters(filters));
  15. }
  16.  
  17. @Override
  18. public void setAllCaps(boolean allCaps) {
  19. super.setAllCaps(allCaps);
  20. getEmojiTextViewHelper().setAllCaps(allCaps);
  21. }
  22.  
  23. private EmojiTextViewHelper getEmojiTextViewHelper() {
  24. ...
  25. }
  26. }

Sample EditText:

  1. public class MyEditText extends AppCompatEditText {
  2. ...
  3. public MyEditText(Context context) {
  4. super(context);
  5. init();
  6. }
  7. ...
  8. private void init() {
  9. super.setKeyListener(getEmojiEditTextHelper().getKeyListener(getKeyListener()));
  10. }
  11.  
  12. @Override
  13. public void setKeyListener(android.text.method.KeyListener keyListener) {
  14. super.setKeyListener(getEmojiEditTextHelper().getKeyListener(keyListener));
  15. }
  16.  
  17. @Override
  18. public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
  19. InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
  20. return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
  21. }
  22.  
  23. private EmojiEditTextHelper getEmojiEditTextHelper() {
  24. ...
  25. }
  26. }

QA:

  • 我该如何初始化字体下载?

如果Emoji字体在设备上并不存在, 那么在第一次请求的时候就会下载好. 下载调度对于应用是透明的.

  • 初始化花费多长时候?

在字体下载好之后, 初始化EmojiCompat大约花费150ms.

  • EmojiCompat支持包占用多大内存?

当前, 找到在应用内存中加载好的emoji并使用它的数据结构大约是200KB.

  • 自定义TextView可以使用EmojiCompat吗?

是的, EmojiCompat为自定义控件提供帮助类. 它也能够预处理给定字符串并将转换成Spanned.

  • 如果我在运行Android 4.4(API 19) - 的设备上, 布局文件中添加了控件, 会发生什么?

你能够在支持Android 4.4(API 19) - 的设备上引入EmojiCompat支持包或者它的控件. 然后, 如果设备运行的Android版本小于API 19, EmojiCompat和它的控件处理"no operation"状态. 这意味着EmojiTextView的行为就是一个常规的TextView. EmojiCompat实例, 在调用init()方法的时候, 马上就会进入LOAD_STATE_SUCCEED状态.

Android Emoji兼容包使用详解的更多相关文章

  1. 转:android Support 兼容包详解

    本文转自stormzhang的ANDROID SUPPORT兼容包详解 背景 来自于知乎上邀请回答的一个问题Android中AppCompat和Holo的一个问题?, 看来很多人还是对这些兼容包搞不清 ...

  2. android v7兼容包RecyclerView的使用(四)——点击事件的不同方式处理

    前三篇文章 android v7兼容包RecyclerView的使用(三)--布局管理器的使用 android v7兼容包RecyclerView的使用(二) android v7兼容包Recycle ...

  3. [Android新手区] SQLite 操作详解--SQL语法

    该文章完全摘自转自:北大青鸟[Android新手区] SQLite 操作详解--SQL语法  :http://home.bdqn.cn/thread-49363-1-1.html SQLite库可以解 ...

  4. Android中Service的使用详解和注意点(LocalService)

    Android中Service的使用详解和注意点(LocalService) 原文地址 开始,先稍稍讲一点android中Service的概念和用途吧~ Service分为本地服务(LocalServ ...

  5. 《Android群英传》读书笔记 (5) 第十一章 搭建云端服务器 + 第十二章 Android 5.X新特性详解 + 第十三章 Android实例提高

    第十一章 搭建云端服务器 该章主要介绍了移动后端服务的概念以及Bmob的使用,比较简单,所以略过不总结. 第十三章 Android实例提高 该章主要介绍了拼图游戏和2048的小项目实例,主要是代码,所 ...

  6. Android 之窗口小部件详解(三)  部分转载

    原文地址:http://blog.csdn.net/iefreer/article/details/4626274. (一) 应用程序窗口小部件App Widgets 应用程序窗口小部件(Widget ...

  7. Android高效率编码-第三方SDK详解系列(三)——JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送

    Android高效率编码-第三方SDK详解系列(三)--JPush推送牵扯出来的江湖恩怨,XMPP实现推送,自定义客户端推送 很久没有更新第三方SDK这个系列了,所以更新一下这几天工作中使用到的推送, ...

  8. 【Android 应用开发】Ubuntu 下 Android Studio 开发工具使用详解 (旧版本 | 仅作参考)

    . 基本上可以导入项目开始使用了 ... . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/21035637 ...

  9. Android高效率编码-第三方SDK详解系列(二)——Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能

    Android高效率编码-第三方SDK详解系列(二)--Bmob后端云开发,实现登录注册,更改资料,修改密码,邮箱验证,上传,下载,推送消息,缩略图加载等功能 我的本意是第二篇写Mob的shareSD ...

随机推荐

  1. docker 从本地拷贝文件

    1.找到docker的ID全称 docker inspect -f '{{.Id}}' docker_name 2.执行拷贝命令 docker cp 本地文件路径 ID全称:docker路径 3.如果 ...

  2. openstack系列文章(一)

    学习openstack的系列文章-虚拟化 虚拟化 KVM CPU 虚拟化 KVM 内存虚拟化 全虚拟化 I/O 设备 半虚拟化 I/O 设备 I/O PCI PCIe 设备直接分配 SR-IOV 在 ...

  3. 根据 WBS 列新 PID 数据

    之前写过关于 菜单树的. http://www.cnblogs.com/newsea/archive/2012/08/01/2618731.html 现在在写城市树. 结构: CREATE TABLE ...

  4. 关于React面试题汇总

    1.redux中间件 中间件提供第三方插件的模式,自定义拦截 action -> reducer 的过程.变为 action -> middlewares -> reducer .这 ...

  5. ubuntu16更新源

    http://blog.csdn.net/fengyuzhiren/article/details/54844870

  6. 【每日scrum】第一次冲刺day5

    请教以前做过类似软件的同学,受益匪浅,启发自己

  7. Java每日学习笔记1

    单选按钮 JRadioButton radioButton1 = new JRadioButton("Java");// 创建单选按钮 contentPane.add(radioB ...

  8. springboot maven

    更多信息请从官网获取https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE 1.parent基于自己项目而非spring-boot-starter- ...

  9. SpringMVC入门学习案例笔记

    一.数据库环境用mysql,数据库建表语句如下: /* SQLyog v10.2 MySQL - 5.1.72-community : Database - mybatis ************* ...

  10. Freemarker中Configuration的setClassForTemplateLoading方法参数问题

    今天使用freemarker中Configuration的setClassForTemplateLoading方法遇到了加载模板目录的一个小问题. 由于网上的其他论坛,博客写的有点乱,故记录一下. F ...