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支持包, 必要要修改开发环境的应用工程路径依赖.
要在应用中添加支持包, 需要:
- 打开应用build.gradle文件.
- 将依赖包添加到dependencies区域
1 dependencies { 2 ... 3 compile "com.android.support:support-emoji:27.1.1" 4 }
初始化可下载字体配置
你需要初始化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的修改版本. 字体接如下规则修改:
- 要提供向后兼容性来渲染emoji, 所有的emoji字符用单个Unicode码点表示, 这个码点位于Unicode Supplement Private Use Area-A, 从U+F001开始的
- 额外的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, 添加如下依赖包.
1 dependencies { 2 compile "com.android.support:support-emoji-appcompat:$version" 3 }
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支持包的绑定字体配置, 你必须修改开发环境中应用工程的类路径依赖.
1 dependencies { 2 ... 3 compile "com.android.support:support-emoji-bundled:$version" 4 }
使用绑定字体配置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对象. 通过这个方法, 你能够处理和缓存已处理实例, 而不是原生字符串, 由此提供了应用的性能.
1 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状态.
谢谢打赏!
您的支持就是我的最大动力!
支付宝
微信
Just remember: Half is worse than none at all.
本文是由SilentKnight诚意发布, 欢迎转载! 但转载请注明出处: 【SilentKnight】
如果觉得还有帮助的话,可以点一下右下角的【推荐】,希望能够持续的为大家带来更好的技术文章!
想跟我一起进步么?那就【关注】我吧