Возможность отправки смс с помощью Sim1 или Sim2 программно

У меня телефон Android с двумя SIM-картами, и я хочу отправлять смс с помощью Sim1 или Sim2. По умолчанию сообщение отправляется с sim1. Но я хочу отправить смс с sim2. Возможна ли настройка отправки смс с помощью Sim1 или Sim2?

Было бы здорово, если бы были настройки для отправки смс с помощью Sim1 или Sim2 .. это полезно для телефонов Android с двумя SIM-картами. Я создал приложение для смс Android. Я смог без проблем отправлять смс, но по умолчанию смс отправляется с SIM-карты 1. Но я хочу отправить смс программно, установив отправку смс с помощью sim1 или sim2?


person Jebasuthan    schedule 28.01.2014    source источник
comment
AFAIK нет стандартного способа сделать это, поскольку Android SDK не поддерживает две SIM-карты. Однако хаки, связанные с отражением, могут сработать - уже есть довольно много похожих вопросов по SO!   -  person jclehner    schedule 09.05.2014
comment
Привет, Джеба, у тебя есть решение. Пожалуйста, помогите мне, если у вас есть   -  person Gangadhar Nimballi    schedule 06.01.2015
comment
@GangadharNimbally, Привет, еще нет решения для этого ... я тоже ищу решение.   -  person Jebasuthan    schedule 06.01.2015
comment
Вы можете найти подробный ответ здесь stackoverflow.com/questions/27351936/   -  person Syed Murtaza Mehdi    schedule 28.03.2018


Ответы (6)


Если вы можете использовать этот код для уровня API 22+.

private void sendDirectSMS() {

    private static String SENT = "SMS_SENT", DELIVERED = "SMS_DELIVERED";

    PendingIntent sentPI = PendingIntent.getBroadcast(this, 0, new Intent(
        SENT), 0);

    PendingIntent deliveredPI = PendingIntent.getBroadcast(this, 0,
        new Intent(DELIVERED), 0);

    // SEND BroadcastReceiver
    BroadcastReceiver sendSMS = new BroadcastReceiver() {
        @Override
        public void onReceive(Context arg0, Intent arg1) {
            switch (getResultCode()) {
                case Activity.RESULT_OK:
                    showSnackBar(getString(R.string.sms_sent));
                    Analytics.track(AnalyticsEvents.SEND_REMINDER_SMS_APP_SUCCESS);
                    break;
                case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                    showSnackBar(getString(R.string.sms_send_failed_try_again));
                    Analytics.track(AnalyticsEvents.SEND_REMINDER_SMS_APP_FAILED);
                    break;
                case SmsManager.RESULT_ERROR_NO_SERVICE:
                    showSnackBar(getString(R.string.no_service_sms_failed));
                    Analytics.track(AnalyticsEvents.SEND_REMINDER_SMS_APP_FAILED);
                    break;
                case SmsManager.RESULT_ERROR_NULL_PDU:
                    showSnackBar(getString(R.string.no_service_sms_failed));
                    Analytics.track(AnalyticsEvents.SEND_REMINDER_SMS_APP_FAILED);
                    break;
                case SmsManager.RESULT_ERROR_RADIO_OFF:
                    showSnackBar(getString(R.string.no_service_sms_failed));
                    Analytics.track(AnalyticsEvents.SEND_REMINDER_SMS_APP_FAILED);
                    break;
            }
        }
    };

    // DELIVERY BroadcastReceiver
    BroadcastReceiver deliverSMS = new BroadcastReceiver() {
        @Override
        public void onReceive(Context arg0, Intent arg1) {
            switch (getResultCode()) {
                case Activity.RESULT_OK:
                    Toast.makeText(getBaseContext(), R.string.sms_delivered,
                        Toast.LENGTH_SHORT).show();
                    break;
                case Activity.RESULT_CANCELED:
                    Toast.makeText(getBaseContext(), R.string.sms_not_delivered,
                        Toast.LENGTH_SHORT).show();
                    break;
            }
        }
    };

    registerReceiver(sendSMS, new IntentFilter(SENT));
    registerReceiver(deliverSMS, new IntentFilter(DELIVERED));
    String smsText = getSmsText();

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
        SubscriptionManager localSubscriptionManager = SubscriptionManager.from(context);
        if (localSubscriptionManager.getActiveSubscriptionInfoCount() > 1) {
            List localList = localSubscriptionManager.getActiveSubscriptionInfoList();

            SubscriptionInfo simInfo1 = (SubscriptionInfo) localList.get(0);
            SubscriptionInfo simInfo2 = (SubscriptionInfo) localList.get(1);

            //SendSMS From SIM One
            SmsManager.getSmsManagerForSubscriptionId(simInfo1.getSubscriptionId()).sendTextMessage(customer.getMobile(), null, smsText, sentPI, deliveredPI);

            //SendSMS From SIM Two
            SmsManager.getSmsManagerForSubscriptionId(simInfo2.getSubscriptionId()).sendTextMessage(customer.getMobile(), null, smsText, sentPI, deliveredPI);
        }
    } else {
        SmsManager.getDefault().sendTextMessage(customer.getMobile(), null, smsText, sentPI, deliveredPI);
        Toast.makeText(getBaseContext(), R.string.sms_sending, Toast.LENGTH_SHORT).show();
    }
}

Также добавьте разрешение.

<uses-permission android:name="android.permission.SEND_SMS"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
person Anjal Saneen    schedule 17.07.2018
comment
какая возможная ценность SENT & DELIVERED? и что такое клиент в строке sendTextMessage (customer.getMobile (), ...? - person asqa; 05.09.2018
comment
@asqaЯ отредактировал ответ со значением SENT & DELIVERED, customer.getMobile () - это номер мобильного телефона - person Anjal Saneen; 06.09.2018
comment
Я очень рекомендую это гораздо более чистое решение (отражение не требуется, работает для уровня API 22+) - person Abdu; 21.09.2018
comment
отображение исключения Exception: java.lang.RuntimeException: не удается получить службу с именем isms0, не работающую на устройствах - person kriti sharma; 18.10.2019
comment
Как разработчикам сохранить выбранную информацию о подписке, чтобы она была выбрана в следующий раз, когда пользователь решит отправить SMS? Там есть какой-то уникальный ID? iccId? Номер телефона (полезно, так как это тот, с которого будут отправлены сообщения)? Если для SMS не выбрана SIM-карта по умолчанию (проверено с помощью subscriptionId ‹0), есть ли намерение позволить пользователю выбрать ее? - person android developer; 25.02.2020

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

это может работать после версии 5.1 Lollipop. до этого нам нужно увидеть больше. как только я получу ответ, я обновлю.

person Thiyagesh waran    schedule 01.08.2017
comment
так как отправить либо с sim1, либо с sim2? - person Efrain Sanjay Adhikary; 30.08.2017

Вы должны проверить Tasker, вы сможете использовать его для создания виджета переключения для этого.

person Ajster1989    schedule 09.05.2014

Вот полный образец, показывающий, как выбрать один, и протестированный на реальном устройстве (OnePlus 2) с 2 сим-картами. Обратите внимание, что вы должны обрабатывать разрешения (предоставить их перед использованием кода):

манифест

    <uses-permission android:name="android.permission.SEND_SMS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
<!--    <uses-permission android:name="android.permission.READ_SMS" />-->
<!--    <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />-->

build.gradle

        minSdkVersion 21
        targetSdkVersion 29
...
    implementation "com.google.android.gms:play-services-auth:17.0.0"

activity_main.xml

<Button xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    tools:text="send sms" />

MainActivity.kt


import android.annotation.SuppressLint
import android.app.Activity
import android.app.PendingIntent
import android.content.*
import android.os.Build
import android.os.Bundle
import android.telephony.SmsManager
import android.telephony.SubscriptionInfo
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
import android.util.Log
import android.util.LongSparseArray
import android.view.View
import android.view.autofill.AutofillManager
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.gms.auth.api.Auth
import com.google.android.gms.auth.api.credentials.Credential
import com.google.android.gms.auth.api.credentials.HintRequest
import com.google.android.gms.common.api.GoogleApiClient
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
    private lateinit var googleApiClient: GoogleApiClient
    private val partialSmsIdToSmsReceiverMap = LongSparseArray<SmsBroadcastReceiver>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        button.visibility = View.GONE
        tryGetCurrentUserPhoneNumber(this)
        googleApiClient = GoogleApiClient.Builder(this).addApi(Auth.CREDENTIALS_API).build()
        if (phoneNumberToSendTo.isEmpty()) {
            val hintRequest = HintRequest.Builder().setPhoneNumberIdentifierSupported(true).build()
            val intent = Auth.CredentialsApi.getHintPickerIntent(googleApiClient, hintRequest)
            try {
                startIntentSenderForResult(intent.intentSender, REQUEST_PHONE_NUMBER, null, 0, 0, 0);
            } catch (e: IntentSender.SendIntentException) {
                Toast.makeText(this, "failed to show phone picker", Toast.LENGTH_SHORT).show()
            }
        } else
            onGotPhoneNumberToSendTo(phoneNumberToSendTo)

    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_PHONE_NUMBER) {
            if (resultCode == Activity.RESULT_OK) {
                val cred: Credential? = data?.getParcelableExtra(Credential.EXTRA_KEY)
                phoneNumberToSendTo = cred?.id ?: ""
                if (phoneNumberToSendTo.isEmpty())
                    Toast.makeText(this, "failed to get phone number", Toast.LENGTH_SHORT).show()
                else
                    onGotPhoneNumberToSendTo(phoneNumberToSendTo)
            }
        }
    }

    private fun onGotPhoneNumberToSendTo(normalizedPhoneNumberToSendSmsTo: String) {
        button.visibility = View.VISIBLE
        button.text = "send SMS to $normalizedPhoneNumberToSendSmsTo"
        button.setOnClickListener {
            val smsManager = SmsManager.getDefault()
            val messageToSend = "Hello there"
            val parts = smsManager.divideMessage(messageToSend)
            val sentIntents = ArrayList<PendingIntent>(parts.size)
            val fullSmsMessageId = fullSmsIdCounter++
            Log.d("AppLog", " sendSmsMessage sending sms #$fullSmsMessageId parts count:${parts.size} messageToSend:\n$messageToSend")
            val pendingPartialSmsIds = HashSet<Long>()
            for (i in 0 until parts.size) {
                val partialSmsId = partialSmsIdCounter++
                Log.d("AppLog", " sendSmsMessage sending sms #$fullSmsMessageId part id:${partialSmsId}")
                val action = "$ACTION_SMS_SENT_FORMAT$partialSmsId"
                sentIntents.add(PendingIntent.getBroadcast(applicationContext, 0, Intent(action), 0))
                val smsSentBroadcastReceiver = SmsBroadcastReceiver(fullSmsMessageId, partialSmsId)
                partialSmsIdToSmsReceiverMap.put(partialSmsId, smsSentBroadcastReceiver)
                applicationContext.registerReceiver(smsSentBroadcastReceiver, IntentFilter(action))
                pendingPartialSmsIds.add(partialSmsId)
            }
            sendSmsUsingDefaultSimCard(applicationContext, normalizedPhoneNumberToSendSmsTo, parts, sentIntents)
        }
    }

    @SuppressLint("NewApi", "MissingPermission")
    fun sendSmsUsingDefaultSimCard(applicationContext: Context, destinationAddress: String, parts: ArrayList<String>,
                                   sentIntents: ArrayList<PendingIntent>? = null, deliveryIntents: ArrayList<PendingIntent>? = null) {
        val defaultSmsManager = SmsManager.getDefault()
        val phoneNumber = if (destinationAddress.startsWith("+")) destinationAddress else "+$destinationAddress"
        //check if we have multi-SIM and don't have a default one to work with, so that we will choose it ourselves
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP_MR1) {
            defaultSmsManager.sendMultipartTextMessage(phoneNumber, null, parts, sentIntents, deliveryIntents)
            return
        }
        val subscriptionManager = applicationContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
        val defaultSubscriptionId = SmsManager.getDefaultSmsSubscriptionId()
        val smsManager = SmsManager.getSmsManagerForSubscriptionId(defaultSubscriptionId)
        if (smsManager != null) {
            smsManager.sendMultipartTextMessage(phoneNumber, null, parts, sentIntents, deliveryIntents)
            return
        }
        val activeSubscriptionInfoList: MutableList<SubscriptionInfo>? = subscriptionManager.activeSubscriptionInfoList
        val subscriptionInfoId = activeSubscriptionInfoList?.getOrNull(0)?.subscriptionId
        if (subscriptionInfoId != null)
            SmsManager.getSmsManagerForSubscriptionId(subscriptionInfoId).sendMultipartTextMessage(phoneNumber, null, parts, sentIntents, deliveryIntents)
        else
            defaultSmsManager.sendMultipartTextMessage(phoneNumber, null, parts, sentIntents, deliveryIntents)
    }

    private inner class SmsBroadcastReceiver(val fullSmsId: Long, val partialSmsId: Long) : BroadcastReceiver() {
        override fun onReceive(someContext: Context, intent: Intent) {
            Log.d("AppLog", " SmsBroadcastReceiver onReceive")
            applicationContext.unregisterReceiver(this)
            partialSmsIdToSmsReceiverMap.remove(partialSmsId)
            val smsError: String? = when (resultCode) {
                -1, 0 /*SmsManager.RESULT_ERROR_NONE*/ -> null
                SmsManager.RESULT_ERROR_GENERIC_FAILURE -> "RESULT_ERROR_GENERIC_FAILURE"
                SmsManager.RESULT_ERROR_RADIO_OFF -> "RESULT_ERROR_RADIO_OFF"
                SmsManager.RESULT_ERROR_NULL_PDU -> "RESULT_ERROR_NULL_PDU"
                SmsManager.RESULT_ERROR_NO_SERVICE -> "RESULT_ERROR_NO_SERVICE"
                SmsManager.RESULT_ERROR_LIMIT_EXCEEDED -> "RESULT_ERROR_LIMIT_EXCEEDED"
                SmsManager.RESULT_ERROR_SHORT_CODE_NOT_ALLOWED -> "RESULT_ERROR_SHORT_CODE_NOT_ALLOWED"
                SmsManager.RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED -> "RESULT_ERROR_SHORT_CODE_NEVER_ALLOWED"
                /**SmsManager.RESULT_ERROR_FDN_CHECK_FAILURE*/
                6 -> "RESULT_ERROR_FDN_CHECK_FAILURE"
//                16 /*SmsManager.RESULT_MODEM_ERROR*/ -> "RESULT_MODEM_ERROR"
//                111 /*SmsManager.RESULT_RIL_MODEM_ERR*/ -> "RESULT_RIL_MODEM_ERR"
                else -> "Unknown error"
            }
            Log.d("AppLog", "SmsBroadcastReceiver sms #$fullSmsId part #$partialSmsId send-state updated. sent fine?${smsError == null} (error:$smsError) errorCode:$resultCode")
        }
    }

    companion object {
        private const val REQUEST_PHONE_NUMBER = 1
        private var partialSmsIdCounter = 0L
        private var fullSmsIdCounter = 0L
        private const val ACTION_SMS_SENT_FORMAT = "_ACTION_SENT_"
        private var phoneNumberToSendTo = ""

        @SuppressLint("MissingPermission", "HardwareIds")
        private fun tryGetCurrentUserPhoneNumber(context: Context): String {
            if (phoneNumberToSendTo.isNotEmpty())
                return phoneNumberToSendTo
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                val subscriptionManager = context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
                try {
                    subscriptionManager.activeSubscriptionInfoList?.forEach {
                        val number: String? = it.number
                        if (!number.isNullOrBlank()) {
                            phoneNumberToSendTo = number
                            return number
                        }
                    }
                } catch (ignored: Exception) {
                }
            }
            try {
                val telephonyManager = context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
                val number = telephonyManager.line1Number ?: ""
                if (!number.isBlank()) {
                    phoneNumberToSendTo = number
                    return number
                }
            } catch (e: Exception) {
            }
            return ""
        }
    }
}


person android developer    schedule 26.02.2020

РЕШЕНИЕ БЕЗ android.permission.READ_PHONE_STATE

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1) {
        SubscriptionManager subs = (SubscriptionManager) getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
        if (subs != null) {
            Log.d("sim_spalsh", "num sims = " + subs.getActiveSubscriptionInfoCountMax());

            if (subs.getActiveSubscriptionInfoCountMax() > 1) {

                //SendSMS From SIM One
                SmsManager.getSmsManagerForSubscriptionId(0)
                        .sendTextMessage(phonenumber, null, "sim1", null, null);

                //SendSMS From SIM Two
                SmsManager.getSmsManagerForSubscriptionId(1)
                        .sendTextMessage(phonenumber, null, "sim2", null, null);

            }
        }
    }

Вы должны гарантировать <uses-permission android:name="android.permission.SEND_SMS"/>

person Javier Castellanos Cruz    schedule 31.01.2020
comment
Есть ли способ получить его до Android API 22? Кроме того, сбой приложений, которые пытаются отправить SMS обычным способом (с использованием sendMultipartTextMessage), если имеется более 1 сим-карты? - person android developer; 23.02.2020

Опция доступна в настройках Android - перейдите в Настройки >> Беспроводные сети >> Управление SIM-картами >> Настройки по умолчанию >> Сообщения >> и выберите «Всегда спрашивать».

person Community    schedule 24.11.2014