Introduction
由於 android 系統的碎片化,導致了最新的 emoji 在老的手機上不支援。
微信也做得不好,很多 emoji 表情直接變成了 X ,不知道什麼意思。
解鈴還須繫鈴人, Android 官方為此做了不少努力。
Android Official Solution
EmojiCompat 的方案包含如下兩種方式
- Downloadable fonts configuration (網路下載)
- Bundled fonts configuration (本地打包)把一個 7.4M 的 ttf 檔案塞進 apk 中
這兩種方式都有缺陷:
- 網路下載方式依賴於翻牆,門檻比較高
- 本地打包方式對 apk 的體積增大不可接受
有沒有一種方式既不用翻牆又不增大 apk 的體積呢?
答案是有的
Best Practice
無論是網路下載還是本地打包,都涉及到讀取 font 檔案進行渲染,那麼這裡有兩步
- 接管讀取的流程
- 接管渲染的流程
Hook Loading Process
首先,我們在 gradle 中匯入如下依賴
compile "com.android.support:support-emoji:$version"
compile "com.android.support:support-emoji-appcompat:$version"
compile "com.android.support:support-emoji-bundled:$version"
複製程式碼
這三個依賴所包含的東西不同
support-emoji
包含 EmojiCompat 方案所需要的基本實現以及 Downloadable fonts configuration 的程式碼support-emoji-appcompat
主要是針對 AppCompat 的 UI 元件的支援support-emoji-bundled
是 Bundled fonts configuration 的程式碼
然後根據官網解決方案,編譯打包成 apk 後,解壓 apk ,取出 NotoColorEmojiCompat.ttf 檔案(建議使用最新版本的 support 包) 放著備用,一會兒下鍋(寬油警告?),哦不,上傳到七牛或者其他雲端儲存
接下來就不需要 support-emoji-bundled
了,也不需要 support-emoji
,因為 support-emoji-appcompat
包含了
新建一個類
class DownloadEmojiCompatConfig : EmojiCompat.Config(DownloadMetadataLoader()) {
private class DownloadMetadataLoader internal constructor() : EmojiCompat.MetadataRepoLoader {
@RequiresApi(19)
override fun load(loaderCallback: EmojiCompat.MetadataRepoLoaderCallback) {
// 這裡只是關鍵部分,並不表示只有這一行
loaderCallback.onLoaded(MetadataRepo.create(Typeface.createFromFile(file.absolutePath), FileInputStream(file)))
}
}
}
複製程式碼
其中 file 就是我們下載好的 ttf 檔案
注意事項:
- 整個 EmojiCompat 只適用於 4.4 以上,再往下的就不支援了(也夠用了)
- 既然是想通過下載來解決本地安裝包增大的問題,那麼就好考慮好 wifi 4g 等情況了, 7M 流量呢
然後就是 EmojiCompat 自己的初始化流程了
EmojiCompat.init(
DownloadEmojiCompatConfig()
.setReplaceAll(false)
.registerInitCallback(object : EmojiCompat.InitCallback() {
override fun onInitialized() {
emojiReady = true
}
override fun onFailed(throwable: Throwable?) {
emojiReady = false
}
})
複製程式碼
注意事項:
- 放到其他執行緒來做,這個初始化時間至少 150ms
- 利用
InitCallback
回撥來處理 ready 狀態, ready 了後面渲染才可以用 - 小於 4.4 就不要初始化了
setReplaceAll
方法這裡重點說明下- true 表示所有的 emoji 都替換為 ttf 裡的,這樣可以保證 emoji 風格統一
- false 表示優先使用系統支援的 emoji ,不支援才用 ttf 裡的
此處使用 setReplaceAll(false)
是因為 ttf 裡的 emoji 在渲染國旗的時候會出現問題(也包括中國國旗)
到這裡,完成了 EmojiCompat 的 loading 流程
Hook Rendering Process
Activity 的 LayoutInflaterCompat.setFactory2 替換 xml 裡的 View
新寫 EmojiTextView
繼承 AppCompatTextView
@Override
public void setText(CharSequence text, BufferType type) {
if (emojiReady) {
super.setText(EmojiCompat.get().process(text), type);
return;
}
super.setText(text, type);
}
複製程式碼
而 EditText
就直接替換為 support-emoji-appcompat
裡的 EmojiAppCompatEditText
即可
到這裡,完成了 EmojiCompat 的 rendering 流程
事情到這裡就結束了麼?並沒有,因為新的 emoji 一直會出來,而 android 的 support 包並不會及時更新
那怎麼辦,有一個開源的組織叫 emojione 這裡 是它的官網
這個組織會發布自己的一套 emoji ttf 來相容各種裝置和統一不同風格的 emoji
也別高興得太早,上一次更新是 v3 版本,落後於 Android 提供的 support 包的版本(就是支援的 emoji 比官方少)
不過,最近,它出了 v4 了,可以期待下,但目前 ttf 版本還是 coming soon 狀態,可以訂閱下以便及時收到郵件提醒
Job Ad
歡迎正在刷 即刻app 的你加入我們,一起參與千萬級使用者產品的研發和運營!
當然也包括 Android 職位啦
工作地點:上海市楊浦區創智天地
簡歷請傳送至 hr@okjike.com 並在郵件標題中註明職位 + 姓名
一起打造明天的即刻 (^U^)ノ~YO