You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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消息需要接收端手动处理并构建系统通知。

解决步骤

  1. 创建自定义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());
        }
    }
    
  2. 在AndroidManifest.xml中注册Service
    在<application>标签内添加:

    <service
        android:name=".MyFirebaseMessagingService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
    
  3. 优化sendNotificationToUsers方法

    • 移除发送端创建通知渠道的代码:通知渠道应在接收端创建
    • 修复循环逻辑:空token时用continue而非return,避免中断后续发送
      // 原代码
      if (token == null || token.isEmpty()) {
          return;
      }
      // 修改为
      if (token == null || token.isEmpty()) {
          continue;
      }
      

额外注意事项

  • 确保通知图标setSmallIcon使用非透明、符合系统规范的图标
  • 发送端与接收端包名必须一致,否则FCM消息无法投递
  • 测试时覆盖应用前台、后台、杀死三种状态,验证通知展示逻辑

内容的提问来源于stack exchange,提问作者enolic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 08:55:12