Firebase Cloud Function推送至iOS设备的通知无声音问题
问题:iOS设备接收FCM推送通知无声音
问题详情
通过Node.js 20开发Firebase Cloud Function,使用FCM向Swift应用的iOS设备推送通知,设备可成功接收通知,但无论配置自定义声音还是payload中的default声音,均无提示音。直接通过Firebase控制台发送测试通知时,iOS默认通知音可正常播放。
已排查项
- 应用已获取正确的通知权限,控制台推送有声音证明权限无问题。
相关代码
index.js
// Import the Firebase SDK for Google Cloud Functions. const functions = require('firebase-functions'); // Import and initialize the Firebase Admin SDK. const admin = require('firebase-admin'); admin.initializeApp(); // Sends notifications to all users when a new message is posted. exports.sendNotifications = functions.firestore.document('CustomersWithoutBooking/{messageId}').onCreate( async (snapshot) => { // Notification details. const text = snapshot.data().text; const payload = { notification: { title: `Dropin trenger hjelp !!`, body: `Kunde står i resepsjonen og trenger hjelp. Husk å markere at du har tatt kunden`, }, android: { notification: { sound: 'default', // Android default sound } }, apns: { headers: { 'apns-priority': '10', // High priority for immediate delivery }, payload: { aps: { alert: { title: `Dropin trenger hjelp !!`, body: `Kunde står i resepsjonen og trenger hjelp. Husk å markere at du har tatt kunden`, }, sound: 'default', //'serious-strike.m4r', // Ensure the sound key is properly set for iOS contentAvailable: true, } } } }; // Fetch the device tokens from 'Behandlere' collection. const allTokensSnapshot = await admin.firestore().collection('Behandlere').get(); const tokens = []; // Get the list of device tokens. // Collect all the PushIDs from documents. allTokensSnapshot.forEach((doc) => { const data = doc.data(); if (data.PushID && Array.isArray(data.PushID)) { tokens.push(...data.PushID); // Push all tokens into the array } }); if (tokens.length > 0) { // Send notifications to all tokens using sendEachForMulticast. const responses = await admin.messaging().sendEachForMulticast({ tokens: tokens, notification: payload.notification, }); // Cleanup invalid tokens after sending notifications await cleanupTokens(responses, tokens); functions.logger.log('Notifications have been sent and tokens cleaned up.'); } } ); // Cleans up the tokens that are no longer valid. async function cleanupTokens(response, tokens) { const tokensDelete = []; response.responses.forEach((result, index) => { const error = result.error; if (error) { functions.logger.error('Failure sending notification to', tokens[index], error); if (error.code === 'messaging/invalid-registration-token' || error.code === 'messaging/registration-token-not-registered') { const deleteTask = admin.firestore().collection('fcmTokens').doc(tokens[index]).delete(); tokensDelete.push(deleteTask); } } }); await Promise.all(tokensDelete); }
package.json
{ "name": "friendlychat-codelab", "description": "Firebase SDK for Cloud Functions codelab", "dependencies": { "@google-cloud/vision": "^3.0.0", "firebase-admin": "^11.10.0", "firebase-functions": "^4.4.0", "util": "^0.12.4" }, "devDependencies": { "eslint": "^7.23.0", "eslint-plugin-promise": "^4.3.1" }, "engines": { "node": "20" }, "private": true }
解决方案
问题核心是发送通知时仅传递了payload.notification,未包含apns和android的配置信息,导致iOS设备无法读取到声音设置。
修改sendEachForMulticast的参数,将完整的payload传入即可:
if (tokens.length > 0) { // Send notifications to all tokens using sendEachForMulticast. const responses = await admin.messaging().sendEachForMulticast({ tokens: tokens, ...payload, // 展开完整的payload配置,包含notification、android、apns }); // Cleanup invalid tokens after sending notifications await cleanupTokens(responses, tokens); functions.logger.log('Notifications have been sent and tokens cleaned up.'); }
也可以明确指定各平台配置:
const responses = await admin.messaging().sendEachForMulticast({ tokens: tokens, notification: payload.notification, android: payload.android, apns: payload.apns, });
若使用自定义声音,额外确认:
- 音频文件格式为
.m4r - 文件已添加到iOS项目中,且在Xcode中勾选了对应的Target Membership
- payload中指定的文件名与实际文件名完全一致(注意大小写)
内容的提问来源于stack exchange,提问作者BluE_MoOn
相关产品推荐
相关产品推荐

