Android 13及以上版本读取短信的方法与权限限制解决方案
Android 12+ 读取特定号码短信的可行方案
针对Android 12及以上版本无法通过常规权限申请获取READ_SMS权限的问题,结合你读取特定号码状态短信的业务场景,以下是几个合法可行的解决方案:
方案一:利用SMS_RECEIVED广播实时接收短信(无需READ_SMS权限)
Android 12+允许应用通过动态注册android.provider.Telephony.SMS_RECEIVED广播实时接收新短信,且无需申请READ_SMS权限。你的代码已实现核心逻辑,可做以下适配优化:
优化后的代码示例
// 在Activity的onCreate中调用动态注册广播 private void registerSmsReceiver() { smsReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(intent.getAction())) { Bundle bundle = intent.getExtras(); if (bundle != null) { Object[] pdus = (Object[]) bundle.get("pdus"); if (pdus != null) { // Android 10+ 推荐使用带format参数的createFromPdu方法 String format = bundle.getString("format"); for (Object pdu : pdus) { SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdu, format); String sender = smsMessage.getDisplayOriginatingAddress(); String messageBody = smsMessage.getMessageBody(); handleSmsMessage(sender, messageBody); } } } } } }; IntentFilter filter = new IntentFilter(Telephony.Sms.Intents.SMS_RECEIVED_ACTION); // 设置优先级(可选,多应用监听时高优先级可先接收短信) filter.setPriority(1000); registerReceiver(smsReceiver, filter); } // 务必在Activity销毁时注销广播,避免内存泄漏 @Override protected void onDestroy() { super.onDestroy(); if (smsReceiver != null) { unregisterReceiver(smsReceiver); } } // 保留原有短信处理逻辑,过滤特定号码并处理内容 private void handleSmsMessage(String sender, String messageBody) { String messageHash = sender + "|" + messageBody; if (receivedMessageHashes.contains(messageHash)) { Log.d("SmsReceiver", "检测到重复消息,忽略处理。"); return; } receivedMessageHashes.add(messageHash); Log.d("SmsReceiver", "发送方: " + sender); Log.d("SmsReceiver", "消息内容: " + messageBody); if (!currentStater.getStarter_phone_number().isEmpty() && sender.contains(currentStater.getStarter_phone_number())) { Log.d("SmsReceiver", "收到来自指定号码的短信: " + currentStater.getStarter_phone_number()); if (messageBody.contains("3-PHASE OK")) { status.setText("3-PHASE OK"); phase1.setImageResource(R.drawable.img_btn_background); phase2.setImageResource(R.drawable.img_btn_background); phase3.setImageResource(R.drawable.img_btn_background); isActivated = false; isActivated1 = false; isActivated2 = false; } else if (messageBody.contains("Line Fault")) { status.setText("Line Fault"); phase1.setImageResource(R.drawable.img_btn_background); phase2.setImageResource(R.drawable.img_btn_background); phase3.setImageResource(R.drawable.img_btn_background); } } }
注意事项
- Android 8.0+静态注册该广播会失效,必须使用动态注册。
- 仅能接收实时短信,无法读取历史短信。
方案二:引导用户手动开启SMS特殊权限(读取历史短信)
若必须读取历史短信,Android 12+将READ_SMS归为特殊权限,无法通过常规弹窗申请,需引导用户到应用设置页面手动开启:
权限申请优化代码
private void checkSmsPermission() { if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED) { // Android 12+ 直接跳转至应用特殊权限设置页 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { Intent intent = new Intent(Settings.ACTION_APP_SPECIAL_ACCESS_SETTINGS); intent.setData(Uri.parse("package:" + getPackageName())); startActivity(intent); } else { ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_SMS}, REQUEST_READ_SMS_PERMISSION); } } } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_READ_SMS_PERMISSION) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { queryLatestSmsMessages(); } else { showToast("读取短信权限被拒绝,请前往设置手动开启。"); } } }
注意事项
- 此方案用户操作成本较高,仅在必须读取历史短信时使用。
方案三:SMS Retriever API(需短信格式配合)
若你能控制发送短信的格式,可使用Google提供的SMS Retriever API。该API无需任何短信权限,只需短信内容包含应用的签名哈希即可自动获取短信,适合验证码场景;若无法调整短信内容,则此方案不适用。
内容的提问来源于stack exchange,提问作者Rohith Chanda
相关产品推荐
相关产品推荐

