在android中用直接使用smsManager.sendTextMessage()方法发送中文或其它unicode字符会显示不正确。
目前来说想正确发送中文,需要自己构造PDU,然后在JAVA中用反射调用SmsManager的private sendRawPdu方法来实现。
参考:http://www.android123.com.cn/androidkaifa/180.html
上文中只说了PDU构造实现原理,具体怎么使用没有涉及。俺这再补一把,直接贴出代码。其实android本身SDK就有相应方法以UCS2编码发送,只是默认不会调用。
以下代码G1下测试通过
public class SmsHelper {
public static final int MAX_USER_DATA_BYTES = 140;
private Context mContext;
public SmsHelper(Context c) {
mContext = c;
}
public void sendUnicodeMessage(String phone, String text) {
SmsManager smsManager = SmsManager.getDefault();
Class clazz = smsManager.getClass();
try {
Class[] types = new Class[4];
types[0] = byte[].class;
types[1] = byte[].class;
types[2] = Class.forName("android.app.PendingIntent");
types[3] = Class.forName("android.app.PendingIntent");
Object[] params = new Object[4];
params[0] = null;
params[1] = getSubmitPdu(null, phone, text).encodedMessage;
params[2] = PendingIntent
.getBroadcast(mContext, 0, new Intent(), 0);
// params[2] = null;
params[3] = null;
Method m = clazz.getDeclaredMethod("sendRawPdu", types);
m.setAccessible(true);
m.invoke(smsManager, params);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
public static SubmitPdu getSubmitPdu(String scAddress,
String destinationAddress, String message) {
if (message == null || destinationAddress == null) {
return null;
}
SubmitPdu ret = new SubmitPdu();
byte mtiByte = (byte) (0x01 | 0x00);
ByteArrayOutputStream bo = getSubmitPduHead(scAddress,
destinationAddress, mtiByte, false, ret);
byte[] userData, textPart;
// Encoding to the 7-bit alphabet failed. Let's see if we can
// send it as a UCS-2 encoded message
try {
textPart = message.getBytes("utf-16be");
} catch (UnsupportedEncodingException uex) {
uex.printStackTrace();
return null;
}
userData = textPart;
if (userData.length > MAX_USER_DATA_BYTES) {
// Message too long
return null;
}
// TP-Data-Coding-Scheme
// Class 3, UCS-2 encoding, uncompressed
bo.write(0x0b);
// (no TP-Validity-Period)
// TP-UDL
bo.write(userData.length);
bo.write(userData, 0, userData.length);
ret.encodedMessage = bo.toByteArray();
return ret;
}
private static ByteArrayOutputStream getSubmitPduHead(String scAddress,
String destinationAddress, byte mtiByte,
boolean statusReportRequested, SubmitPdu ret) {
ByteArrayOutputStream bo = new ByteArrayOutputStream(
MAX_USER_DATA_BYTES + 40);
// SMSC address with length octet, or 0
if (scAddress == null) {
ret.encodedScAddress = null;
} else {
ret.encodedScAddress = PhoneNumberUtils
.networkPortionToCalledPartyBCDWithLength(scAddress);
}
// TP-Message-Type-Indicator (and friends)
if (statusReportRequested) {
// Set TP-Status-Report-Request bit.
mtiByte |= 0x20;
}
bo.write(mtiByte);
// space for TP-Message-Reference
bo.write(0);
byte[] daBytes;
daBytes = PhoneNumberUtils
.networkPortionToCalledPartyBCD(destinationAddress);
// destination address length in BCD digits, ignoring TON byte and pad
// TODO Should be better.
bo.write((daBytes.length - 1) * 2
- ((daBytes[daBytes.length - 1] & 0xf0) == 0xf0 ? 1 : 0));
// destination address
bo.write(daBytes, 0, daBytes.length);
// TP-Protocol-Identifier
bo.write(0);
return bo;
}
}