andoid中存在的adb-server服务,可以在命令行使用android SDK中的ADB命令与android设备中的adb-server进行通信,当然前提是android设备要打开调试模式(Debug Mode)。大家应该知道一个问题就是,android基于Linux内核,其内部使用UTF-8编码,但是在非unicode编码的系统如windows中文版系统中大多使用的编码是GBK,即国标。于是在不经任何处理的非UTF-8编码环境下就会出现编码问题,android设备在处理的时候由于编码问题出现乱码或者根本无法执行。最直接的表现就是使用adb push中文或其他unicode编码的文件名时,出现Invalid argument错误。

以下使用windows 7 X86旗舰版和Ubuntu11.10 X86版分别介绍下产生这个问题的原因和解决方法。首先是windows,如下:

直接读返回的文本,会显示乱码。按照默认惯例,cmd中默认是GBK编码,而android为UTF-8编码,现在我们试着将乱码使用GBK还原,然后转换成UTF-8看看效果,如下:

上图为代码及执行结果,可以看出确实和之前预想的一样,至于有些转换之后还是乱码的问题。那是因为对于有些字符来说转换是不可逆的,因为并不是所有字符都在其他字符集存在,如上面文件名存在SHIT-JIS编码,即日文编码,其转换成GBK自然没有对应字符,这一步是不可逆的,也就是再转回UTF-8已经是不可能。接下来我们尽可能的使环境接近UTF-8.如下图:

如上图,使用chcp 65001命令将CMD默认编码改为UTF-8同时修改默认字体为Lucida Console,这时在使用adb命令即可显示UTF-8的文件名。但是此时输入和输出非常诡异。于是我想有没有什么单纯的在不使用任何工具的前提下在GBK环境支持UTF-8的命令,到目前为止没有找到这种方式,而改CMD编码这种事情没有实用价值。于是只有走编码一条路线了,其一是通过修改adb源代码,这个好像真的可以但是本人对C不熟于是跳过。接下来使用官方的ddmlib,我使用ddmlib发现问题很多于是升级了一下,之后我发现一个诡异的问题,那就是某天我用DDMS传一个有中文字符的文件,竟然成功了,于是我去看ddmuilib的代码。因为dmlib代码我都看过了,升级之后的ddmlib貌似改动较大的样子,我从ddmuilib到ddmlib看了几遍发现和我写的没什么区别。

但是有一点引起我的注意。就是旧版的ddmlib在用FileListingService遍历文件的时候发现出来是乱码,测试发现返回的是ISO8859-1编码,后来我手动转换成UTF-8,之后ddmlib升级后其返回的竟然直接是UTF-8编码。于是我又回去把新版的ddmlib源代码看一遍,看完后发现ddmlib改动确实挺大的,很多地方都比之前合理了许多,但是编码问题依旧很奇怪,不明白为什么这样做,但是已经发现问题所在。

如上图所示,我们比较一下ddmlib产生乱码和不会产生乱码的位置,上右二,类MultiLineReceiver,位置com.android.ddmlib.MultiLineReceiver。遍历文件是其直接子类:com.android.ddmlib.FileListingService#LsReceiver。可以看到在接收adb-server返回的时候直接硬编码为UTF-8,保证返回的是正确的UTF-8字符。而在文件同步类com.android.ddmlib.FileListingService中其使用com.android.ddmlib.AdbHelper中的编码,而这里编码默认为ISO98859-1。之后我改为UTF-8。好了,这里可以肯定adb无法上传unicode文件的原因。但是在动手修改之前,我们先换一个UTF-8环境下,在排除编码之后看看是什么效果。

如上图所示,环境ubuntu11.10 x86,不做任何设置,可以正确显示中文和其他unicode编码的文字,并在执行包含unicode字符的命令行也不会出现Invalid argumen错误。至此可以断定adb在windows中产生Invalid argumen的原因是默认编码问题。知道原因之后就动手修改ddmlib代码。在这里需要明白另外一个问题就是路径转义,比如空格这个字符。在命令行下空格会被当做区分参数的标识,所以每个空格钱都需要添加一个\斜杠转义。参见ddmlib的实现,使用正则匹配。Pattern.compile("([\\()*+?\"'#/\s])").matcher(value).replaceAll("\\$1"),将value中的每个空格前面添加一个转义符。

如上图,使用UTF-8重新编码的命令行原理很简单,将adb返回的字节流使用UTF-8编码为字符流,而不是使用是同的默认编码。然后是adb push 的问题

如上图,重编码之后使用adb push到sdcard的【蛇足】いろは唄【歌ってみた】.mp3。至此adb对unicode出现的问题已将完全解决。通过对ddmlib代码的分析,发现adb-server和之前自己的理解有较大的差别,当然这是之后的事情。另外,不要在再win7下随便使用chcp命令修改编码页(CodePage)。

就到这里。