You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android-Java:发送SMS后BroadcastReceiver.onReceive()未调用及机型异常

问题分析与修复方案

问题现象

  • 小米设备:SMS完全无法发送,默认短信客户端显示消息未发送
  • 三星设备:SMS能正常发送,但SMSBroadcastReceiver的onReceive()方法未触发,应用最终因等待超时返回错误

LogCat日志

I SmsServiceModule: onReceiveSmsMessage: errorCode=-1

核心问题梳理

1. 自定义对象传递错误

SMS.Result类未实现Parcelable接口,却尝试通过Intent.putExtra("result", res)传递数组,导致广播接收时无法正确获取对象,直接触发异常,这是三星设备广播不生效的核心原因之一。

2. 广播注册逻辑冲突

代码同时使用动态注册和静态注册同一SMSBroadcastReceiver:

  • 动态注册的Receiver在发送短信后立即被注销,可能导致广播还未触发就失去接收能力
  • 静态注册的Receiver配置了自定义广播的intent-filter,与动态注册逻辑重叠,造成干扰

3. BroadcastReceiver代码错误

  • 错误引用Functions.Result类,实际应为SMS.Result,直接引发类转换异常
  • 对SMS_SENT/SMS_DELIVERED广播尝试解析pdu参数,这两个广播由系统发送,不会携带该参数,导致空指针风险
  • 日志打印语句未执行是因为上述异常被系统捕获,代码逻辑根本无法走到日志步骤

4. 线程等待逻辑缺陷

使用Thread.sleep循环等待结果,会阻塞当前线程(主线程调用会触发ANR),且等待条件仅判断DELIVERED状态,忽略了SENT广播的提前回调,导致超时逻辑错误。

5. 小米设备发送失败原因

  • 小米系统对非默认短信应用的发送权限有严格限制,未设置为默认应用时可能被拦截
  • 权限申请不完整:Android 6+需动态申请SEND_SMS权限,仅Manifest声明无效

6. 语法错误

service.java中使用单引号定义字符串(Java要求双引号),且调用了不存在的sms.sent()方法,直接导致编译错误。


修复步骤

1. 修正Result类实现Parcelable

public class SMS {
    public Context context = null;

    SMS(Context context) { this.context = context; }

    // 实现Parcelable接口,支持Intent传递
    public static class Result implements Parcelable {
        public String status = null;
        public String body = null;
        public String error = null;

        Result(String body) { this.body = body; }
        Result(String body, String error) { this.error = error; }
        Result(String body, String error, String status) {
            if (body != null && !body.isEmpty())
                 this.body = body;
            else this.error = error;
            this.status = status;
        }

        protected Result(Parcel in) {
            status = in.readString();
            body = in.readString();
            error = in.readString();
        }

        public static final Creator<Result> CREATOR = new Creator<Result>() {
            @Override
            public Result createFromParcel(Parcel in) {
                return new Result(in);
            }

            @Override
            public Result[] newArray(int size) {
                return new Result[size];
            }
        };

        @Override
        public int describeContents() {
            return 0;
        }

        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(status);
            dest.writeString(body);
            dest.writeString(error);
        }
    }

    public static String SENT = "SMS_SENT";
    public static String DELIVERED = "SMS_DELIVERED";
}

2. 重构广播接收逻辑(改用静态注册+回调机制)

修改SMSBroadcastReceiver

public class SMSBroadcastReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.d("~=", "onReceive triggered: " + intent.getAction());

        int resultCode = getResultCode();
        String action = intent.getAction();
        int requestCode = intent.getIntExtra("requestCode", -1);

        SMS.SMSCallback callback = SMS.getCallback(requestCode);
        if (callback == null) return;

        SMS.Result result;
        if (SMS.SENT.equals(action)) {
            if (resultCode == Activity.RESULT_OK) {
                result = new SMS.Result(null, null, SMS.SENT);
            } else {
                String error = getConstantName(resultCode, SmsManager.class);
                result = new SMS.Result(null, "发送失败: " + error, SMS.SENT);
            }
        } else if (SMS.DELIVERED.equals(action)) {
            result = resultCode == Activity.RESULT_OK
                    ? new SMS.Result(null, null, SMS.DELIVERED)
                    : new SMS.Result(null, "送达失败", SMS.DELIVERED);
        } else {
            result = null;
        }

        if (result != null) {
            callback.onResult(result);
            SMS.removeCallback(requestCode);
        }
    }

    private String getConstantName(int value, Class<?> cls) {
        for (java.lang.reflect.Field f : cls.getDeclaredFields()) {
            int mod = f.getModifiers();
            if (Modifier.isStatic(mod) && Modifier.isPublic(mod) && Modifier.isFinal(mod)) {
                try {
                    if ((int) f.get(null) == value) return f.getName();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return "未知错误(" + value + ")";
    }
}

修改SMS类的发送逻辑(移除线程等待,改用回调)

public class SMS {
    // ... 保留之前的Result类和常量定义 ...

    public interface SMSCallback {
        void onResult(Result result);
    }

    private static final HashMap<Integer, SMSCallback> callbackMap = new HashMap<>();
    private static int requestCodeCounter = 0;

    public void sendSMS(JSONObject input, SMSCallback callback) {
        try {
            ArrayList<PendingIntent> sentPendingIntents = new ArrayList<>();
            ArrayList<PendingIntent> deliveredPendingIntents = new ArrayList<>();

            SmsManager smsManager = SmsManager.getDefault();
            ArrayList<String> mSMSMessage = smsManager.divideMessage(input.getString("message"));
            String number = input.getString("number");

            for (int i = 0; i < mSMSMessage.size(); i++) {
                int requestCode = generateUniqueRequestCode();
                addCallback(requestCode, callback);

                Intent iSent = new Intent(SENT)
                        .setPackage(context.getPackageName())
                        .putExtra("requestCode", requestCode);
                Intent iDelivered = new Intent(DELIVERED)
                        .setPackage(context.getPackageName())
                        .putExtra("requestCode", requestCode + 1000);

                PendingIntent sentPI = PendingIntent.getBroadcast(
                        context, requestCode, iSent,
                        PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE
                );
                PendingIntent deliveredPI = PendingIntent.getBroadcast(
                        context, requestCode + 1000, iDelivered,
                        PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE
                );

                sentPendingIntents.add(sentPI);
                deliveredPendingIntents.add(deliveredPI);
            }

            smsManager.sendMultipartTextMessage(number, null, mSMSMessage, sentPendingIntents, deliveredPendingIntents);
        } catch (Exception e) {
            Log.e("~=", "发送异常: " + e.toString());
            callback.onResult(new Result("", "发送异常: " + e.toString()));
        }
    }

    private synchronized int generateUniqueRequestCode() {
        return requestCodeCounter++;
    }

    private synchronized void addCallback(int requestCode, SMSCallback callback) {
        callbackMap.put(requestCode, callback);
    }

    public static synchronized SMSCallback getCallback(int requestCode) {
        return callbackMap.get(requestCode);
    }

    public static synchronized void removeCallback(int requestCode) {
        callbackMap.remove(requestCode);
    }
}

3. 修复SMSService语法错误

public class SMSService extends Service {
    SMS sms = new SMS(this);

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        try {
            JSONObject input = new JSONObject();
            input.put("number", "123456");
            input.put("message", "test message");
            
            sms.sendSMS(input, result -> {
                if (result.error != null) {
                    Log.e("~=", result.error);
                } else {
                    Log.d("~=", result.status + " 成功");
                }
                stopSelf(startId);
            });
        } catch (JSONException e) {
            e.printStackTrace();
            stopSelf(startId);
        }
        return START_NOT_STICKY;
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}

4. 小米设备适配:处理默认短信应用权限

// 在MainActivity中添加权限检查与引导
private static final int REQUEST_SMS_PERMISSIONS = 100;

private void checkSmsPermissions() {
    String[] permissions = {
            Manifest.permission.SEND_SMS,
            Manifest.permission.RECEIVE_SMS,
            Manifest.permission.READ_SMS
    };
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.SEND_SMS) != PackageManager.PERMISSION_GRANTED) {
        ActivityCompat.requestPermissions(this, permissions, REQUEST_SMS_PERMISSIONS);
    }

    // 检查是否为默认短信应用,小米设备需此权限才能正常发送
    if (!isDefaultSmsApp(this)) {
        setDefaultSmsApp(this);
    }
}

private boolean isDefaultSmsApp(Context context) {
    String defaultPackage = Telephony.Sms.getDefaultSmsPackage(context);
    return getPackageName().equals(defaultPackage);
}

private void setDefaultSmsApp(Context context) {
    Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
    intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, getPackageName());
    startActivity(intent);
}

内容的提问来源于stack exchange,提问作者Obscurus Grassator

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 04:27:02