Android App后台接收FCM通知无振动及图标异常问题求助
这个问题的核心原因是FCM消息的两种处理机制差异:当你的App处于后台时,notification类型的消息会由Android系统直接展示,不会触发App内的onMessageReceived方法,所以你在MyNotificationManager里设置的振动、自定义图标等配置完全不会生效;只有当App在前台时,notification消息才会传递到App,让你自己的代码处理通知。
你的PHP代码同时发送了notification和data字段,后台时系统优先处理notification字段,导致自定义配置失效。下面是两种解决方案,推荐第一种更可靠的方式:
方案一:改用纯Data消息,统一前后台通知逻辑
这种方式下,无论App在前台还是后台,FCM都会把消息传递到你的FirebaseMessagingService,让App自己处理通知,这样振动、图标等配置就能统一生效。
1. 修改PHP推送代码
移除notification字段,只保留data字段,把通知需要的标题、内容都放在data里:
function send_notification ($token, $message, $Raum, $Notruf) { $url = 'https://fcm.googleapis.com/fcm/send'; // 只保留data字段,把通知内容都放在这里 $fields = array( 'to' => $token, 'data' => array( 'title' => '紧急通知', // 可以自定义通知标题 'body' => "Raum ".$Raum.", Notruf ".$Notruf, 'message' => $message ) ); $headers = array ( 'Authorization:key = (HERE IS MY AUTH KEY)', 'Content-Type: application/json' ); $ch = curl_init (); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields)); $result = curl_exec($ch); if ($result == FALSE) { die ('Curl failed: ' . curl_error($ch)); } curl_close($ch); return $result; }
2. 实现FirebaseMessagingService
创建一个继承自FirebaseMessagingService的类,用来接收所有FCM消息(包括后台),然后调用你的MyNotificationManager展示通知:
public class MyFirebaseMessagingService extends FirebaseMessagingService { @Override public void onMessageReceived(RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); // 从data中取出通知内容 String title = remoteMessage.getData().get("title"); String body = remoteMessage.getData().get("body"); // 调用自定义通知管理器展示通知 MyNotificationManager.getInstance(this).displayNotification(title, body); } }
3. 在Manifest中注册服务
在AndroidManifest.xml里添加这个服务的注册,确保FCM能找到它:
<application ...> <!-- 其他组件 --> <service android:name=".MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service> </application>
方案二:在Notification字段中添加系统级配置
如果你坚持要保留notification字段,可以在PHP的notification里直接指定振动、图标等参数,让系统后台展示时使用这些配置:
'notification' => array( 'body' => "Raum ".$Raum.", Notruf ".$Notruf, 'icon' => "sirenlight", // 这里是drawable资源的名称(不带扩展名),必须符合通知图标规范 'vibrate' => array(0, 5000, 100, 5000, 100, 5000, 100, 5000, 100, 5000, 100, 5000), 'sound' => "default" // 可选:添加默认通知声音 )
⚠️ 注意:这种方式下,App前台时可能会收到两次通知(系统一次,你的代码一次),需要额外处理重复通知的问题;另外通知图标必须是白色透明背景的符合Android规范的图标,否则系统会自动替换成默认图标,导致显示异常。
额外注意事项
- 通知图标规范:Android要求通知图标必须是白色图形+透明背景,否则在Android 8.0+的系统上会显示异常,建议你检查
R.drawable.sirenlight是否符合这个要求。 - 通知渠道:你的代码里用了
Constants.CHANNEL_ID,确保已经在App启动时创建了对应的通知渠道,并且渠道的振动、声音等配置是开启的,否则Android 8.0+系统可能会限制通知的振动和声音。
内容的提问来源于stack exchange,提问作者Mario0933




