since.2006  

在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;
 }

}
Posted by hee at 21:12 PM | Permalink | 评论(3)