¿Cómo enviar un SMS usando SMSmanager en el móvil Dual SIM?

Estoy usando el administrador de SMS para enviar SMS.Para SIM solo funciona perfectamente para enviar el SMS.pero en la tarjeta SIM dual, el SMS no se enviará.Es posible enviar el mensaje de texto desde la tarjeta SIM dual, si es posible significa cómo puedo seleccionar el que SIM para enviar SMS. ¿Alguien puede ayudarme a resolver este problema?

Código de trabajo SIM simple

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

    Lo uso de esta manera para administrar qué SIM utilizar para enviar SMS, incluso un mensaje largo. Está trabajando en mi teléfono con doble sim Lenovo A319 (4.4.3), sin necesidad de root. está construido sobre la reflexión.

     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 smsTextlist, ArrayList sentIntentList, ArrayList 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; } } 

    Agregar permiso:

      

    entonces simplemente llama a ese método estático (sangriento) como este 🙂

    Para usar SIM1:

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

    Para usar SIM2:

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

    Pero espera ... eso no funcionará si el mensaje tiene más de 160 caracteres ... así que mejor:

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

    para que pueda pasar el cuerpo del mensaje sin preocuparse por la longitud.

    ------------ ACTUALIZACIÓN 09.10.2016 ----------

    Para usar PendingIntent / DeliveryIntent en MultipartMessage, simplemente cree ArrayList con el mismo contenido y páselo. Aquí hay una implementación de la creación de la lista de PendingIntent:

     final static String sSMSManagerIntentSENT = "package.DeliveryReport.SMS_SENT"; int numParts = parts.size(); ArrayList pendingIntents = new ArrayList(); 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)); } 

    Para entregar, solo use el mismo enfoque.

    ------------------ Extra ------------------

    He visto que Android 22 es compatible con varias tarjetas SIM de Android 5.1 y aquí se explica cómo usarlo. Desafortunadamente, no tengo un dispositivo con esa versión para probar, así que por favor para comentarios:

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

    ¿Cómo obtener subscriptionId? para revisar todos los SubscriptionID disponibles que pertenecen a la tarjeta SIM:

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

    ** Tenga en cuenta que este código está funcionando en 5.1. si intentas ejecutarlo en una versión anterior, obtendrías una excepción de que el método no existe.

    ------------ ACTUALIZACIÓN 19.8.2015 ----------

    La información sobre las tarjetas SIM se encuentra en DB: telephony.db (de forma predeterminada: /data/data/com.android.providers.telephony/databases/telephony.db) en la tabla siminfo. Vea la captura de pantalla en la tabla siminfo en DB en el dispositivo real.

    enter image description here

    Afortunadamente, hay un proveedor de contenido para eso:

     "content://telephony/siminfo/" 

    Básicamente, basta con consultar los datos de esa tabla. Es importante mencionar que la ranura 0 representa SIM1 y 1 representa SIM2, y la ranura -1 de las SIM antiguas / eliminadas / reemplazadas.

    Esto se aplica en Lenovo A319. Supongo que eso puede funcionar en otros dispositivos. Aquí está el método util que utilizo:

     public static List getSIMInfo(Context context) { List 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; } 

    y aquí está la clase de entidad 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 + '}'; } } 

    Buena suerte,'.

    La solución basada en la reflexión de Maher funciona para el emulador Android SDK 10, 17, 18, 19,20,21 y, como se mencionó, la solución basada en SubscriptionId funciona para el SDK 22 y también funciona para Micromax Canvas 4 (Android 4.2).

    Pero para algunas marcas de teléfonos como Lenevo, Asus con Android 5.0 se equivoca con

    java.lang.NullPointerException: bash de invocar el método virtual ‘Java.lang.Class Java.Lang.Object.GetClass () ‘ en una referencia de objetos nulos ” en el código

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

    lo que significa que no puede obtener el stubObj adecuado.

    Probé el método de Reflejo de Mahers para enviar sms en un teléfono con Android dual sim (API 19 y siguientes). El chipset en el teléfono inteligente era de Spreadtrum . Encontré excepciones con el código de Maher, primero fue la excepción del puntero nulo, en el nombre = isms2. Para mí, sim1 era isms0 y sim2 is iss1, recuperé esta información en dumpsys. Con mucha depuración y algo más de búsqueda de código siguiente funcionó para mí:

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

    }

    Los siguientes enlaces pueden ser útiles:

    La solución de Maher es casi correcta.

    Lo probé con Motorola motog 5.1 android (single sim), pero su solución con el content://telephony/siminfo tabla de lectura content://telephony/siminfo tenía un pequeño error:

    en mi motorola no había ninguna slot campo sino sim_id

    El rest de esto estuvo bien e idéntico.