在Android 2.3上通过短信发送时,为什么“@”被翻译为“¿”?

时间:2014-03-17 17:44:27

标签: android encoding sms

我正在开发一个Android应用程序,它通过短信向远程设备发送命令。这些命令都是常规文本消息,其中一些以前缀A@@开头。为了测试应用程序,我使用Android 4.3手机和Android 2.3手机向其他手机发送了一些“命令”。

当我在Android 4.3手机上运行该应用时,接收端的短信在任何设备上都显示正常,但如果我使用Android 2.3发送命令,则会在Android上发送A¿¿ 4.3手机,但在Android 2.3或iPhone上正常到达A@@。在目标设备(它使用GSM调制解调器)上,消息变为A(字符“A”加上两个空格 - ASCII 0x20),因此我怀疑发送方使用的是不同的编码。我觉得奇怪的是@符号甚至不是扩展的ASCII字符,所以我想知道为什么它会被编码在除ASCII之外的其他字符集中。

有人能解释这里发生了什么吗?如果Android 2.3设备真的使用其他编码,有没有办法在发送短信之前将其强制为ASCII?

发送代码如下:

@Override
public void sendCommand(String command) {
    //TODO: Send SMS with 'command' as its text message
    SmsManager sms=SmsManager.getDefault();
    PendingIntent piSent=PendingIntent.getBroadcast(this, 0,
                                       new Intent("SMS_SENT"), 0);
    PendingIntent piDelivered=PendingIntent.getBroadcast(this, 0,
                                            new Intent("SMS_DELIVERED"), 0);
    String phone = txtPhone.getText().toString();
    sms.sendTextMessage(phone, null, command, piSent, piDelivered);
}

参数command始终是前缀与其他文本的串联,如下所示:

String SmsPrefix = new String("A@@");
sendCommand(SmsPrefix + "AT+DEACT");

更新

我从某人那里得到了一个暗示,这个问题可能与运营商有关,而不是与Android系统本身有关。我住在巴西,我的Android 2.3设备正在使用运营商TIM,就像我们使用的iPhone一样。 Android 4.3设备使用的是运营商Claro。我发现,如果我拿到TIM SIM卡并将其放在Android 4.3设备上,则接收端也会显示乱码@,因此运营商TIM似乎正在搞乱通过他们的网络发送的短信。我将尝试下面的@PMunch的新建议,以便我们可以找到一种解决方法,但我们可以确定它已经不是从Android 2.3到4.3中纠正的某种错误。

1 个答案:

答案 0 :(得分:3)

真的好像是一个编码问题。可能是您尝试以ASCII格式发送,但接收方尝试以不同的编码方式对其进行解析。如果您在发送方和接收方端明确指定编码,它应该可以工作。

编辑:

这将获得字符数组,并使用US-ASCII编码从中创建一个字符串。

String newString = new String(oldString.getBytes("US-ASCII"), "US-ASCII"));

EDIT2:

原来GSM不使用常规的US-ASCII,而是使用它自己的GSM alphabet。似乎正在发生的事情是@(ASCII 0x40)被直接翻译成GSM字母表¡(颠倒的感叹号,GSM 0x40)。这不会影响常规文本字符,因为它们共享相同的地址(加号0x2B相同)。然后,当转换回来时,它试图将它所假设的GSM-alphabet转换为ASCII,这意味着早期@符号的0x40现在是一个颠倒的感叹号。这是常规ASCII中不存在的标志,因此被未知字符符号替换,显然是Android 2.3中的颠倒问号和GSM接收器中的空格。在Android 2.3和Android 4.3之间似乎已经修复了从ASCII到GSM的转换缺失。

如果您尝试使用new String ("A@@","ISO-8859-1")向Android指定这是一个ASCII字符串,则可以使用它自己进行转换。如果不是,你可能必须自己做(像this这样的东西可能有帮助)。如果@是您需要支持的唯一特殊字符,那么您当然可以自己编码该单个字符(\ 0 \ 0表示@@)。

EDIT3:

Edit2包含多项操作,您尝试了什么?解释整个GSM / ASCII的事情: ASCII使用前32个字符作为控制字符。 GSM认为这些字符是不必要的,因此它们被其他字符替换。用于终止字符串的计算机上的空字符不用于文本消息。它们设置为140个八位字节,任何空白空间都只填充填充字符。因此,ASCII中的空字符0x00用于其他内容,@字符。如果您查看GSM字母表和ASCII字母表,您会看到32个第一个字符被希腊字符和其他字符替换。如果你看其余的字符,他们大多在正确的位置,@字符是其中一个不是。例如,如果您尝试输入_,您应该会得到类似的结果。如果您说@ A {}出现A@@,那么A会变为AAA还是0x00 is NULL (when followed only by 0x00 up to the end of (fixed byte length) message, possibly also up to FORM FEED. But 0x00 is also the code for COMMERCIAL AT when some other character (CARRIAGE RETURN if nothing else) comes after the 0x00.?在查看Unicode公司提供的Unicode转换时,我也发现了一些有趣的东西:

A@@

因此,如果您尝试仅发送byte[] stringToGsm7BitPacked(String data) throws EncodeException,那么最后两个@s可能会被解释为填充字符而不是@字符。无论您所在地区的运营商是否在它们之间进行了一些转换,您是否尝试将带有sendDataMessage的字符作为原始数据字节发送?来自telephony.GsmAlphabet的函数{{1}}应该有助于将您的字符串转换为GSM字母表。