Отправка SMS: система сообщает, что SMS доставлено успешно, но на самом деле нет - PullRequest
0 голосов
/ 20 февраля 2019

Мое приложение отправляет SMS через SmsManager.sendMultipartTextMessage, а затем уведомляет сервер о состоянии отправки SMS.

Все работает нормально, но есть проблема с оператором Yota.СМС не доставляются на телефоны с оператором МТС.Сотрудники оператора Yota утверждают, что оператор МТС блокирует получение сообщений от Yota.

Это не наша проблема, но система Android сообщает, что такие SMS успешно доставлены.Мы не можем повторно отправлять такие SMS-сообщения с другого телефона, поскольку наша система считает, что они уже были успешно доставлены.

Если приложение пытается отправить такое SMS, система сначала сообщает об успешной отправке SMS, а затем об успешной доставке SMS.Звучит хорошо, но на самом деле СМС не доставляется.Это не единичный случай.Проверено на разных устройствах.Также пытался отправить смс на разные телефоны с оператором МТС.

Я пытался отправить одно и то же SMS через стандартное приложение «Сообщения» и заметил следующее:

SMS, отправленные из моего приложения, по-разному отображаются в стандартном приложении «Сообщения» на разныхустройства.Например, ZTE BLADE L110 (API 22) показывает ошибку при отправке сообщения, а Xiaomi Redmi 3S (API 23) - нет.Но на обоих смартфонах при попытке отправить такое СМС через стандартное приложение отображается сообщение об ошибке отправки (ZTE до этого показывает тост "СМС успешно отправлено").

Кто может помочь?Может ли быть другой способ проверить, доставлено SMS или нет?Как стандартное приложение «Сообщения» регистрирует факт ошибки отправки SMS, когда система генерирует намерения с сигналами, что сообщение было успешно отправлено и доставлено?

Вот мой код:

Отправка SMSзадание:

public class SendSMSJob extends SimpleJobService {

    public static final String EXTRA_SMS_LIST_JSON = "sms_list";
    public static final String TAG = "send_sms_job";

    private static final String ACTION_SENT = "ru.sp2all.smsgate.SMS_SENT";
    private static final String ACTION_DELIVERED = "ru.sp2all.smsgate.SMS_DELIVERED";

    private int startId;

    @Override
    public void onCreate() {
        super.onCreate();
        MyLog.i(getLogTag(), "onCreate()");
    }

    @Override
    public int onRunJob(JobParameters parameters) {
        try {
            this.startId = startId;
            String json = parameters.getExtras().getString(EXTRA_SMS_LIST_JSON);
            Gson gson = new Gson();
            SMSDataList smsDataList = gson.fromJson(json, SMSDataList.class);

            MyLog.d(getLogTag(), "Sending " + String.valueOf(smsDataList.items.length) + " messages");

            boolean complete = true;
            boolean needRetry = true;
            for (SMSData sms: smsDataList.items) {
                Integer subscriptionId = SimsHelper.getSimSubscriptionIdForIndex(getApplicationContext(), sms.simIndex);
                SmsManager smsManager = null;
                if (subscriptionId != null) {
                    smsManager = SmsManager.getSmsManagerForSubscriptionId(subscriptionId);
                } else {
                    smsManager = SmsManager.getDefault();
                }
                ArrayList<String> parts = smsManager.divideMessage(sms.message);
                MyLog.i(getLogTag(), "parts.size=" + parts.size());

                insertSmsToDB(sms, parts);

                ArrayList<PendingIntent> deliveryIntents = new ArrayList<>(parts.size());
                ArrayList<PendingIntent> sentIntents = new ArrayList<>(parts.size());

                try {
                    for (int part = 0; part < parts.size(); part++) {
                        Intent sentIntent = new Intent(ACTION_SENT);

                        sentIntent.putExtra("id",     sms.smsId + "_" + Integer.toString(part));
                        sentIntent.putExtra("sms_id", sms.smsId);
                        sentIntent.putExtra("parts",  Integer.toString(parts.size()));
                        sentIntent.putExtra("part", Integer.toString(part));
                        sentIntent.putExtra("phone", sms.phone);
                        sentIntent.putExtra("msg", sms.message);

                        PendingIntent sentPI = PendingIntent.getBroadcast(this,
                                Integer.parseInt(sms.smsId) * 100 + part,
                                sentIntent,
                                PendingIntent.FLAG_UPDATE_CURRENT);
                        sentIntents.add(sentPI);

                        Intent deliveredIntent = new Intent(ACTION_DELIVERED);

                        deliveredIntent.putExtra("id",     sms.smsId + "_" + Integer.toString(part));
                        deliveredIntent.putExtra("sms_id", sms.smsId);
                        deliveredIntent.putExtra("parts",  Integer.toString(parts.size()));
                        deliveredIntent.putExtra("part",   Integer.toString(part));
                        deliveredIntent.putExtra("phone", sms.phone);
                        deliveredIntent.putExtra("msg", sms.message);

                        PendingIntent deliveredPI = PendingIntent.getBroadcast(this,
                                Integer.parseInt(sms.smsId) * 100 + part,
                                deliveredIntent,
                                PendingIntent.FLAG_UPDATE_CURRENT);
                        deliveryIntents.add(deliveredPI);
                    }

                    MyLog.i(getLogTag(), "Sending to " + sms.phone);
                    smsManager.sendMultipartTextMessage(sms.phone, null, parts,
                            sentIntents, deliveryIntents);

                } catch (Exception e) {
                    ErrorReporter.exception(this, getLogTag(), e, new ErrorReporter.ReporterHandler(e));
                    complete = true;
                }
            }
            if (complete) {
                return RESULT_SUCCESS;
            } else if (needRetry) {
                return RESULT_FAIL_RETRY;
            } else {
                return RESULT_FAIL_NORETRY;
            }
        } catch (Exception e) {
            ErrorReporter.exception(this, getLogTag(), e, new ErrorReporter.ReporterHandler(e));
            return RESULT_FAIL_RETRY;
        }
    }

    private String getLogTag() {
        return getClass().getSimpleName();
    }
}

Зарегистрировано в AndroidManifest Приемники вещания для обработки статуса SMS:

    <receiver android:name=".SMSSentReceiver">
        <intent-filter>
            <action android:name="ru.sp2all.smsgate.SMS_SENT" />
        </intent-filter>
    </receiver>

    <receiver android:name=".SMSDeliveredReceiver">
        <intent-filter>
            <action android:name="ru.sp2all.smsgate.SMS_DELIVERED" />
        </intent-filter>
    </receiver>

Отправлено SMS BroadcastReceiver:

public class SMSSentReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            String sms_id = intent.getStringExtra("sms_id");
            int part = Integer.parseInt(intent.getStringExtra("part"));
            MyLog.d(getLogTag(), "br_sent " + sms_id);

            int status = 0;

            int code = getResultCode();

            switch (code) {
                case SmsManager.RESULT_ERROR_GENERIC_FAILURE:
                    status = 400;
                    break;
                case SmsManager.RESULT_ERROR_NO_SERVICE:
                    status = 401;
                    break;
                case SmsManager.RESULT_ERROR_NULL_PDU:
                    status = 402;
                    break;
                case SmsManager.RESULT_ERROR_RADIO_OFF:
                    status = 403;
                    break;
                case Activity.RESULT_OK:
                    updateDBWithNewSentPartsCount();
                    status = 202; // 202 is SMS sent Server status
                    break;
                default:
                    status = 404; break;
            }

            if (status == 202) {
                int sent = getSentPartsFromDB();
                int parts = getAllPartsFromDB();
                MyLog.d(getLogTag(), "DB sent:" + sms_id + " - : sent:" + sent + " parts: " + parts);
                if (sent >= parts) {
                    MyLog.d(getLogTag(), "DB sent all parts");
                    Network.sendSMSStatus(context, sms_id, status);
                }
            } else {
                Network.sendSMSStatus(context, sms_id, status);
            }

        } catch (Exception e) {
            ErrorReporter.exception(context, getLogTag(), e, new ErrorReporter.ReporterHandler(e));
        }
    }

    private String getLogTag() {
        return getClass().getSimpleName();
    }

}

SMS доставлено Broadcast Receiver:

public class SMSDeliveredReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        try {
            String sms_id = intent.getStringExtra("sms_id");
            int part = Integer.parseInt(intent.getStringExtra("part"));
            MyLog.d(getLogTag(), "br_delivered " + sms_id);
            int resultCode = getResultCode();

            switch (resultCode) {
                case Activity.RESULT_OK:

                    updateDBWithNewDeliveredPartsCount();

                    int delivered = getDeliveredPartsFromDB();
                    int parts = getAllPartsFromDB();
                    MyLog.i(getLogTag(), "DB delivered: " + sms_id + ", " + delivered + " parts of " + parts);
                    if (delivered >= parts) {
                        MyLog.i(getLogTag(), "DB delivered all parts");
                        Network.sendSMSStatus(context, sms_id, 200); // 200 is SMS delivered Server status
                    }

                    break;
                case Activity.RESULT_CANCELED:
                    MyLog.w(getLogTag(), "DB delivered: CANCELLED " + sms_id);
                    Network.sendSMSStatus(context, sms_id, 405);
                    break;
                default:
                    MyLog.w(getLogTag(), "DB delivered: unknown code " + resultCode);
                    Network.sendSMSStatus(context, sms_id, resultCode);
            }
        } catch (Exception e) {
            ErrorReporter.exception(context, getLogTag(), e, new ErrorReporter.ReporterHandler(e));
        }
    }

    private String getLogTag() {
        return getClass().getSimpleName();
    }
}

Журнал с устройства, когда я пытаюсь отправить SMS и SMS фактически не доставлено:

SendSMSJob: onCreate()
SendSMSJob: Sending 1 messages
SendSMSJob: parts.size=1
SendSMSJob: Sending to +7988*******
SMSSentReceiver: br_sent 704402
SMSSentReceiver: DB sent:704402 - : sent:1 parts: 1
SMSSentReceiver: DB sent all parts
Network: sendSMSStatus status: 202
Network: get: https://{SERVER_NAME}/result.php?status=202&smsId=704402
Network: got: {"status":200}
SMSDeliveredReceiver: br_delivered 704402
SMSDeliveredReceiver: DB delivered: 704402, 1 parts of 1
SMSDeliveredReceiver: DB delivered all parts
Network: sendSMSStatus status: 200
Network: get: https://{SERVER_NAME}/result.php?status=200&smsId=704402
Network: got: {"status":200}

Текст SMS для теста: gate4

1 Ответ

0 голосов
/ 21 февраля 2019

SMS не является подтвержденным протоколом.Вы не можете знать, было ли оно доставлено с отправляющей стороны.Отправитель может знать только когда сообщение отправлено.Отправка сообщает правильно, так как данные отправляются, но они блокируются на другом конце.

Если вам нужно подтвержденное SMS, вы можете ответить от получателя, но это потребует разработки собственного протокола подтверждения,

Я бы просто опросил веб-сервис с устройства.В любом случае данные на LOT дешевле, чем SMS-сообщения.

Удачи.

...