Unified Emoji表情for Android


這個是我做Android以來碰到的最煩的東西,該死的emoji表情,恨之入骨。。無奈這個問題分配給我了。我也只能硬着頭皮做。

0.吐個槽先

首先,你要明白什么是emoji表情,不知道的google,不需要支持emoji的可以繞道了。

emoji有很多不同的版本,我tm最討厭的就是不同版本的了。Unified DoCoMo KDDI Softbank Google

因為ios5升級了,emoji編碼從softbank變成unified了。所以只能Android這邊改了。傷心。

我要做的工作就是把消息中含有的unified的emoji編碼過濾出來,然后映射出對應的表情資源顯示出來。

1.准備工作。

google下emoji表情的歷史,google code上有個源碼,不過是java的,那么你要把它改成java的。。(記得當初解析gif表情時也是把java改成android,可憐的我為咩總是干這活。。)

這里有個link,上面有所有的編碼對應轉換。Emoji for PHP

然后google code里有所有對應的編碼轉換的xml。叫emoji4unicode.xml. 這里是link: emoji4unicode

如果沒興趣我等下會直接貼代碼的,但是最好你先自己弄明白解析的原理是什么,emoji表情一直在增加,以后要兼容你就得自己想辦法了。

2.舉個例子

black sun with rays unified : U+2600 softbank: U+E04A

如果以前你解析過softbank,應該很熟悉了。好歹它還有個大致得順序,解析得時候只要判斷是否在這個unicode范圍內就可以了。so easy

可是unified完全是無順序得,所以必須得自己建好映射。

因為原始的emoji.xml很大,把所有的描述信息都放里面了,我不需要,所以我寫了個java把xml解析了一遍,然后重新生成了一個我需要的xml。貼個圖出來大家看下。

you see , 這個原始的xml實在太大了,有162K,而且還是xml解析。。你想想多耗內存和時間。所以必須把它再轉換一遍。

so 這個過程做好了,就可以進行下一步真正的解析了。。

3 解析過程。

因為emoji是有表情分組的,所以你要優先考慮解析出來的也是分好組的。

HashMap<String, ArrayList<String>> emoMap = new HashMap<String, ArrayList<String>>();

我是這么來分組的。

解析xml,然后把2600這樣的字符串轉換成unicode。這個很關鍵,映射對應不上肯定也解析不出來。要注意的一點是有的emoji是兩個unicode組成的  U+1F1F0 U+1F1F7  這樣。。所以么。又多了一個環節。

HashMap<List<Integer>, String> convertMap = new HashMap<List<Integer>, String>();

再定義一個map來存unicode和string字符的映射。

if (xmlpull.getName().equals("e")) {
fromAttr = xmlpull.nextText();
emos.add(fromAttr);
List<Integer> fromCodePoints =  new ArrayList<Integer>();
if (fromAttr.length() > 6) {
String[] froms = fromAttr.split("\\_");
for (String part : froms) {
fromCodePoints.add(Integer.parseInt(part, 16));
}
else {
fromCodePoints.add(Integer.parseInt(fromAttr, 16));
}
convertMap.put(fromCodePoints, fromAttr);
}

這樣就把整個解析都寫到內存里了。這個就做成單例咯,在程序一進來,application里初始化。

4,解析過程

這里我是把emoji表情解析出來,再改成[e]2600[/e]的形式。然后再用正則再解析一遍(為什么這樣做。。因為消息里面不可能只有emoji表情的啊親。。。你還要解析另外的表情。)

下面是過濾emoji表情的方法:

public String parseEmoji(String input) {
if (input ==  null || input.length() <= 0) {
return "";
}
StringBuilder result =  new StringBuilder();
int[] codePoints = toCodePointArray(input);
List<Integer> key =  null;
for ( int i = 0; i < codePoints.length; i++) {
key =  new ArrayList<Integer>()
if (i + 1 < codePoints.length) {
key.add(codePoints[i]);
key.add(codePoints[i + 1]);
if (convertMap.containsKey(key)) {
String value = convertMap.get(key);
if (value !=  null) {
result.append("[e]" + value + "[/e]");
}
i++;
continue;
}
}
key.clear();
key.add(codePoints[i]);
if (convertMap.containsKey(key)) {
String value = convertMap.get(key);
if (value !=  null) {
result.append("[e]" + value + "[/e]");
}
continue;
}
result.append(Character.toChars(codePoints[i]));
}
return result.toString();
}

看到這里,你可能覺得懵了。當時我也是卡了兩三天,不停的網上找資料,反編譯別人的代碼。最后才找的解決方案的,代碼其實沒有很多,最重要的是要怎么去思考。

4.渲染成圖片。

public  static SpannableStringBuilder convetToHtml(String content, Context mContext) {
String regex = "\\[e\\](.*?)\\[/e\\]";
Pattern pattern = Pattern.compile(regex);
String emo = "";
Resources resources = mContext.getResources();
String unicode = EmojiParser.getInstance(mContext).parseEmoji(content);
Matcher matcher = pattern.matcher(unicode);
SpannableStringBuilder sBuilder =  new SpannableStringBuilder(unicode);
Drawable drawable =  null;
ImageSpan span =  null;
while (matcher.find()) {
emo = matcher.group();
try {
int id = resources.getIdentifier(
"emoji_" + emo.substring(emo.indexOf("]") + 1, emo.lastIndexOf("[")),
"drawable", "package");
if (id != 0) {
drawable = resources.getDrawable(id);
drawable.setBounds(0, 0, 24, 24);
span =  new ImageSpan(drawable);
sBuilder.setSpan(span, matcher.start(), matcher.end(),
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
catch (Exception e) {
break;
}
}
return sBuilder;
}

好了,成功解析出來了。但是!!你得先把圖片弄到手啊,親。而且還要我這個格式得。

貼個圖

額,話說這個我也是寫了個java,把之前得softbank得命名轉換成unified的命名,當初我還准備一個一個手動改來着,還好我同事一語點醒夢中人額。。不然我估計就吐血身亡了。程序寫多了就是這樣,思維固定了。。。

5.發emoji消息。

既然能顯示了,你還得發啊,親。

直接貼代碼把,一個還原過程

public  static String convertToMsg(CharSequence cs, Context mContext) {
SpannableStringBuilder ssb =  new SpannableStringBuilder(cs);
ImageSpan[] spans = ssb.getSpans(0, cs.length(), ImageSpan. class);
for ( int i = 0; i < spans.length; i++) {
ImageSpan span = spans[i];
String c = span.getSource();
int a = ssb.getSpanStart(span);
int b = ssb.getSpanEnd(span);
if (c.contains("emoji")) {
ssb.replace(a, b, convertUnicode(c));
}
}
ssb.clearSpans();
return ssb.toString();
}
private  static String convertUnicode(String emo) {
emo = emo.substring(emo.indexOf("_") + 1);
if (emo.length() < 6) {
return  new String(Character.toChars(Integer.parseInt(emo, 16)));
}
String[] emos = emo.split("_");
char[] char0 = Character.toChars(Integer.parseInt(emos[0], 16));
char[] char1 = Character.toChars(Integer.parseInt(emos[1], 16));
char[] emoji =  new  char[char0.length + char1.length];
for ( int i = 0; i < char0.length; i++) {
emoji[i]  = char0[i];
}
for ( int i = char0.length; i < emoji.length; i++) {
emoji[i]  = char1[i - char0.length];
}
return  new String(emoji);
}

由於時間跨度比較長了。年初得時候寫得,基本都記不清了。所以盡量不要來問我額,親們,我只提供解決方案。

代碼我也會上傳一份,有需要得可以拿去耍。

源代碼:http://stay4it.com/course/20

個人辛苦勞動所得,請勿轉載~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM