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
相关产品推荐
相关产品推荐

