Android Firebase FCM推送日志显示成功但设备未收到通知
FCM推送通知已发送但设备未接收的排查与解决
我在Android项目中通过FCM Token向目标设备推送通知,日志显示应用运行正常且已发送通知,但设备始终未收到通知。
补充信息
- 已开启应用的通知权限(2台实体设备+1台模拟器均开启,无效)
- FCM Token有效,通过Firebase控制台发送测试通知可成功接收
Realtime Database结构
USER节点下存储用户的lat、lng、fcmToken等核心字段(原提问附带3张结构截图)
相关代码
UserActivity中获取并写入FCM Token
FirebaseMessaging.getInstance().getToken() .addOnCompleteListener(new OnCompleteListener<String>() { @Override public void onComplete(@NonNull Task<String> task) { if (task.isSuccessful()) { String fcmToken = task.getResult(); writeNewUserToDatabase(mAuth.getUid(), emailET.getText().toString(), fullNameET.getText().toString(), lat, lng, fcmToken); } else { Log.d("MyApp", "Failed to get FCM token: " + task.getException().getMessage()); } } });
AdminActivity中查找附近用户的方法
private void findNearbyUsers(Alert alert) { DatabaseReference usersRef = FirebaseDatabase.getInstance().getReference().child("USER"); usersRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { Set<String> nearbyTokens = new HashSet<>(); for (DataSnapshot userSnapshot : snapshot.getChildren()) { double userLat = userSnapshot.child("lat").getValue(Double.class); double userLng = userSnapshot.child("lng").getValue(Double.class); String userToken = userSnapshot.child("fcmToken").getValue(String.class); // 计算用户与告警点的距离 float[] results = new float[1]; Location.distanceBetween(alert.getLat(), alert.getLng(), userLat, userLng, results); // 判断是否在1公里范围内 if (results[0] <= 1000) { nearbyTokens.add(userToken); } } // 向附近用户推送通知 sendNotificationToUsers(nearbyTokens, alert); } @Override public void onCancelled(@NonNull DatabaseError error) { Log.e("LoG", "Failed to read value.", error.toException()); } }); }
发送通知的方法
private void sendNotificationToUsers(Set<String> tokens, Alert alert) { // 创建通知渠道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("CHANNEL_ID", "Channel Name", NotificationManager.IMPORTANCE_HIGH); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } // 构建通知内容 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "CHANNEL_ID") .setSmallIcon(R.drawable.ic_launcher_background) .setContentTitle("Alert nearby!") .setContentText("An alert has been verified near your location.") .setPriority(NotificationCompat.PRIORITY_HIGH) .setAutoCancel(true); // 创建点击通知打开应用的Intent Intent intent = new Intent(this, AdminActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE); builder.setContentIntent(pendingIntent); // 后台线程向每个用户发送通知 new Thread(() -> { for (String token : tokens) { if (token == null || token.isEmpty()) { return; } Log.d("FCM", "Sending notification to FCM token(sendMessage): " + token); Log.d("FCM", "Notification title: " + alert.getTitle()); Log.d("FCM", "Notification message: " + alert.getDescription()); FirebaseMessaging.getInstance().send(new RemoteMessage.Builder(token) .setMessageId(UUID.randomUUID().toString()) .addData("title", alert.getTitle()) .addData("message", alert.getDescription()) .build()); } }).start(); }
日志输出(点击按钮后)
D/FCM: Sending notification to FCM token(sendMessage): cly-c8S9SpSHsd6_pIrVDw:APA91bGkqMK5AYCJyWad_1cQlDRjOaqVSO... Notification title: 1@flood D/FCM: Notification message: j D/FCM: Sending notification to FCM token(sendMessage): ck3P3SCbSHurWVHZ4o8Czy:APA91bFbU66AoYwrvlM2gkdR3vtD52rT7qeJU8Ig7-ds7HKPQC4BM7ftLHeQSQca47zBHSG3UQjyXsbQav2aEjK... D/FCM: Notification title: 1@flood D/FCM: Notification message: j D/FCM: Sending notification to FCM token(sendMessage): eVuZsrTWQwyElN8BhEmtC7:APA91bFXF4EBytwy158204Tav9nzqLIPwo_7HzX1K5Qgo4RjcMRTuX2ca-GG78FCpqYAt1Bp2PJngsXP4wdMtqrYRop... D/FCM: Notification title: 1@flood D/FCM: Notification message: j
问题根源及解决办法
核心问题:客户端用FirebaseMessaging.getInstance().send()发送的是纯Data消息,而非Notification消息。Firebase控制台发送的是Notification消息,系统会自动展示;但纯Data消息需要接收端手动处理并构建系统通知。
解决步骤
创建自定义FirebaseMessagingService
新建类继承FirebaseMessagingService,重写onMessageReceived处理Data消息:public class MyFirebaseMessagingService extends FirebaseMessagingService { @Override public void onMessageReceived(@NonNull RemoteMessage remoteMessage) { super.onMessageReceived(remoteMessage); // 提取Data消息中的标题和内容 String title = remoteMessage.getData().get("title"); String message = remoteMessage.getData().get("message"); // 展示系统通知 showNotification(title, message); } private void showNotification(String title, String message) { // 创建通知渠道(适配Android O+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("CHANNEL_ID", "Alert Notifications", NotificationManager.IMPORTANCE_HIGH); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } // 构建通知跳转Intent Intent intent = new Intent(this, UserActivity.class); // 跳转至用户端页面,而非Admin页面 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE); // 构建通知 NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "CHANNEL_ID") .setSmallIcon(R.drawable.ic_launcher_foreground) // 使用符合规范的图标,避免通知不显示 .setContentTitle(title) .setContentText(message) .setPriority(NotificationCompat.PRIORITY_HIGH) .setAutoCancel(true) .setContentIntent(pendingIntent); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.notify((int) System.currentTimeMillis(), builder.build()); } }在AndroidManifest.xml中注册Service
在<application>标签内添加:<service android:name=".MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>优化sendNotificationToUsers方法
- 移除发送端创建通知渠道的代码:通知渠道应在接收端创建
- 修复循环逻辑:空token时用
continue而非return,避免中断后续发送// 原代码 if (token == null || token.isEmpty()) { return; } // 修改为 if (token == null || token.isEmpty()) { continue; }
额外注意事项
- 确保通知图标
setSmallIcon使用非透明、符合系统规范的图标 - 发送端与接收端包名必须一致,否则FCM消息无法投递
- 测试时覆盖应用前台、后台、杀死三种状态,验证通知展示逻辑
内容的提问来源于stack exchange,提问作者enolic
相关产品推荐
相关产品推荐

