web-dev-qa-db-ger.com

So senden Sie eine SMS SMSmanager in Dual-SIM-Handys verwenden

Ich verwende SMS Manager, um SMS zu senden. Für eine SIM-Karte funktioniert das Senden der SMS einwandfrei. Bei einer Dual-SIM-Karte wird das SMS nicht gesendet. Kann das SMS von Dual-SIM, wenn möglich, wie kann ich die SIM-Karte auswählen, die SMS senden soll. Kann mir jemand helfen, dieses Problem zu lösen.

Single SIM Arbeitscode

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

Ich verwende diesen Weg, um zu verwalten, welche Sim für das Senden von SMS auch lange Nachrichten verwendet werden soll. Es funktioniert auf meinem Dual-SIM-Telefon Lenovo A319 (4.4.3), keine Notwendigkeit für root. Es ist auf Reflexion gebaut.

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


}

Erlaubnis hinzufügen:

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

dann nennen Sie diese (blutige) statische Methode so :) 

So verwenden Sie SIM1:

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

So verwenden Sie SIM2:

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

Aber warte ... das funktioniert nicht, wenn die Nachricht länger als 160 Zeichen ist ... also besser:

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

so können Sie den Nachrichtentext sicher übergeben, ohne sich um die Länge zu kümmern.

------------ UPDATE 09.10.2016 ----------

Um PendingIntent/DeliveryIntent in MultipartMessage zu verwenden, erstellen Sie einfach ArrayList mit demselben Inhalt und übergeben Sie diese. Hier ist eine Implementierung zum Erstellen von 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));
}

Verwenden Sie für die Lieferung einfach den gleichen Ansatz.

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

Ich habe gesehen, dass Android 22 Multi-SIM-Karten von Android 5.1 unterstützt. Hier erfahren Sie, wie Sie es verwenden können. Leider habe ich kein Gerät mit dieser Version zum Testen. Bitte für Rückmeldungen:

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

Wie bekomme ich eine Abo-ID? zur Überprüfung aller verfügbaren Abonnement-IDs, die zur SIM-Karte gehören:

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

** Bitte beachten Sie, dass dieser Code auf 5.1 funktioniert. Wenn Sie versuchen, es mit einer älteren Version auszuführen, erhalten Sie eine Ausnahme, dass die Methode nicht existiert.

------------ UPDATE 19.8.2015 ----------

Informationen zu SIMs finden Sie in DB: telephony.db (standardmäßig: /data/data/com.Android.providers.telephony/databases/telephony.db) in der Tabelle siminfo. Siehe Abbildung auf der Tabelle siminfo in DB auf dem realen Gerät.

 enter image description here

Zum Glück gibt es dafür einen Content-Provider: 

"content://telephony/siminfo/"

Im Grunde fragen Sie also einfach Daten aus dieser Tabelle ab. Es ist wichtig zu erwähnen, dass Steckplatz 0 SIM1 und 1 SIM2 und Steckplatz -1 von alten/entfernten/ersetzten SIMs darstellt.

Dies gilt für Lenovo A319. Ich denke, das funktioniert vielleicht auch auf anderen Geräten ... Hier ist die Methode, die ich benutze: 

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

und hier ist die Entitätsklasse 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 +
                '}';
    }
}

Viel Glück,'.

44
Maher Abuthraa

Die reflexionsbasierte Lösung von Maher funktioniert für Emulator Android SDK 10, 17, 18, 19,20,21 und wie bereits erwähnt, funktioniert die auf SubscriptionId basierende Lösung für SDK 22 Sie funktioniert auch für Micromax Canvas 4 (Android 4.2) . 

Aber für einige Handys Marken wie Lenevo, Asus Marken mit Android 5.0 gibt es Fehler

Java.lang.NullPointerException: Versuch, die virtuelle Methode aufzurufen 'Java.lang.Class Java.Lang.Object.GetClass () ' für Nullobjekte Referenz "bei Code 

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

was bedeutet, dass es nicht in der Lage ist, die richtige stubObj zu erhalten.

3
Vibhav

Ich habe die Mahers Refletion-Methode zum Senden von SMS in Android-Handys (API 19 und darunter) ausprobiert. Der Chipsatz im Smartphone stammt von Spreadtrum. Ich habe Ausnahmen mit Maher-Code gefunden, zuerst war es eine Null-Zeiger-Ausnahme im Namen = isms2. Für mich war sim1 isms0 und sim2 war isms1. Ich habe diese Informationen im Dumpsys abgerufen. Mit viel Debugging und mehr Suche funktionierte folgender Code für mich:

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

}

Folgende Links können hilfreich sein:

2
Shweta Shrestha

Mohers Lösung ist fast richtig. 

Ich habe es auf Motorola motog 5.1 Android (single sim) ausprobiert, aber seine Lösung mit der Lesetabelle content://telephony/siminfo hatte einen kleinen Fehler: 

bei meinem Motorola gab es kein Feld slot, sondern sim_id

der Rest war gut und identisch.

2

im Hinblick auf die @ Vibhav-Lösung, hier ist, wie ich es erfolgreich implementieren konnte

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

Diese Lösung hat bei mir gut funktioniert, aber ich würde diese viel sauberere Lösung (keine Reflektion erforderlich, funktioniert für API-Level 22+) wärmstens empfehlen, die hier zu finden ist https: // stackoverflow .com/a/51380282/342788

1
Abdu