极光征文 | 如何实现Emoji表情的推送😆

0.518字数 1202阅读 1400

在开发中难免有些奇葩的需求。正常使用极光推送的都知道,是通过后端直接推字符串,或者json数据

首先在推送前要和后端约定好。
比如以这个表情为例
😀
数据格式1:(UTF-8编码)

{
"emoji":"表情推送\uD83D\uDE00"
}

数据格式2:

{
"emoji":"表情推送😀"
}

首先说一个场景:
A.用户输入一个带😆表情,然后提交给服务端,注意,这时候服务端收到的不一定是😆,而是被编码后的\uD83D\uDE00,这是个UFT-8编码。
如果这时候服务端需要将这个带😆的表情再转发给用户B,那么B收到的也是\uD83D\uDE00

用极光推送测试情况1


用极光推送测试情况2(这里在指不通过服务端,直接在极光的后台操作)

针对这种推送,到达手机的显示也是UTF-8编码过的,如果想要在手机正常显示表情,需要对字符串解析,以安卓为例使用Gson


    public class EmojiBean {
        String emoji;

        public EmojiBean(String emoji) {
            this.emoji = emoji;
        }

        @Override
        public String toString() {
            return "EmojiBean{" +
                    "emoji='" + emoji + '\'' +
                    '}';
        }
    }

EmojiBean s = new Gson().fromJson(message, EmojiBean.class);
LogUtils.e("解析:"+s.toString());

解析完成把setText字符串,就能显示表情了

注意这里控制台打印的log是无法识别的字符

E/Tag[TAG] LogUtils[e, 231]: 解析:EmojiBean{emoji='表情推送��'}

最后在手机上显示是这样的


在这个时候直接使用通知栏推送utf-8编码过的表情显然就不行了
然后想象是否可以同过通知栏入手,在接收到系统通知的时候先对消息做序列化处理,处理后再提醒,于是查阅极光的推送文档发现了这个

通知栏样式定义不符合要求?
以上提供的自定义通知栏样式的功能是有限的。比如:Android SDK 4.0 以后的 Notification 支持指定 Style ,而这种复杂的通知样式定义 JPush SDK 还未有支持。
或者你想要自定义的复杂的通知样式,但不愿意使用上述高级的自定义通知栏定制功能。
建议不要使用 JPush 提供的通知功能,而使用自定义消息功能。
即:推送自定义消息到客户端后,App 取到自定义消息全部内容,然后 App 自己来写代码做通知的展示。请参考文档:通知 vs. 自定义消息

文档也说了,建议我们使用自定义消息,但是如果使用极光的自定义消息,通知栏是没有提示,这里还需要我们自定义通知栏。

所以为了兼容这种奇葩的推送内容,就只能采用自定消息+自定义通知栏的方式了。

以Android为例:
1、服务端要通过极光发送带表情的推送,则在服务端将表情转成utf-8编码,或者用户在提交的表情到服务端的时候本地对带表情的字符串做反序列化操作

String strEmoji = "😆";
String strPush = new Gson().toJson(new EmojiBean(strEmoji));
//转换后的结果
{
"emoji":"\uD83D\uDE00"
}

2、如果服务端拿到了编码后的表情,想推送给其它用户怎么办?

那就需要推送一条自定义消息了,注意一定要是自定义消息。普通消息会直接在通知栏显示,对未序列化过的例如\uD83D\uDE00,通知栏所出现的还是原编码后的消息。

如果要在客户端显示就必须在自定义消息中手动进行序列化处理。

 private void customMessage(Context context, String msg) {
        String message = "{\n" +
                "\"emoji\":\"" +
                msg +
                "\"}";
        
        LogUtils.e(message);
        EmojiBean s = new Gson().fromJson(message, EmojiBean.class);
        //发送到通知栏
        NotificationCompat.Builder mBuilder =
                new NotificationCompat.Builder(context)
                        .setSmallIcon(R.mipmap.ic_launcher)
                        .setContentTitle(s.getEmoji())
                        .setContentText(s.getEmoji());

        Notification notification = mBuilder.build();
        NotificationManager mNotifyMgr =
                (NotificationManager) context.getSystemService(NOTIFICATION_SERVICE);
        mNotifyMgr.notify(1, notification);
}

这样做虽然麻烦了点,但是能避免客户端收到一些乱码。

还有一种情况是,服务端返回给极光推送是 😆 ,但是通过极光转发后就变成了 �� 这样的非法字符,所以针对这种情况建议服务端给提供编码后的utf-8字符,不要直接丢表情过来。

更高级的,还可以对通知栏自定义,推送图片URL等。

再补充一点,如果在用户编辑输入框的时候,不想让他输入 emoji 表情,那么就要通过正则取匹配 emoji 的字符集,如果查到了说明是 emoji 表情,可以给提示禁止输入非法字符等

Pattern emoji = Pattern.compile("[\ud83c\udc00-\ud83c\udfff]|[\ud83d\udc00-\ud83d\udfff]|[\u2600-\u27ff]",
            Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE);
      //动态监听输入内容
      Matcher emojiMatcher = emoji.matcher(source);
            if (emojiMatcher.find()) {
                ToastUtils.showShort("亲,此处不可以输入表情哦~");
                return "";
            }

源码:
MyReceiver.java

另外
关于推送你还可能想要了解的:

在BroadcastReceiver中利用推送设置全局弹窗,并将消息保存至本地
Android利用极光推送获取到消息并缓存至本地
关于JPush极光推送的基本用法和通知介绍


「本文为极光征文参赛文章」

推荐阅读更多精彩内容