如何在双卡手机中使用SMSmanager发送短信?

我使用短信pipe理器发送短信。对于单一的SIM卡,它的作品完美的发送短信。但在双卡的短信不会发送。是否有可能从双卡发送短信,如果可能的话,我怎样才能select哪个SIM卡发送短信。可以任何一个知道帮我解决这个问题。

单SIM卡工作代码

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

Solutions Collecting From Web of "如何在双卡手机中使用SMSmanager发送短信?"

我用这种方式来pipe理哪个SIM卡用于发送短信即使长信息。它的工作在我的双卡手机联想A319(4.4.3),无需根。 它build立在反思之上。

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

所以你可以安全地传递消息体而不用担心长度。

————更新09.10.2016

要在MultipartMessage中使用PendingIntent / DeliveryIntent,只需创build具有相同内容的ArrayList并传递它。 这是一个创buildPendingIntent列表的实现:

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

为了交付,只需使用相同的方法。

—————— Extra ——————

我已经看到,Android 22支持从Android 5.1多SIM卡,这里是如何使用它..不幸的是,我没有该版本的设备进行testing,所以请提供反馈意见:

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

如何获得subscriptionId? 查看属于SIM卡的所有可用订阅ID:

 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。 如果您尝试在旧版本上运行它,则会出现该方法不存在的exception。

————更新19.8.2015

有关SIM卡的信息位于表siminfo中的DB:telephony.db(默认为:/data/data/com.android.providers.telephony/databases/telephony.db)。 在真实设备上的数据库中查看siminfo中的屏幕截图。

在这里输入图像说明

幸运的是有一个内容提供者:

 "content://telephony/siminfo/" 

所以基本上只是从该表中查询数据。其中重要的是要提到的是,插槽0代表SIM1,并且1代表SIM2,插槽-1来自旧/被移除/被replace的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 + '}'; } } 

祝你好运,'。

Maher基于reflection的解决scheme适用于模拟器Android SDK 10,17,18,19,20,21以及基于SubscriptionId的解决scheme适用于SDK 22,它实际上也适用于Micromax Canvas 4(Android 4.2)。

但是对于一些像Lenevo这样的手机品牌,搭配Android 5.0的华硕品牌则会出错

java.lang.NullPointerException:试图在代码上调用虚方法' Java.lang.Class Java.Lang.Object.GetClass() '在空对象引用上“

method = stubObj.getClass()。getMethod(”sendText“,String.class,String.class,String.class,String.class,PendingIntent.class,PendingIntent.class);

这意味着它无法获得正确的stubObj

我尝试使用Mahers Refletion方法在双卡android手机(API 19及以下版本)中发送短信。 智能手机中的芯片组来自展讯 。 我遇到Maher的代码exception,首先是空指针exception,名字= isms2。 对我来说,sim1是isms0,sim2是isms1,我在dumpsys中检索到这个信息。 随着更多的debugging和更多的search下面的代码为我工作:

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

}

以下链接可能有帮助:

马赫的解决scheme几乎是正确的。

我尝试了摩托罗拉motog 5.1安卓(单sim),但他的解决scheme阅读表content://telephony/siminfo有一个小小的bug:

在我的sim_id没有现场slotsim_id

其余的这是罚款和相同的。