Android 8设备使用FCM 11.8.0启动服务触发IllegalStateException异常求助
这个问题我之前帮不少开发者排查过,核心原因很清晰:Android 8.0(API 26)开始引入了严格的后台执行限制,禁止应用在无可见Activity的后台状态下直接启动传统Service;而你使用的com.google.firebase:firebase-messaging:11.8.0是比较早期的版本,还没针对这个系统规则做适配,所以才会抛出java.lang.IllegalStateException: Not allowed to start service Intent错误。
下面给你两种可行的解决方案,优先推荐第一种:
方案一:升级Firebase Messaging依赖版本
这是最简单也最稳妥的方式,Google在后续的Firebase Messaging版本中已经完全适配了Android 8+的后台限制,内部会自动处理服务启动的逻辑,不需要你修改业务代码。
只需要把依赖替换为较新的稳定版本(建议直接用最新稳定版,比如23.x系列,你可以根据项目其他依赖的兼容性调整):
implementation 'com.google.firebase:firebase-messaging:23.0.0'
升级后,原来的FirebaseMessagesService代码不需要做任何修改,就能在Android 8设备上正常工作。
方案二:手动适配Android 8+的后台限制(不升级依赖时使用)
如果因为项目兼容性问题暂时无法升级依赖,可以通过以下两种方式手动适配:
方式1:用JobIntentService替代传统Service
JobIntentService是Android官方推荐的适配方案,它会根据系统版本自动选择用JobScheduler(Android O+)或传统Service(低于O版本)来执行后台任务,完美避开后台启动限制。
步骤如下:
- 创建继承
JobIntentService的消息处理类:
public class FCMJobIntentService extends JobIntentService { public static final String FCM_ACTION_MESSAGE = "com.project.services.fcm.ACTION_MESSAGE"; public static final String EXTRA_MESSAGE = "VALUE"; private static final int JOB_ID = 1001; // 唯一的Job ID,自己定义即可 // 静态方法,用于启动任务,自动适配系统版本 public static void enqueueWork(Context context, Intent intent) { enqueueWork(context, FCMJobIntentService.class, JOB_ID, intent); } @Override protected void onHandleWork(@NonNull Intent intent) { // 这里写你原来在FirebaseMessagesService中处理消息的逻辑 if (FCM_ACTION_MESSAGE.equals(intent.getAction())) { String message = intent.getStringExtra(EXTRA_MESSAGE); // 处理消息的业务代码... } } }
- 修改原
FirebaseMessagesService的onMessageReceived方法,改用JobIntentService处理任务:
public class FirebaseMessagesService extends FirebaseMessagingService { @Override public void onMessageReceived(@NonNull RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); Intent intent = new Intent(FCMJobIntentService.FCM_ACTION_MESSAGE); intent.putExtra(FCMJobIntentService.EXTRA_MESSAGE, remoteMessage.getData().toString()); // 用JobIntentService的方式启动任务 FCMJobIntentService.enqueueWork(this, intent); } }
- 在
AndroidManifest.xml中注册FCMJobIntentService:
<service android:name=".FCMJobIntentService" android:permission="android.permission.BIND_JOB_SERVICE" />
方式2:启动前台Service(不推荐,会显示通知)
如果你必须使用传统Service,那么在Android 8+设备上需要调用startForegroundService,并且在Service的onCreate方法中调用startForeground显示一个前台通知,否则系统会在几秒后强制停止服务并抛出异常。
示例代码:
- 启动Service时的版本判断:
Intent intent = new Intent(this, YourService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { startForegroundService(intent); } else { startService(intent); }
- 在Service的
onCreate中创建前台通知:
@Override public void onCreate() { super.onCreate(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { // 创建通知渠道(Android O+必须) NotificationChannel channel = new NotificationChannel("fcm_service_channel", "FCM消息处理", NotificationManager.IMPORTANCE_LOW); NotificationManager notificationManager = getSystemService(NotificationManager.class); if (notificationManager != null) { notificationManager.createNotificationChannel(channel); } // 构建前台通知 Notification notification = new NotificationCompat.Builder(this, "fcm_service_channel") .setSmallIcon(R.drawable.ic_notification) // 替换成你的通知图标 .setContentTitle("处理FCM消息") .setContentText("正在后台处理消息") .build(); startForeground(1, notification); // 启动前台服务,传入唯一的通知ID和通知实例 } }
内容的提问来源于stack exchange,提问作者Alejandro Uribe Sánchez

