目标SDK26的自动回复应用:重启锁屏后SMS广播接收器失效求助
解决重启后锁屏状态下SMS广播接收器失效的问题
嘿,针对你遇到的这个重启后锁屏(Direct Boot模式)下两个SMS广播接收器都不工作的问题,结合SDK26的Android特性,我整理了几个关键修复点,应该能帮你搞定:
1. 先搞懂动态注册接收器的坑
你通过registerPhoneStateReceiver()动态注册的DynamicPhoneStateReceiver,只有在应用进程运行起来之后才会生效。设备重启后,锁屏状态下应用还没启动,这个动态接收器完全处于“未激活”状态,自然收不到任何广播。
怎么破?
- 把
BOOT_COMPLETED广播的接收逻辑移到**静态注册的PhoneStateReceiver**里——静态接收器是可以在Direct Boot模式下被系统唤醒的,不受应用是否启动的限制。 - 等静态接收器收到
BOOT_COMPLETED后,启动一个标记了directBootAware=true的后台服务,在服务里面完成动态接收器的注册操作。
2. 完善静态接收器的配置和权限
调整AndroidManifest.xml
给静态接收器加上BOOT_COMPLETED的intent-filter,同时确保所有要在Direct Boot下工作的组件都正确标记directBootAware="true":
<receiver android:name="com.lemi.callsautoresponder.callreceiver.PhoneStateReceiver" android:directBootAware="true" android:enabled="true" android:exported="true"> <!-- 保留原有SMS相关的action,新增BOOT_COMPLETED --> <intent-filter android:priority="2147483647"> <action android:name="android.intent.action.PHONE_STATE"/> <action android:name="android.provider.Telephony.SMS_DELIVER"/> <action android:name="android.provider.Telephony.SMS_RECEIVED"/> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> <!-- 保留其他原有的intent-filter --> </receiver> <!-- 新增一个支持Direct Boot的服务,用来注册动态接收器 --> <service android:name=".DirectBootInitService" android:directBootAware="true" android:exported="false"/>
补加BOOT_COMPLETED权限
别忘了在AndroidManifest里加上RECEIVE_BOOT_COMPLETED权限,不然收不到开机广播:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
3. 实现Direct Boot初始化服务
创建DirectBootInitService类,在服务启动的时候完成动态接收器的注册:
public class DirectBootInitService extends Service { private static final String TAG = "DirectBootInitService"; private DynamicPhoneStateReceiver _phoneReceiver; @Override public void onCreate() { super.onCreate(); // 在这里注册动态接收器 registerDynamicReceivers(); } private void registerDynamicReceivers() { Log.i(TAG, "在Direct Boot模式下注册动态接收器"); _phoneReceiver = new DynamicPhoneStateReceiver(); // 注册电话状态变化的广播 IntentFilter intentFilter1 = new IntentFilter(); intentFilter1.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED); intentFilter1.setPriority(0x7fffffff); registerReceiver(_phoneReceiver, intentFilter1); // 注册SMS_RECEIVED广播,带上权限验证 IntentFilter intentFilter2 = new IntentFilter(Telephony.SMS_RECEIVED); intentFilter2.setPriority(0x7fffffff); registerReceiver(_phoneReceiver, intentFilter2, Manifest.permission.BROADCAST_SMS, null); // 注册GSM_SMS_RECEIVED广播 IntentFilter intentFilter3 = new IntentFilter(Telephony.GSM_SMS_RECEIVED); intentFilter3.setPriority(0x7fffffff); registerReceiver(_phoneReceiver, intentFilter3, Manifest.permission.BROADCAST_SMS, null); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 让服务保持存活(如果怕被系统杀死,可以改成前台服务) return START_STICKY; } @Override public void onDestroy() { super.onDestroy(); // 注销接收器,避免内存泄漏 if (_phoneReceiver != null) { unregisterReceiver(_phoneReceiver); } } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }
4. 修改静态接收器的onReceive方法
在PhoneStateReceiver里处理BOOT_COMPLETED广播,启动我们刚才创建的初始化服务:
public class PhoneStateReceiver extends BroadcastReceiver { private static final String TAG = "PhoneStateReceiver"; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (Intent.ACTION_BOOT_COMPLETED.equals(action)) { Log.i(TAG, "收到开机广播,启动DirectBoot初始化服务"); // 获取Direct Boot模式下的上下文,确保服务能在锁屏状态启动 Context directBootContext = context.createDeviceProtectedStorageContext(); Intent serviceIntent = new Intent(directBootContext, DirectBootInitService.class); directBootContext.startForegroundService(serviceIntent); } else if (Telephony.SMS_DELIVER.equals(action) || Telephony.SMS_RECEIVED.equals(action)) { Log.i(TAG, "静态接收器收到SMS广播"); // 在这里处理SMS逻辑,或者转发给动态接收器处理 } } }
几个关键细节要注意
- Direct Boot上下文:必须用
createDeviceProtectedStorageContext()获取设备保护存储的上下文,这样服务才能在锁屏状态下正常启动,不受用户数据锁的限制。 - SMS广播的区别:
SMS_DELIVER是系统发给默认短信应用的显式广播,静态注册就能在Direct Boot下接收;而SMS_RECEIVED是隐式广播,Android O及以上版本静态注册收不到,必须动态注册。 - 服务存活问题:如果你的应用在后台容易被系统回收,可以把
DirectBootInitService改成前台服务(弹出一个通知),避免被系统杀死。
内容的提问来源于stack exchange,提问作者M.Gin
相关产品推荐
相关产品推荐

