Android端FCM通知接收失败(控制台显示送达成功)及云函数咨询
解决FCM通知显示送达但收不到+数据库触发通知的问题
我来帮你搞定这个问题!首先咱们先把你的云函数补全并优化,然后再排查收不到通知的常见坑点。
完整的云函数代码
你原来的代码不完整,我给你写了一个可以直接运行的版本,专门针对/published节点新增数据时触发通知:
'use strict'; const functions = require('firebase-functions'); const admin = require('firebase-admin'); // 初始化Admin SDK,最新写法不需要额外参数 admin.initializeApp(); exports.sendNotification = functions.database.ref('/published/{msg_id}') .onCreate(async (snapshot, context) => { // 用onCreate代替onWrite,只在新增文章时触发,避免修改/删除时误发 try { // 1. 获取刚发布的文章数据 const newPost = snapshot.val(); // 兜底处理,防止标题/内容为空 const postTitle = newPost.title || '新文章发布啦!'; const postContent = newPost.content || '点击查看最新内容'; // 2. 从数据库获取所有用户的FCM令牌 // 假设你在/users节点存储了每个用户的fcmToken字段 const usersSnapshot = await admin.database().ref('/users').once('value'); const users = usersSnapshot.val(); const validTokens = []; if (users) { // 遍历所有用户,收集有效的令牌 Object.values(users).forEach(user => { if (user.fcmToken) { validTokens.push(user.fcmToken); } }); } if (validTokens.length === 0) { console.log('没有可用的FCM令牌,跳过通知发送'); return null; } // 3. 构建通知内容 const payload = { notification: { title: postTitle, body: postContent, // 注意:如果是Flutter项目,这个字段必须设为FLUTTER_NOTIFICATION_CLICK // 原生Android/iOS根据自己的需求调整 click_action: 'FLUTTER_NOTIFICATION_CLICK' }, data: { // 可选:传递额外数据,比如文章ID,方便客户端跳转 postId: context.params.msg_id, title: postTitle } }; // 4. 批量发送通知(Firebase推荐的高效方式) const sendResult = await admin.messaging().sendMulticast({ tokens: validTokens, notification: payload.notification, data: payload.data }); // 5. 打印发送结果,方便排查问题 console.log(`成功发送 ${sendResult.successCount} 条通知,失败 ${sendResult.failureCount} 条`); // 可选:清理无效令牌(用户卸载APP后令牌会失效) const failedTokens = []; sendResult.responses.forEach((resp, index) => { if (!resp.success) { failedTokens.push(validTokens[index]); } }); if (failedTokens.length > 0) { console.log('无效的FCM令牌:', failedTokens); // 这里可以加逻辑删除数据库里的无效令牌,比如: // Object.keys(users).forEach((userId, index) => { // if (failedTokens.includes(users[userId].fcmToken)) { // admin.database().ref(`/users/${userId}/fcmToken`).remove(); // } // }); } return null; } catch (error) { console.error('发送通知出错:', error); return null; } });
代码关键点说明
- 用
onCreate替代onWrite:onWrite会在节点新增、修改、删除时都触发,而你只需要发布新文章时发通知,onCreate更精准,避免不必要的触发。 - 令牌收集逻辑:必须确保你的
/users节点里存储了每个用户的FCM令牌(用户登录后要把设备的令牌上传到数据库),这是发送批量通知的前提。 - 通知格式适配:
click_action字段对Flutter项目至关重要,原生Android/iOS要根据自己的通知点击逻辑调整。 - 批量发送优化:用
sendMulticast代替循环发送单个通知,效率更高,还能直接获取成功/失败统计。
排查“控制台显示送达但收不到通知”的常见原因
- 无效令牌:用户卸载APP、清除数据或设备重置后,令牌会失效。上面的代码已经帮你记录了失败的令牌,你可以定期清理数据库里的无效令牌。
- 前台通知不显示:如果APP在前台,默认可能不会弹出通知。比如:
- Android需要创建Notification Channel,并且配置前台通知的显示逻辑。
- Flutter需要用
flutter_local_notifications插件处理前台通知的展示。
- 推送权限未开启:iOS必须用户允许推送通知,Android 13+需要申请
POST_NOTIFICATIONS权限,要确保客户端已经请求并获取了权限。 - 客户端FCM配置错误:检查Android的
google-services.json或iOS的GoogleService-Info.plist是否配置正确,客户端初始化FCM时是否有报错。 - 通知内容问题:如果
title或body为空,或者click_action设置错误,可能导致通知无法正常显示。 - 云函数权限问题:默认情况下Functions的服务账号有发送FCM的权限,但如果手动修改过IAM权限,要确保账号有
firebase.messaging.send权限。
测试建议
- 先测试单个令牌:在代码里临时写一个固定的有效令牌,发送测试通知,确认能收到后再批量发送。
- 查看云函数日志:在Firebase控制台的Functions页面查看日志,看是否有错误信息(比如令牌为空、发送失败的具体原因)。
- 客户端日志:在设备上查看FCM相关的日志,确认是否有接收通知的记录。
内容的提问来源于stack exchange,提问作者user3792429
相关产品推荐
相关产品推荐

