web-dev-qa-db-fra.com

Comment envoyer un SMS utiliser SMSmanager dans Dual SIM mobile?

J'utilise le gestionnaire SMS pour envoyer des SMS.Pour une carte SIM unique, il fonctionne parfaitement pour envoyer les SMS.Mais dans la carte SIM double, le message SMS ne sera pas envoyé. Est-il possible d'envoyer le SMS à partir de SIM, si possible, signifie comment puis-je sélectionner la carte SIM à envoyer par SMS? Quelqu'un peut-il m'aider à résoudre ce problème?.

Code de travail SIM unique

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

J'utilise cette méthode pour gérer la carte SIM à utiliser pour l'envoi d'un message même long SMS .. Son travail sur mon téléphone double carte Lenovo A319 (4.4.3), aucun besoin de root. son construit sur la réflexion.

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


}

Ajouter une permission:

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

ensuite, appelez cette méthode statique (sanglante) comme celle-ci :) 

Pour utiliser SIM1:

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

Pour utiliser SIM2:

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

Mais attendez ... ça ne marchera pas si le message est plus long que 160 caractères .. alors meilleure façon:

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

afin que vous puissiez passer en toute sécurité le corps du message sans vous soucier de sa longueur.

------------ MISE À JOUR 09.10.2016 ----------

Pour utiliser PendingIntent/DeliveryIntent dans MultipartMessage .., créez simplement ArrayList avec le même contenu et transmettez-le. Voici une implémentation de la création de List of 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));
}

Pour livrer, utilisez simplement la même approche.

------------------ Supplémentaire ------------------

J'ai vu qu'Android 22 prend en charge plusieurs cartes SIM à partir d'Android 5.1. Voici comment l'utiliser. Malheureusement, je n'ai pas d'appareil avec cette version à tester, alors veuillez nous faire part de vos commentaires:

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

Comment obtenir subscriptionId? pour examiner tous les abonnements disponibles appartenant à la carte SIM:

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

** Veuillez noter que ce code fonctionne sur 5.1. si vous essayez de l'exécuter sur une version plus ancienne, vous obtiendrez une exception: cette méthode n'existe pas.

------------ MISE À JOUR 19.8.2015 ----------

Les informations sur les cartes SIM se trouvent dans la base de données: telephony.db (par défaut: /data/data/com.Android.providers.telephony/databases/telephony.db) dans le tableau siminfo. Voir la capture d'écran de la table siminfo dans la base de données sur un périphérique réel.

 enter image description here

Heureusement, il existe un fournisseur de contenu pour cela: 

"content://telephony/siminfo/"

Il est donc important de mentionner que l’emplacement 0 représente SIM1, et 1 représente SIM2 et l’emplacement -1 des anciennes SIM supprimées/remplacées/remplacées.

Ceci s’applique à Lenovo A319. Je suppose que cela peut fonctionner sur d’autres périphériques . Voici la méthode util que j’utilise: 

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

et voici la classe d'entité 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 +
                '}';
    }
}

Bonne chance,'.

44
Maher Abuthraa

La solution basée sur la réflexion de Maher fonctionne pour l'émulateur Android SDK 10, 17, 18, 19,20,21 et, comme mentionné, la solution basée sur SubscriptionId fonctionne pour le SDK 22. Elle fonctionne également pour Micromax Canvas 4 (Android 4.2). . 

Mais pour certaines marques de téléphones comme Lenevo, les marques Asus avec Android 5.0, il erreurs avec

Java.lang.NullPointerException: tentative d'appel de la méthode virtuelle 'Java.lang.Class Java.Lang.Object.GetClass () ' sur un objet null référence "au code 

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

ce qui signifie que vous ne pouvez pas obtenir la bonne variable stubObj.

3
Vibhav

J'ai essayé la méthode Mahers Refletion pour envoyer des sms sur un téléphone Android double sim (API 19 et moins). Le chipset dans le smartphone provenait de Spreadtrum. J'ai rencontré des exceptions avec le code de Maher. Il s'agissait d'abord de l'exception Null Pointer, dans le nom = isms2. Pour moi, sim1 était isms0 et sim2 était isms1, j'ai récupéré cette information dans les dumpsys. Avec beaucoup de débogage et un peu plus de recherche, le code suivant a fonctionné pour moi:

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

}

Les liens suivants peuvent être utiles:

2
Shweta Shrestha

La solution de Maher est presque juste. 

Je l'ai essayé sur Motorola motog 5.1 Android (single sim), mais sa solution avec la table de lecture content://telephony/siminfo présentait un léger bug: 

sur mon Motorola, il n'y avait pas de champ slot mais sim_id

le reste était parfait et identique.

2
Kamil Orzechowski

en ce qui concerne la solution @Vibhav, voici comment je pourrais la mettre en œuvre avec succès 

method = Class.forName("Android.telephony.SubscriptionManager").getDeclaredMethod("getSubId", int.class);
method.setAccessible(true);
int simID = 1; //while simID is the slot number of your second simCard
param = (int[]) method.invoke(null, new Integer(simID));
int inst =  param[0];
smsMan = SmsManager.getSmsManagerForSubscriptionId(inst);
smsMan.sendTextMessage(toNum, null, smsText, null, null);

Cette solution a bien fonctionné avec moi, mais je recommanderais vivement cette solution beaucoup plus propre (aucune réflexion nécessaire, fonctionne pour l'API de niveau 22+) trouvée ici https://stackoverflow.com/a/51380282/3427883

0
Abdu