热门标签 | HotTags
当前位置:  开发笔记 > Android > 正文

Emoji表情在AndroidJNI中的兼容性问题详解

这篇文章主要给大家介绍了关于Emoji表情在AndroidJNI中的兼容性问题,文中通过示例代码介绍的非常详细,对大家学习或者使用AndroidJNI具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧

起因

最近遇到一个问题,把某个字符串计算MD5,之后把该字符串加密与MD5一起上传到服务端,服务端解密后重新计算md5发现与上传的MD5不一致,而出问题的字符串中无一例外都有Emoji表情。但我自己弄个带表情的字符串上传却没有什么问题。

最终确认这是在Android 5.1以下 jstring -> char数组 时出的问题。下面通过一个示例来还原这个过程。

事件还原

假设有一个字符串s,String s = "\uD83D\uDC8B"; ,对应表情💋。通过调用getBytes()方法,会看到对应的byte数组为[-16, -97, -110, -117] ,按16进制输出为[f0, 9f, 92, 8b]

定义一个参数为String的native方法,public native String test(String str); ,在对应的C/C++代码中,通过env->GetStringUTFChars获取传入的String对应的char数组,把char数组的每一个元素按16进制输出。

在Android 7.1.2的测试机上,native层输出的结果为[f0, 9f, 92, 8b] ,与Java的byte数组是一样的,但是在Android 4.4.4的测试机上,输出结果为[ed, a0, bd, ed, b2, 8b] 。从而导致加密后的结果不一样。

服务端收到旧版Android的数据解密后得到[ed, a0, bd, ed, b2, 8b] ,计算MD5自然无法与[f0, 9f, 92, 8b]计算MD5一样。

Unicode、UTF-8、UTF-16

可能有人不是很清楚上面那2种byte数组是怎么来的。首先我们要知道,UTF-8和UTF-16都是Unicode的实现。\uD83D\uDC8B其实是UTF-16大端的表现形式,对于大于0xFFFF(0x10000~0x10FFFF)的Unicode,转换为UTF-16的步骤如下:

  1. 将Unicode减去0x10000,结果将是一个长度为20bit的值。
  2. 将第一步的20bit的高10bit与0xD800进行或运算,得到UTF-16的高位代理。
  3. 将第一步的20bit的低10bit与0xDC00进行或运算,得到UTF-16的低位代理。
  4. 高位代理+低位代理即Unicode对应的UTF-16的大端形式。

按照这个步骤反推:

  1. \uD83D\uDC8B的二进制位1101 1000 0011 1101 1101 1100 1000 1011,则高位代理为1101 1000 0011 1101,低位代理为1101 1100 1000 1011。
  2. 高位代理由高10bit与0xD800进行或运算得到,因此高10bit为00 0011 1101。
  3. 低位代理由低10bit与0xDC00进行或运算得到,因此低10bit为00 1000 1011。
  4. 所有20bit的值为0000 1111 0100 1000 1011。
  5. 加上0x10000,为0001 1111 0100 1000 1011,即0x1F48B。

所以,表情💋对应的Unicode为0x1F48B。


UTF-8的规则是,对于占N个字节的符号(N>1),第一个字节前N位都是1,N+1位是0,后面的字节前2位为10,然后把Unicode的二进制位填入空缺的二进制位中,空出的位置补0。因此,上面的Unicode 0x1F48B转为UTF-8需要占4个字节,为:

11110 000
10 011111
10 010010
10 001011

即0xF09F928B,这也就是[f0, 9f, 92, 8b]这个byte数组的由来。


那么[ed, a0, bd, ed, b2, 8b]这个byte数组又是怎么来的呢?这是把\uD83D\uDC8B当成2个单独的字符处理了,按照上面Unicode转UTF-8的逻辑,Unicode 0xD83D转为UTF-8为1110 1101 10 100000 10 111101,即0xEDA0BD,Unicode 0xDC8B转为UTF-8为1110 1101 10 110010 10 001011,即0xEDB28B。


总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。


推荐阅读
  • Android性能优化检测App卡顿
    在移动APP性能评测-流畅度评测中,我们介绍了如何准确客观评价APP的流畅度,最终采用SM指标来评价应用的流畅度,在知道如何评价流畅度之后 ... [详细]
  • 自定义RecyclerView添加EmptyView
    你知道RecyclerView里没有Em ... [详细]
  • spotify engineering culture part 1
    原文,因为原视频说的太快太长,又没有字幕,于是借助youtube,把原文听&打出来了。中文版日后有时间再翻译。oneofthebigsucceessfactorshereatSpo ... [详细]
  • MyBatis模糊查询和多条件查询一、ISmbmsUserDao层根据姓名模糊查询publicListgetUser();多条件查询publicList ... [详细]
  • 载波|等份_NR SRS时频域位置
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了NRSRS时频域位置相关的知识,希望对你有一定的参考价值。微信同步更新欢迎关注同名modem协议笔记S ... [详细]
  • Mac下Flutter安装AndroidStudio配置
    补一个Mac下Flutter安装AndroidStudio配置(官网地址:https:flutter.devdocsget-startedinstallmacos)1.下载安装包; ... [详细]
  • vscode里的html标签导航的一系列问题
    哈喽,我今天带来的经验是,vscode在18年10月更新后的1.29以后,编辑html文档时,会发现最上面有个类似于HTML标签导航的玩意儿,可能部分同学和我一样不习惯用它们,现在 ... [详细]
  • Android Rxbus事件总线
    我的视频课程:《FFmpeg打造Android万能音频播放器》最近在项目中使用了Rxjava和RxAndroid,确实感觉挺不错的,然后听说可以用RxBus来替换 ... [详细]
  • Illustrator绘制逼真的愤怒的小鸟实例教程
    Illustrator教程: ... [详细]
  • Android 自定义控件基础 canvas paint
    1、首先说一下canvas类:ClassOverviewTheCanvasclassholdsthedrawcalls.Todrawsomething,youne ... [详细]
  • 抓取百万知乎用户设计之实体设计
    一.实体的关系实体是根据返回的Json数据来设计的教育经历方面用户可以有很多教育经理,USER和education是一对多的关系,一个education对应一个education一 ... [详细]
  • iOS之富文本
    之前做项目时遇到一个问题:使用UITextView显示一段电影的简介,由于字数比较多,所以字体设置的很小,行间距和段间距也很小,一大段文字挤在一起看起来很别扭,想要把行间距调大,结 ... [详细]
  • Xib九宫格应用管理使用xib封装一个自定义view的步骤1新建一个继承UIView的自定义view,假设类名叫做(AppView)2新建一个AppView.xib文件来描述 ... [详细]
  • 【自制小工具】代码生成器
    【自制小工具】代码生成器陆陆续续接触过好几款代码生成工具,发现确实好用,但都会有那么点不完善的地方,所以索性就自己做一个吧。界面非常简单,反正是自己用的,简单点用起来也方便上图:左 ... [详细]
  • kepserver中文手册,kepserver使用教程,kepserver设置
    下面介绍一下KepServer模拟器的使用,以下示例使用服务器随附的Simulator驱动程序来演示创建、配置和运行项目的过程。Simulator驱动程序是基于内存的驱动程序,能为 ... [详细]
author-avatar
拉着潜艇的鱼_396
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有