问题
I'm developing an Android application which sends commands to a remote equipment through SMS. The commands are all regular text messages, and some of them start with the prefix A@@
. To test the app I sent some "commands" to other phones using an Android 4.3 phone and also an Android 2.3 phone.
When I run the app on the Android 4.3 phone, the SMS on the receiving end shows just fine on any device, but if I use the Android 2.3 to send the commands they get received as A¿¿
on an Android 4.3 phone but arrive as normally as A@@
either on an Android 2.3 or an iPhone. On the target equipment (it uses a GSM modem) the message gets like A
(character "A" plus two spaces - ASCII 0x20), so I suspect the sender is using a different encoding. What I find strange is the @
symbol is not even an extended ASCII char, so I'm wondering why it would be encoded in some other charset than ASCII anyway.
Can anyone explain what is happening here? If the Android 2.3 device is really using another encoding, is there a way to force it to ASCII before sending the SMS?
The sending code is as follows:
@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);
}
Where the parameter command
is always the concatenation of the prefix with some other text, like this:
String SmsPrefix = new String("A@@");
sendCommand(SmsPrefix + "AT+DEACT");
UPDATE:
I had a hint from someone that problem might be related to the carrier, not to the Android system itself. I live in Brazil and my Android 2.3 device was using the carrier TIM
, just the same as the iPhone we used. The Android 4.3 device was using the carrier Claro
. What I found is that, if I get the TIM
SIM card and put it on the Android 4.3 device the receiving end also shows the garbled @
, so it seems the carrier TIM
is messing up the SMS sent through their network. I will try the new suggestions from @PMunch below so we can possibly find a workaround, but we can be sure already it wasn't really some kind of bug corrected from Android 2.3 to 4.3.
回答1:
Really seems like an encoding issue. It might be that you try to send as ASCII but the receiver tries to parse it in a different encoding. If you explicitly specify encoding on both sender and receiver end it should work.
EDIT:
This would get the character array and create a string from it all using US-ASCII encoding.
String newString = new String(oldString.getBytes("US-ASCII"), "US-ASCII"));
EDIT2:
Turns out GSM doesn't use regular US-ASCII, rather it uses it's own GSM alphabet. What seems to be happening is that the @ (ASCII 0x40) is translated into the GSM alphabet directly as ¡ (Upside down exlamation mark, GSM 0x40). This won't affect regular text characters as they share the same addresses (same for the plus sign 0x2B). Then when converted back it tries to convert it frow what it assumes is GSM-alphabet to ASCII, meaning the 0x40 of the earlier @ sign is now an upside down exclamation mark. This is a sign that does not exist in regular ASCII and is therefore replaced by an unknown character symbol, apparently an upside down question mark in Android 2.3 and a space in the GSM receiver. This lack of conversion from ASCII to GSM seems to have been fixed between Android 2.3 and Android 4.3.
If you try to specify to Android that this is an ASCII string by using new String ("A@@","ISO-8859-1")
it might do the conversion in it's own. If not you might have to do it yourself (Something like this might help). If @ is the only special character you need to support then you could of course encode that single character yourself(\0\0 for @@).
EDIT3:
Edit2 included multiple actions, what did you try? To explain the whole GSM/ASCII thing:
ASCII uses it's first 32 characters as control characters. These characters were deemed unnecessary for GSM and so they were replaced with other characters. The null character, on computers used to terminate a string, is not used for text messages. They are set at 140 octets and any empty space is simply filled with filler characters. So the null character 0x00 in ASCII is used for something else, the @
character. If you look at the GSM alphabet and the ASCII alphabet you will see that the 32 first characters are replaced by Greek characters and some others. If you look at the remaining characters they are mostly in the right place, the @ character is one of the ones that aren't. If you for example try to type in _
you should get similar results. When you say that @
comes out as A
do you then mean that A@@
becomes A
or that it becomes AAA
? I also found something interesting while looking through Unicode conversion supplied by Unicode Inc.:
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.
So if you tried to send only A@@
then the two last @s might be interpreted as padding characters instead of @ characters. Regardless it seems like the carriers in your area does some conversion between them, have you tried to send the characters with sendDataMessage as raw data bytes? The function byte[] stringToGsm7BitPacked(String data) throws EncodeException
from telephony.GsmAlphabet should help convert your string to the GSM alphabet.
来源:https://stackoverflow.com/questions/22461516/why-is-a-being-translated-to-when-sent-through-sms-on-android-2-3