2014-12-08 105 views
17

我正在使用短信管理器發送短信。對於單卡,它的作品完全可以發送短信。但在雙卡上,短信不會發送。如果可能,我可以如何選擇雙卡發送短信哪個SIM卡發送短信。任何人都知道可以幫我解決這個問題。如何使用雙SIM卡手機中的SMSmanager發送短信?

單SIM工作守則

SmsManager smsManager = SmsManager.getDefault(); 
smsManager.sendTextMessage(ph_number, null, body, null,null); 
+0

這可能是你正在尋找的東西http://stackoverflow.com/questions/24007885/how-can-send-sms-in-android-in-dual-sim-with-set-default-sim – QAMAR 2014-12-08 05:44:55

+0

5月你會在這裏找到解決方案。 http://stackoverflow.com/questions/14276328/sms-manager-for-dual-sim-phones – 2014-12-08 05:46:57

+0

@MurtazaHussain我想在編碼本身做所有事情。這是可能的。 – Yugesh 2014-12-08 06:00:40

回答

36

我用這樣的方式來管理其SIM用於發送短信,甚至長的消息。它的工作我的雙卡雙待手機聯想A319(4.4.3)上,不需要根。它建立在反思之上。

import android.app.PendingIntent; 
import android.content.Context; 
import android.os.Build; 
import android.os.IBinder; 
import android.util.Log; 

import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.util.ArrayList; 
import java.util.List; 

/** 
* Created by Apipas on 6/4/15. 
*/ 
public class SimUtil { 

    public static boolean sendSMS(Context ctx, int simID, String toNum, String centerNum, String smsText, PendingIntent sentIntent, PendingIntent deliveryIntent) { 
     String name; 

     try { 
      if (simID == 0) { 
       name = "isms"; 
       // for model : "Philips T939" name = "isms0" 
      } else if (simID == 1) { 
       name = "isms2"; 
      } else { 
       throw new Exception("can not get service which for sim '" + simID + "', only 0,1 accepted as values"); 
      } 
      Method method = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", String.class); 
      method.setAccessible(true); 
      Object param = method.invoke(null, name); 

      method = Class.forName("com.android.internal.telephony.ISms$Stub").getDeclaredMethod("asInterface", IBinder.class); 
      method.setAccessible(true); 
      Object stubObj = method.invoke(null, param); 
      if (Build.VERSION.SDK_INT < 18) { 
       method = stubObj.getClass().getMethod("sendText", String.class, String.class, String.class, PendingIntent.class, PendingIntent.class); 
       method.invoke(stubObj, toNum, centerNum, smsText, sentIntent, deliveryIntent); 
      } else { 
       method = stubObj.getClass().getMethod("sendText", String.class, String.class, String.class, String.class, PendingIntent.class, PendingIntent.class); 
       method.invoke(stubObj, ctx.getPackageName(), toNum, centerNum, smsText, sentIntent, deliveryIntent); 
      } 

      return true; 
     } catch (ClassNotFoundException e) { 
      Log.e("apipas", "ClassNotFoundException:" + e.getMessage()); 
     } catch (NoSuchMethodException e) { 
      Log.e("apipas", "NoSuchMethodException:" + e.getMessage()); 
     } catch (InvocationTargetException e) { 
      Log.e("apipas", "InvocationTargetException:" + e.getMessage()); 
     } catch (IllegalAccessException e) { 
      Log.e("apipas", "IllegalAccessException:" + e.getMessage()); 
     } catch (Exception e) { 
      Log.e("apipas", "Exception:" + e.getMessage()); 
     } 
     return false; 
    } 


    public static boolean sendMultipartTextSMS(Context ctx, int simID, String toNum, String centerNum, ArrayList<String> smsTextlist, ArrayList<PendingIntent> sentIntentList, ArrayList<PendingIntent> deliveryIntentList) { 
     String name; 
     try { 
      if (simID == 0) { 
       name = "isms"; 
       // for model : "Philips T939" name = "isms0" 
      } else if (simID == 1) { 
       name = "isms2"; 
      } else { 
       throw new Exception("can not get service which for sim '" + simID + "', only 0,1 accepted as values"); 
      } 
      Method method = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", String.class); 
      method.setAccessible(true); 
      Object param = method.invoke(null, name); 

      method = Class.forName("com.android.internal.telephony.ISms$Stub").getDeclaredMethod("asInterface", IBinder.class); 
      method.setAccessible(true); 
      Object stubObj = method.invoke(null, param); 
      if (Build.VERSION.SDK_INT < 18) { 
       method = stubObj.getClass().getMethod("sendMultipartText", String.class, String.class, List.class, List.class, List.class); 
       method.invoke(stubObj, toNum, centerNum, smsTextlist, sentIntentList, deliveryIntentList); 
      } else { 
       method = stubObj.getClass().getMethod("sendMultipartText", String.class, String.class, String.class, List.class, List.class, List.class); 
       method.invoke(stubObj, ctx.getPackageName(), toNum, centerNum, smsTextlist, sentIntentList, deliveryIntentList); 
      } 
      return true; 
     } catch (ClassNotFoundException e) { 
      Log.e("apipas", "ClassNotFoundException:" + e.getMessage()); 
     } catch (NoSuchMethodException e) { 
      Log.e("apipas", "NoSuchMethodException:" + e.getMessage()); 
     } catch (InvocationTargetException e) { 
      Log.e("apipas", "InvocationTargetException:" + e.getMessage()); 
     } catch (IllegalAccessException e) { 
      Log.e("apipas", "IllegalAccessException:" + e.getMessage()); 
     } catch (Exception e) { 
      Log.e("apipas", "Exception:" + e.getMessage()); 
     } 
     return false; 
    } 


} 

添加權限:

<uses-permission android:name="android.permission.SEND_SMS"/> 

然後就這樣調用:)

要使用(血腥)靜態方法SIM1:

SimUtil.sendSMS(this,0,"00970XXXXXXXXX",null,"Hi Stackoverflow! its me Maher. Sent by sim1",null,null); 

要使用SIM2:

SimUtil.sendSMS(this,1,"00970XXXXXXXXX",null,"Hi Stackoverflow! its me Maher. Sent by sim2",null,null); 

別急...如果消息是超過160個字符,將無法正常工作..所以更好的辦法:

String textSMS; 
//short <160 
// textSMS = "Hi Stackoverflow! its me Maher."; 


//long >160 
textSMS = "Hi Jerusalem, hi Cairo, Hi Prague, hi Baghdad, hi Riyadh, hi Jeddah, hi Dammam, hi Aleppo, hi Casablanca, hi Damascus, hi Alexandria, hi Algiers, hi Mosul, hi Basra, hi Arabia, hi Tripoli, hi Amman, hi Kuwait, hi Beirut, hi Abu Dhabi"; 

int simID = 0;//0:sim_1, 1:sim_2 

ArrayList<String> messageList = SmsManager.getDefault().divideMessage(textSMS); 
if (messageList.size() > 1) { 
    SimUtil.sendMultipartTextSMS(this, simID, "00972XXXXXXXXX", null, messageList, null, null); 
} else { 
    SimUtil.sendSMS(this, simID, "00972XXXXXXXXX", null, textSMS, null, null); 
} 

,所以你可以放心地傳遞消息體,而不必擔心長度。

------------ UPDATE 2016年9月10日----------

要MultipartMessage使用的PendingIntent/DeliveryIntent ..只是創建具有相同內容ArrayList和交上來。這裏是創建PendingIntent列表的實現:

final static String sSMSManagerIntentSENT = "package.DeliveryReport.SMS_SENT"; 
int numParts = parts.size(); 
ArrayList<PendingIntent> pendingIntents = new ArrayList<PendingIntent>(); 

for (int i = 0; i < numParts; i++) { 

    Intent pendingIntent = new Intent(sSMSManagerIntentSENT); 
    //optional if you want to keep info about what action has been done for feedback or analysis later when message is sent 
    pendingIntent.putExtra("package.DeliveryReport.phoneNumber", phoneNo); // receiver phoneNo 
    pendingIntent.putExtra("package.DeliveryReport.textSMS", msg);// msg body 
    pendingIntent.putExtra("SIM", simID); // which sim is sending this message 

    pendingIntents.add(PendingIntent.getBroadcast(getActivity(), 0, pendingIntent,PendingIntent.FLAG_ONE_SHOT)); 
} 

對於交付,只需使用相同的方法。

------------------額外------------------

我已經看到了Android的22是Android 5.1支持多SIM卡,在這裏是如何使用它..不幸的是我沒有設備與該版本進行測試,所以請反饋:

SmsManager.getSmsManagerForSubscriptionId(int subscriptionId).sendTextMessage(String destinationAddress, String scAddress, String text,PendingIntent sentIntent, PendingIntent deliveryIntent); 

如何獲得subscriptionId? 審查屬於SIM卡的所有可用subscriptionID:

SubscriptionManager subscriptionManager = SubscriptionManager.from(getApplicationContext()); 
     List<SubscriptionInfo> subscriptionInfoList = subscriptionManager.getActiveSubscriptionInfoList(); 
     for (SubscriptionInfo subscriptionInfo : subscriptionInfoList) { 
      int subscriptionId = subscriptionInfo.getSubscriptionId(); 
      Log.d("apipas","subscriptionId:"+subscriptionId); 
     } 

**請注意,此代碼正在5.1。如果你嘗試在舊版本上運行它,你會得到一個該方法不存在的異常。

------------ UPDATE 2015年8月19日----------

SIM卡上的信息,均位於DB:telephony.db(默認情況下: /data/data/com.android.providers.telephony/databases/telephony.db)。 查看真實設備上的數據庫表siminfo中的屏幕截圖。

enter image description here

幸運的是對於內容提供商:

"content://telephony/siminfo/" 

所以基本上只是查詢從table.Its重要一提的是插槽0代表SIM1和1代表SIM2的數據,插槽-1從舊/已移除/已更換的SIM卡。

這適用於聯想A319。我想這可能適用於其他設備。 這裏是util的方法我用:

public static List<SimInfo> getSIMInfo(Context context) { 
     List<SimInfo> simInfoList = new ArrayList<>(); 
     Uri URI_TELEPHONY = Uri.parse("content://telephony/siminfo/"); 
     Cursor c = context.getContentResolver().query(URI_TELEPHONY, null, null, null, null); 
     if (c.moveToFirst()) { 
      do { 
       int id = c.getInt(c.getColumnIndex("_id")); 
       int slot = c.getInt(c.getColumnIndex("slot")); 
       String display_name = c.getString(c.getColumnIndex("display_name")); 
       String icc_id = c.getString(c.getColumnIndex("icc_id")); 
       SimInfo simInfo = new SimInfo(id, display_name, icc_id, slot); 
       Log.d("apipas_sim_info", simInfo.toString()); 
       simInfoList.add(simInfo); 
      } while (c.moveToNext()); 
     } 
     c.close(); 

     return simInfoList; 
    } 

,這裏是實體類SimInfo:

public class SimInfo { 
    private int id_; 
    private String display_name; 
    private String icc_id; 
    private int slot; 

    public SimInfo(int id_, String display_name, String icc_id, int slot) { 
     this.id_ = id_; 
     this.display_name = display_name; 
     this.icc_id = icc_id; 
     this.slot = slot; 
    } 

    public int getId_() { 
     return id_; 
    } 

    public String getDisplay_name() { 
     return display_name; 
    } 

    public String getIcc_id() { 
     return icc_id; 
    } 

    public int getSlot() { 
     return slot; 
    } 

    @Override 
    public String toString() { 
     return "SimInfo{" + 
       "id_=" + id_ + 
       ", display_name='" + display_name + '\'' + 
       ", icc_id='" + icc_id + '\'' + 
       ", slot=" + slot + 
       '}'; 
    } 
} 

祝你好運,「。

+1

很好,但我如何獲得有關sim1和sim2的信息?我只想使用特定的運營商發送文本,可以說AT&T。你有什麼想法如何找出每個SIM卡的信息? – Reza 2015-08-18 11:24:48

+1

嗨Alireza,看到我更新的答案。我包括我用於這個目的的util。 – 2015-08-19 08:06:49

+1

非常感謝你,我一定會試一試。 – Reza 2015-08-20 08:54:15

2

馬赫的基於反射解決方案適用於仿真器的Android SDK 10,17,18,19,20,21和如所提到的基於SubscriptionId解決方案適用於SDK 22 它的實際工作爲Micromax的畫布4(的Android 4.2)以及。

但對於一些手機品牌,如Lenevo,華碩品牌與Android 5.0它的錯誤了與

顯示java.lang.NullPointerException:試圖調用虛擬方法 「java.lang.Class中的java.lang。 Object.GetClass()'上一個空對象 參考 「在代碼

方法= stubObj.getClass()。getMethod(「 sendText」,String.class, String.class,String.class,字符串.class,PendingIntent.class, PendingIntent.class);

這意味着它無法得到正確的stubObj

+0

**空指針異常直接與名稱相關聯。即isms或isms0。**華碩我嘗試了isms1,isms2 for sim no 2,但它不起作用。試圖找到我們如何通過反思獲得正確的價值,如果有人知道請讓我知道。 – Vibhav 2015-12-24 17:45:29

+0

我發現的是**服務列表| grep sms會給出電話中有效服務名稱**的列表,即isms,isms2。 現在這裏是棘手的部分..在華碩雙SIM卡手機,我可以看到只有一個短信服務(isms)正在運行,但短信應用程序能夠發送來自2個不同的SIM卡消息。想知道如何... 人需要幫助理解。 – Vibhav 2015-12-24 19:31:07

+0

如果雙sim與1 isms服務存在,發送短信無縫Android 5.0以下是我的解決方案(與聯想和華碩手機測試) - 使用反射和取決於Android 5.0子版本一需要執行 'SmsManager sm = SmsManager.getSmsManagerForSubscriber(SubscriptionManager.getSubId(SimSlotNo))' OR 'SmsManager SM = SmsManager.getSmsManagerForSubscriptionId(SubscriptionManager.getSubId(SimSlotNo))' 得到相應的SIM卡的短信管理器。 然後使用 sm.sendTextMessage(phoneNo,null,msg,sentPI,deliverPI); 通過所需的Sim – Vibhav 2016-01-03 10:15:00

1

我試着在雙SIM卡android手機(API 19及以下版本)中發送短信Mahers Refletion方法。智能手機中的芯片組來自展訊。我遇到Maher的代碼異常,首先它是空指針異常,名稱= isms2。對我來說,sim1是isms0,sim2是isms1,我在dumpsys中檢索了這些信息。由於大部分調試和一些更多的搜索下面的代碼爲我工作:

public class SimUtil { 

public static boolean sendSMS(Context ctx, int simID, String toNum, String centerNum, String smsText, PendingIntent sentIntent, PendingIntent deliveryIntent) { 
    String name; 

    try { 
     if (simID == 0) { 
      name = "isms0"; 
     } else if (simID == 1) { 
      name = "isms1"; 
     } else { 
      throw new Exception("can not get service which for sim '" + simID + "', only 0,1 accepted as values"); 
     } 

     try 
     { 
      Method method = Class.forName("android.os.ServiceManager").getDeclaredMethod("getService", new Class[]{String.class}); 
      method.setAccessible(true); 
      Object param = method.invoke(null, new Object[]{name}); 
      if (param == null) 
      { 
       throw new RuntimeException("can not get service which is named '" + name + "'"); 
      } 
      method = Class.forName("com.android.internal.telephony.ISms$Stub").getDeclaredMethod("asInterface", new Class[]{IBinder.class}); 
      method.setAccessible(true); 
      Object stubObj = method.invoke(null, new Object[]{param}); 
      method = stubObj.getClass().getMethod("sendText", String.class, String.class, String.class, String.class, PendingIntent.class, PendingIntent.class); 
      method.invoke(stubObj, ctx.getPackageName(), toNum, centerNum, smsText, sentIntent, deliveryIntent); 
     } catch (ClassNotFoundException e) 
     { 
      throw new RuntimeException(e); 
     } catch (NoSuchMethodException e) 
     { 
      throw new RuntimeException(e); 
     } catch (InvocationTargetException e) 
     { 
      throw new RuntimeException(e); 
     } catch (IllegalAccessException e) 
     { 
      throw new RuntimeException(e); 
     } 

     return true; 
    } catch (ClassNotFoundException e) { 
     Log.e("Exception", "ClassNotFoundException:" + e.getMessage()); 
    } catch (NoSuchMethodException e) { 
     Log.e("Exception", "NoSuchMethodException:" + e.getMessage()); 
    } catch (InvocationTargetException e) { 
     Log.e("Exception", "InvocationTargetException:" + e.getMessage()); 
    } catch (IllegalAccessException e) { 
     Log.e("Exception", "IllegalAccessException:" + e.getMessage()); 
    } catch (Exception e) { 
     Log.e("Exception", "Exception:" + e); 
    } 
    return false; 
} 

}

以下鏈接也許有幫助:

1

馬赫的解決方案几乎正確。

我在摩托羅拉motog 5上試了一下。1個機器人(單卡),但他的伴讀表content://telephony/siminfo解決方案有一個微小的錯誤:

我的摩托羅拉沒有現場slotsim_id

這種休息是個好人,是相同的。

相關問題