絵文字サポートライブラリ EmojiCompat を味見

# 概要
【最終更新日】2017/07/03 (現在プレビュー版のため内容に変更があるかもしれません)

EmojiCompat サポートライブラリは古いバージョンの Android でも最新版の絵文字を表示できるようにする Google 製のライブラリです。

Android では OS のバージョンによって対応している絵文字が異なるため、OS が対応していない絵文字は □ のような文字 (Tofu) で表示されてしまいます。

EmojiCompat サポートライブラリを使用すると、ユーザーは Android OS のバージョンが古くても最新版の絵文字を見ることができます。

![.png](https://qiita-image-store.s3.amazonaws.com/0/189004/aaf47532-6bbd-74f4-48bd-7767997c35c7.png)

> Android Developers : Emoji Compatibility 
> https://developer.android.com/topic/libraries/support-library/preview/emoji-compat.html#using-widgets-with-appcompat

# おすすめ資料
▼ Androidエンジニアが抑えておくべき Unicode Emojiの知識 (DroidKaigi 2019)
(Youtube) https://www.youtube.com/watch?v=rsRnHCrWK8o
(スライド) https://speakerdeck.com/tacke_jp/unicode-emoji-for-android-engineer-droidkaigi09
「EmojiCompat で絵文字を変更できるのは分かったけど中では何をやっているの？」
「そもそも絵文字ってどうやって表現されてるの？」
上記の資料では絵文字の仕組みを理解することで EmojiCompat についての造詣が深まります。

# EmojiCompat
## サンプル
> GitHub : googlesamples/android-EmojiCompat
> https://github.com/googlesamples/android-EmojiCompat

## ライブラリの導入
EmojiCompat は Android 4.4 (API 19) 以上で動作します。

EmojiCompat の導入方法は2通りあります。

- Downloadable fonts
 
Android O および Android Support Library 26 で導入された "Downloadable Fonts" の機能を使い Google Play サービス経由で絵文字データをダウンロードしてアプリで使用する方法です。
アプリ内に絵文字データを含める必要がないため、apk のサイズを抑えることができます。

- Bundled fonts

アプリに絵文字データを含める方法です。
絵文字データの分、apk のサイズが大きくなります。
(備考: 自環境では apk のサイズが 7MB 増加しました。assets に NotoColorEmojiCompat.ttf が追加されるようです)
	
## Downloadable fonts
※ Android O プレビュー版必須だったためスキップ

> Android Developer : Emoji Compatibility - Downloadable fonts configuration
> https://developer.android.com/topic/libraries/support-library/preview/emoji-compat.html#downloadable-fonts
> 　
> Android Developer : Downloadable fonts
> https://developer.android.com/preview/features/downloadable-fonts.html

## Bundled fonts
Bundled 版のEmojiCompat サポートライブラリを追加します。

``` build.gradle
dependencies {
    ...
    compile "com.android.support:support-emoji-bundled:26.0.0-beta2"
}
```
アプリ開始時に `EmojiCompat` の初期化を行う必要があります。
サンプルでは `Application` を継承したクラスで `onCreate` が呼ばれたときに行っています。

`BundledEmojiCompatConfig` のインスタンスを引数として、`EmojiCompat.init(EmojiCompat.Config)` メソッドをコールすることで `EmojiCompat` の初期化が行われます。

``` MyApplication.java
public class MyApplication extends Application {
@Override
    public void onCreate() {
       super.onCreate();
       EmojiCompat.Config config = new BundledEmojiCompatConfig(this);
       EmojiCompat.init(config);
    }
}
```
EmojiCompatを通して最新版の絵文字を表示させたい View は EmojiCompat 専用の View を使用する必要があります。
TextView であれば `android.support.text.emoji.widget.EmojiTextView` を使用します。
その他に専用の EditText, Button も用意されています。

``` main_activity.xml
<android.support.text.emoji.widget.EmojiTextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
```

通常のTextViewと同じように `EmojiTextView.setText(CharSequence)` で文字列をセットできます。
未対応の絵文字がセットされた場合には、EmojiCompat を通して最新版の絵文字が表示されます。

例. 
Unicode 6.0 の絵文字まで対応している Android 5.1.1 で
Unicode 9.0 のキウイフルーツ (🥝: \ud83e\udd5d)
Unicode 10.0 のサンドイッチ (🥪: \ud83e\udd6a) を表示した場合

![sample.png](https://qiita-image-store.s3.amazonaws.com/0/189004/ee561df7-5d62-56d3-7c4e-60527c7b11da.png)

上. 通常版のTextView に上記2つをセットした場合
　Android 5.1.1では未対応の絵文字であるため Tofu が表示されてしまっている
下. EmojiTextView に上記2つをセットした場合
　2つの絵文字が正しく描画されている

## AppCompat 対応
AppCompat 版のライブラリもあります。

``` build.gradle
dependencies {
      compile "com.android.support:support-emoji-appcompat:26.0.0-beta2"
}
```

View は android.support.text.emoji.widget パッケージの EmojiAppCompatTextView などの AppCompat 対応版を使用します。

v7 appcompat library が元になっており、EmojiAppCompatTextView であれば android.support.v7.widget.AppCompatTextView を継承しています。

``` main_activity.xml
<android.support.text.emoji.widget.EmojiAppCompatTextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"/>
```

## 全ての絵文字を最新版に置き換えるかどうか
EmojiComapt.Config に対して setReplaceAll(boolean) で設定できる。
true にすると旧バージョンで使用可能な絵文字を最新バージョンの絵文字に置換する。
デフォルトはfalse。

``` MyApplication.java
public class MyApplication extends Application {

	@Override
	public void onCreate() {
		super.onCreate();

		EmojiCompat.Config config = new BundledEmojiCompatConfig(this);
		config.setReplaceAll(true);
		EmojiCompat.init(config);
	}
}
```

例. Android 5.1.1 での動作
![setReplaceAll(true).png](https://qiita-image-store.s3.amazonaws.com/0/189004/a3eff0ff-4f3f-9138-c56d-3101639b045f.png)

上. setReplaceAll(false) or 未設定 の場合
　旧バージョンの絵文字は最新版のものに置換されずにそのまま表示される。
下. setReplaceAll(true) の場合
　旧版の絵文字が最新の絵文字に置換されて表示される
　( 撮影時は Android 8.0 用の絵文字が最新 )

# 遭遇したエラー
## EmojiCompat.init() してない
	Caused by: java.lang.IllegalStateException: EmojiCompat is not initialized.
	Please call EmojiCompat.init() first
必ずアプリ開始時に `EmojiCompat.init()` しましょう。

## 絵文字をそのまま使用してエラー
`setText("🥝")` のように絵文字をそのまま使用することはできない。
`setText("\ud83e\udd5d")` のようにUTF-16の文字コードを使用する。

## Android Studio 2.x でのエラー
Android Studio 2.x でプロジェクトを作成した場合に発生したエラー群。
(ライブラリの読み込みのエラーについては Android Studio 3.0 でプロジェクトを作成した場合、下記エラー群は発生しないんじゃないかなと思います)

### ライブラリが読み込めない
サポートライブラリの仕様が変わったらしく、今まで Android SDK 経由でダウンロードしたライブラリを参照していた(と思われる)のを、maven 経由で参照する形式に変わったらしい。
下記のように build.gradle ファイルを変更する。

``` build.gradle
repositories{
    maven{
        url"https://maven.google.com"
    }
}

dependencies{
    ...
    compile'com.android.support:support-emoji:26.0.0-beta2'
    ...
}
```

### ビルドするとエラー

	Error:Error converting bytecode to dex:
	Cause: Dex cannot parse version 52 byte code.
	This is caused by library dependencies that have been compiled using Java 8 or above.
	If you are using the 'java' gradle plugin in a library submodule add 
	targetCompatibility = '1.7'
	sourceCompatibility = '1.7'
	to that submodule's build.gradle file.

説明文を読むにライブラリが Java 8 以上で作成されているために発生しているエラーと思われる。なのでプロジェクト自体をJava 8でビルドするように下記を追加した。

	android{
	    ....
	    compileOptions{
	        sourceCompatibilityJavaVersion.VERSION_1_8
	        targetCompatibilityJavaVersion.VERSION_1_8
	    }
	}

にしたが再度エラー。

	Error:Jack is required to support java 8 language features.
	Either enable Jack or remove sourceCompatibility JavaVersion.VERSION_1_8.

Android Developer : Java 8 の言語機能を使う
https://developer.android.com/guide/platform/j8-jack.html?hl=ja
を参考に、Jackを有効にするとビルドが通るようになった。

``` build.gradle
android {
  ...
  defaultConfig {
    ...
    jackOptions {
      enabled true
    }
  }
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}
```

# Android バージョンと絵文字の歴史
http://emojipedia.org/google/android-4.3/ 
https://en.wikipedia.org/wiki/Android_version_history
などを参照しました。
Android バージョンによって使用可能な絵文字、実際に表示される絵文字が異なります。

|Version|変更履歴|更新日|絵文字数|
|:-:|:--|:-:|:-:|
|[4.1-4.3](https://emojipedia.org/google/android-4.3/)|Unicode 6.0 の絵文字に対応<br>モノトーン調の絵文字|2012/7/9|717|
|[4.4](https://emojipedia.org/google/android-4.4/)|絵文字がカラーに変更|2013/10/31|850|
|[5.0](https://emojipedia.org/google/android-5.0/)|・肌色問題などで人に関する絵文字が黄色のスライムみたいなキャラクターに変更された<br>・その他、国旗の絵文字などが追加|2014/11/3|1090|
|[6.0.1](https://emojipedia.org/google/android-6.0.1/)|・Unicode 7.0 と 8.0 の絵文字に対応|2015/12/7|1294|
|[7.0](https://emojipedia.org/google/android-7.0/)|・Unicode 9.0 の絵文字に対応<br>・人に関連する絵文字について、スキントーン(肌色)の変更と男女の変更に対応|2016/8/22|1796|
|[7.1.1](https://emojipedia.org/google/android-7.1/)|・人に関連する絵文字について、男女いずれかしかなかった絵文字などを男女両方対応するように変更|2016/10/20|2379|
|[8.0](https://emojipedia.org/google/android-8.0/)|・絵文字の規格をGoogle独自のものからUnicodeが制定した [Emoji 5.0 ](https://emojipedia.org/emoji-5.0/)に変更したためデザインが大幅刷新<br>・Emoji 5.0 対応により Unicode 10.0 の絵文字に対応|2017/8/21|2669|
|[8.1](https://emojipedia.org/google/android-8.1/)|・[ハンバーガーとビールと穴あきチーズの絵文字が修正](https://blog.emojipedia.org/google-fixes-burger-emoji/)|2017/12/5|2669|
|[9.0](https://emojipedia.org/google/android-9.0/)|・[Emoji 11.0](https://emojipedia.org/emoji-11.0/) に対応<br>・[ピストルがおもちゃに、サラダから卵がなくなり、ジェンダーレスに考慮、など色々変更](https://blog.emojipedia.org/android-9-0-emoji-changelog/)|2018/8/6|2820|