【问题标题】:SMS sending: System says SMS delivered successfully, but actually not短信发送:系统提示短信发送成功,但实际上没有
【发布时间】:2019-07-14 04:38:43
【问题描述】:

我的应用通过 SmsManager.sendMultipartTextMessage 发送短信,然后通知服务器短信发送的状态。

一切正常,但 Yota 运算符有问题。短信不会发送到 MTS 运营商的手机。 Yota 运营商的员工声称 MTS 运营商阻止接收来自 Yota 的消息。

这不是我们的问题,但是安卓系统说这样的短信发送成功了。我们无法从另一部手机重新发送此类短信,因为我们的系统认为它们已经成功发送。

如果应用尝试发送此类短信,系统首先会发出成功发送短信的信号,然后发出成功发送短信的信号。听起来不错,但实际上没有发送短信。这不是一个孤立的案例。在不同的设备上进行了测试。还尝试使用 MTS 运营商将 SMS 发送到不同的手机。

我尝试通过标准的“消息”应用程序发送相同的短信并注意到以下内容:

从我的应用程序发送的短信在不同设备上的标准“消息”应用程序中的显示方式不同。例如,ZTE BLADE L110 (API 22) 显示发送消息时出错,而小米红米 3S (API 23) 则没有。但是,当我尝试通过标准应用程序发送此类短信时,在两部智能手机上都会显示错误发送消息(中兴通讯在此之前显示 Toast“短信成功发送”)。

谁能帮忙?是否有其他方法可以检查 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>

短信发送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();
    }

}

短信发送广播接收器:

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}

测试短信:gate4

【问题讨论】:

    标签: android sms send


    【解决方案1】:

    SMS 不是公认的协议。您无法知道它是否已从发送端交付。发件人只能知道消息何时发送。发送报告正确,因为数据正在发送,但在另一端被阻止。

    如果您需要确认短信,您可以从接收方回复,但这需要您开发自己的确认协议。

    我只是从设备轮询网络服务。无论如何,数据比短信便宜很多

    祝你好运。

    【讨论】:

    • 谢谢。但是标准的“消息”应用程序如何注册短信发送错误?
    • 如果“消息”应用程序报告发送错误,则实际上是在上传消息时出现问题。它不像发送 TCP 消息。它更接近于发送邮件(不是电子邮件,因为某些服务器实际上会报告发送失败)。
    • 如果“消息”应用程序报告发送错误,则实际上是在上传消息时出现问题。我明白这一点,但它总是发生。通过我的应用程序和标准“消息”应用程序发送短信的结果是相同的:没有发送短信。但标准应用程序承认这一事实。我的应用没有,因为系统说该消息已成功传递。
    • SMS 未发送,因为 MTS 阻止从 Yota 接收。没有理由认为从我的应用程序和标准发送的消息无法传递的原因存在差异。
    • 因此,如果您使用“消息”或您的应用程序发送完全相同的消息,它会返回不同的结果?这很奇怪。这个程序可以毫无问题地发送到非 MTS 电话/调制解调器吗?
    猜你喜欢
    • 2015-10-26
    • 1970-01-01
    • 2019-04-24
    • 2017-06-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多