開發中,難免會遇到各種各樣的適配問題,尤其是經過深度修改定製過的系統,有的無論是軟硬體上都有很大的區別,這裡不得不提到一種奇葩的機型,沒錯,那就是雙卡雙待的手機(比如XT800, A60, S8600 , Lenovo A750,中興V889D等).由於是雙SIM卡,而且兩個卡槽支援的電訊廠商或者網路制式不一定相同,比如一個卡槽支援WCDMA,另一個卻只支援GSM ,導致用正常方法解析簡訊很容易遇到異常
想深入瞭解雙卡雙待手機簡訊發送與接收流程的話,請看我之前關於 MMS的分析:
Android 簡訊模組分析(四) MMS之簡訊的發送與接收
這裡先看下解決方案,這裡需要以反射的方式解析不同類型的簡訊,並且對於不同機型,需對應地進行調整適配:
擷取簡訊資訊,注意:為解決雙卡雙待手機解析簡訊異常問題,使用Java反射機制,優先解析GSM類型的簡訊,假如解析失敗才按CDMA類型的簡訊進行解析)
public static SmsMessage[] getSmsMessage(Intent intent) {SmsMessage[] msgs = null;Object messages[] = (Object[]) intent.getSerializableExtra(pdus);int len = 0;if (null != messages && (len = messages.length) > 0) {msgs = new SmsMessage[len];try {for (int i = 0; i < len; i++) {SmsMessage message = null;if (GSM.equals(intent.getStringExtra(from))) { // 適配MOTO XT800雙卡雙待手機message = createFromPduGsm((byte[]) messages[i]);} else if (CDMA.equals(intent.getStringExtra(from))) { // 適配MOTO XT800雙卡雙待手機message = createFromPduCdma((byte[]) messages[i]);} else {message = SmsMessage.createFromPdu((byte[]) messages[i]); // 系統預設的解析簡訊方式}if (null == message) { // 解決雙卡雙待類型手機解析簡訊異常問題message = createFromPduGsm((byte[]) messages[i]);if (null == message) {message = createFromPduCdma((byte[]) messages[i]);}}if (null != message) {msgs[i] = message;}}} catch (Exception e) {e.printStackTrace();msgs = getSmsMessageByReflect(intent); // 解決雙卡雙待手機解析簡訊異常問題} catch (Error er) {er.printStackTrace();msgs = getSmsMessageByReflect(intent); // 解決雙卡雙待手機解析簡訊異常問題}}return msgs;}
反射方式擷取簡訊
/** * 使用Java反射機制擷取簡訊資訊(解決雙卡雙待手機解析簡訊異常問題,優先解析GSM類型的簡訊,假如解析失敗才按CDMA類型的簡訊進行解析) * * @param intent * @return */private static SmsMessage[] getSmsMessageByReflect(Intent intent) {SmsMessage[] msgs = null;Object messages[] = (Object[]) intent.getSerializableExtra(pdus);int len = 0;if (null != messages && (len = messages.length) > 0) {msgs = new SmsMessage[len];try {for (int i = 0; i < len; i++) {SmsMessage message = createFromPduGsm((byte[]) messages[i]);if (null == message) {message = createFromPduCdma((byte[]) messages[i]);}if (null != message) {msgs[i] = message;}}} catch (SecurityException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();}}return msgs;}
通過Java反射機制解析GSM類型的簡訊:
private static SmsMessage createFromPduGsm(byte[] pdu) throws SecurityException, IllegalArgumentException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {return createFromPdu(pdu, com.android.internal.telephony.gsm.SmsMessage);}
解析CDMA類型的簡訊
private static SmsMessage createFromPduCdma(byte[] pdu) throws SecurityException, IllegalArgumentException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {return createFromPdu(pdu, com.android.internal.telephony.cdma.SmsMessage);}
解析GSM或者CDMA類型的簡訊
private static SmsMessage createFromPdu(byte[] pdu, String className) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException {Class clazz = Class.forName(className);Object object = clazz.getMethod(createFromPdu, byte[].class).invoke(clazz.newInstance(), pdu);if (null != object) {Constructor constructor = SmsMessage.class.getDeclaredConstructor(Class.forName(com.android.internal.telephony.SmsMessageBase));constructor.setAccessible(true);return (SmsMessage) constructor.newInstance(object);} else {return null;}}