• Android Emoji兼容包使用详解


    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区域

     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的修改版本. 字体接如下规则修改:
    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, 添加如下依赖包.
     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 uD83DuDE10"); 

    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状态.

  • 相关阅读:
    NTDLL未文档化函数RtlGetNtVersionNumbers获取操作系统版本
    FormatMessage与GetLastError配合使用,排查windows api调用过程中的错误
    [翻译]:怎样从C/C++代码中对C#进行回调
    解决libcurl7.50.3在windows XP SP3 VC++ 6.0下编译报错 unresolved external symbol __imp__IdnToAscii@20 unresolved external symbol __imp__IdnToUnicode@20
    Windows XP SP3 VC6环境下成功编译openssl-0.9.8zh
    Windows XP SP3下编译安装openssl-1.1.0b
    Ubuntu关闭自动更新
    IDEA中分析JVM堆导出文件heapdump-1591244153347.hprof文件
    Linux环境下非root用户通过防火墙nat将端口转发到8080端口
    Linux自定义java程序运行脚本的命令
  • 原文地址:https://www.cnblogs.com/littlepanpc/p/9284619.html
Copyright © 2020-2023  润新知