奥利奥广播接收器未能接收短信的问题

15
我正在开发的应用程序允许用户允许该应用程序读取确认短信的内容以自动输入验证码。对于所有使用早于 Oreo(API 26)操作系统的设备,BroadcastReceiver 的实现可以正常工作,并允许正确接收短信。通过这种实现方式,我是指将接收器对象放置在 AndroidManifest 中。
<receiver android:name=".SmsReceiver">
        <intent-filter>
            <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
        </intent-filter>
</receiver>

然而,从Oreo开始,必须显式地将BroadcastReceivers注册到适当的上下文中。我已经按照以下方式实现了这一点:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            smsReceiver = new SmsReceiver();
            IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
            intentFilter.addAction(Telephony.Sms.Intents.DATA_SMS_RECEIVED_ACTION);
            this.registerReceiver(smsReceiver, intentFilter);
        }

在收到Manifest.permission.READ_SMS权限后,将执行此代码块。SmsReceiver类扩展了BroadcastReceiver并覆盖了其onReceive()方法。

我有几个问题:

  1. 我已经测试了这个实现,并在我的SmsReceiver的onReceive()方法中设置了断点。当短信到达时,应用程序从未进入onReceive()方法。这可能是为什么?

  2. 我按照Android开发者网站上描述的方式实例化了IntentFilter,即使用ConnectivityManager.CONNECTIVITY_ACTION操作。我知道SmsReceiver可以工作,因为在注册接收器时总是会命中onReceive()中的断点。然而,操作仅为CONNECTIVITY_ACTION。SMS_RECEIVED_ACTION从未被接收器捕获。是否绝对必要使用此操作来实例化IntentFilter,或者可以省略此操作?

  3. 是否还有其他遗漏的内容可能导致接收器无法捕获到到达的短信?


SMS_RECEIVED广播白名单中,因此您使用的原始方法 <intent-filter> 仍然有效。 - CommonsWare
我也曾经这样想过,但是它在所有之前的操作系统上都能正常工作,但不知为何在Oreo上却不能。难道接收Oreo上的短信会有什么问题吗? - oldsport76
我刚在运行Android 8.1的Pixel 2上尝试了一下,并且在清单中注册SMS_RECEIVED广播时没有遇到任何问题。我记录了一条消息到LogCat,消息显示出来了。 - CommonsWare
这听起来好和不好 ;). 你是用和我一样的方法吗?你能贴一些代码吗? - oldsport76
1
三星S8也是同样的情况。这是我做的让它只工作了一次:手动关闭和打开短信权限,然后它就可以工作了。你们有没有解决这个问题? - Waqas Ahmed Ansari
显示剩余5条评论
6个回答

20

之前我请求了- Manifest.permission.READ_SMS权限,但不起作用,然后我将权限更改为- Manifest.permission.RECEIVE_SMS,然后它在Oreo中开始起作用,并且我还在清单中指定了接收器。我不知道这是否有帮助,但这让我的一天过得很愉快

   public static void requestPermissionForReadSMS(Fragment fragment) {
    //        if (fragment.shouldShowRequestPermissionRationale(Manifest.permission.READ_SMS)) {
    //            Helpers.showRequestPermissionAlertDialog(fragment, fragment.getString(R.string.read_sms_permission), fragment.getString(R.string.permission_request));

    //        } else {
            fragment.requestPermissions(new String[]{Manifest.permission.RECEIVE_SMS},
                    Constants.READ_SMS_PERMISSION);
   // }

        }

1
我已经苦苦挣扎了几个小时,一直在使用相同的READ_SMS权限。你救了我的一天。 - Wijay Sharma

5
@rohit sharma 提供的答案对我起初很有帮助,但后来我也在一加、小米、OPPO和vivo等不同设备上测试了我的应用程序,发现:
1. 在vivo、OPPO和小米(miui系统)设备上,默认情况下会禁用名为“自启动”的功能,因此SMS_RECIEVED_ACTION无法正常工作(这里的工作是指在接收到短信时启动应用程序或在后台运行任何服务)。即使已从最近隐式禁止列表中被列入白名单。
2. 在一加设备上,如果您的应用程序被列入电池优化列表中(默认情况下是这样),则SMS_RECIEVED_ACTION仅在应用程序在前台或后台时才能正常工作。如果您的应用程序被杀死或在手机重新启动后,广播接收器将无法工作。要使SMS_RECIEVD_ACTION正常工作,您需要将应用程序从电池优化列表中删除。有关更多信息,请参阅此处的线程。

1
自动启动是一个大问题,除非用户启用,否则我们无法做任何事情,这也适用于推送通知。 - Rohit Sharma
在Android 9中,我已经关闭了两个地方的电池优化,以使我的应用程序正常工作:设置-->电池优化和优化电池使用。 Android 9的更改非常奇怪,Google应该认真修订它们。 - saeed khalafinejad

5
对我而言这个有效:
private int MY_PERMISSIONS_REQUEST_SMS_RECEIVE = 10;
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.RECEIVE_SMS},
        MY_PERMISSIONS_REQUEST_SMS_RECEIVE);

在权限被授予后,在您的主活动中提及上述代码。之后覆盖以下内容:
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] 
            permissions, @NonNull int[] grantResults) {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
            if (requestCode == MY_PERMISSIONS_REQUEST_SMS_RECEIVE) {
                Log.d("TAG", "My permission request sms received successfully");
            }
 }

现在不需要手动开启或关闭短信权限。

这就是全部。


4

同时关闭和打开了短信权限。几秒钟后,它就起作用了。


4
为什么你要把别人的文字复制到你的回答里? - Mr. T
抱歉,我的意图不是在得到解决方案后复制另一个答案,我只是为这个问题添加了解决方案。对此我感到抱歉。我忘记提到将解决此问题的人。 - Pranav Wani

2
只需要添加 < /p>
android:permission="android.permission.BROADCAST_SMS"

需要在清单文件中将接收器标签指向特定的位置。

因此,理想的清单文件注册广播接收器如下:

<receiver android:name=".receivers.SMSBroadCastReceiver"
        android:exported="true"
        android:permission="android.permission.BROADCAST_SMS">
        <intent-filter
            android:priority="2147483647">
            <action android:name="android.provider.Telephony.SMS_RECEIVED" />
        </intent-filter>
    </receiver>

更新:

现在建议使用SMS RETRIEVER API来读取短信(否则在某些情况下,Play Store将不允许发布apk)。请查看链接。


你需要在 <manifest>...</manifest> 部分中授予权限 <uses-permission android:name="android.permission.RECEIVE_SMS"/>,并在 <receiver ...> 属性中添加 android:permission="android.permission.BROADCAST_SMS" 权限 - 在我的 LG G6 上测试通过,运行的是 Android 8。 - D. Müller

1
对于Oreo及更高版本,特别是在请求权限声明中添加Manifest.permission.RECEIVE_SMS,无论你是否已经要求其他与短信相关的权限。在清单中列出相同的权限但不包括接收器,接收器将会动态注册(静态和编程方式都放置接收器会失去意义)。
requestPermissions(new String[]{Manifest.permission.READ_SMS, Manifest.permission.RECEIVE_SMS},
                    Constants.SMS_REQUEST_PERMISSION_CODE);

在Android 8.0之前(API级别26),如果应用程序在运行时请求权限并且被授予了该权限,则系统还会错误地授予应用程序属于同一权限组且在清单中注册的其余权限,这是因为文档中引用的原因。针对Android 8.0的应用程序已经更正了这种行为。应用程序仅被授予它明确请求的权限。但是,一旦用户向应用程序授予了某个权限,该权限组中所有后续的权限请求都将自动授予。这就是为什么您需要确保在测试之前撤销模拟器/设备中的短信权限的原因。

在 Vivo 手机上,需要手动检查自启动权限,这样当应用程序关闭或被杀死时,才能正常接收短信(在 Android 9 上进行测试)。 - DILSHAD AHMAD

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接