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);
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.
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,'.
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
.
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:
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.
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