如何在SwiftUI应用中通过Firebase直接发送推送通知(无需Firebase官网)
在SwiftUI应用内通过Firebase发送推送通知(无需依赖官网)
可以实现,但不能直接在iOS客户端调用Firebase Cloud Messaging(FCM)的推送接口——因为FCM要求请求必须携带你的Firebase项目服务器密钥,把密钥硬编码在客户端会导致严重安全风险(任何人反编译app就能拿到密钥,滥用你的推送服务)。正确的做法是通过后端服务(自己搭建的服务器或Firebase Cloud Functions)中转推送请求。
你的现有代码问题分析
你提供的示例代码存在几个关键问题导致无法工作:
- 请求URL错误:你使用的
https://NOT_LETTING_SERVER_GET_SHOWN.json不是FCM的合法接口,FCM官方推送接口为https://fcm.googleapis.com/fcm/send,但该接口不能直接在客户端调用。 - 请求体不完整:FCM推送需要包含
notification或data字段定义通知内容,你只传递了token,缺少必要的通知信息。 - 缺少认证头:调用FCM接口必须在请求头中添加
Authorization: key=你的服务器密钥,而这个密钥绝对不能暴露在客户端代码中。
具体解决方案
方案一:使用Firebase Cloud Functions中转(推荐)
这是最便捷的方式,无需自行搭建服务器:
1. 编写Cloud Functions(Node.js)
在你的Firebase项目中创建云函数,负责接收客户端请求并调用FCM接口发送推送:
const functions = require("firebase-functions"); const admin = require("firebase-admin"); admin.initializeApp(); exports.sendPushNotification = functions.https.onCall(async (data, context) => { // 可选:验证用户身份,防止恶意调用 if (!context.auth) { throw new functions.https.HttpsError("unauthenticated", "用户未登录"); } const { token, title, body } = data; if (!token || !title || !body) { throw new functions.https.HttpsError("invalid-argument", "缺少必要参数"); } const message = { notification: { title: title, body: body }, token: token }; try { const response = await admin.messaging().send(message); return { success: true, messageId: response }; } catch (error) { throw new functions.https.HttpsError("internal", error.message); } });
2. 修改SwiftUI客户端代码
调用上述云函数发送推送,无需处理FCM的认证和接口细节:
import SwiftUI import FirebaseFunctions struct ContentView: View { @EnvironmentObject var appDelegate: AppDelegate var body: some View { Button(action: sendPushNotification) { Text("Send Push Notification") } } func sendPushNotification() { guard let token = appDelegate.fcmToken else { print("FCM token not available") return } let functions = Functions.functions() // 开发环境可使用本地模拟器:functions.useEmulator(host: "localhost", port: 5001) functions.httpsCallable("sendPushNotification").call([ "token": token, "title": "测试推送", "body": "这是从SwiftUI应用内发送的推送通知" ]) { result, error in if let error = error as NSError? { print("云函数调用失败: \(error.localizedDescription)") return } if let response = result?.data as? [String: Any] { print("推送发送成功: \(response)") } } } }
方案二:自行搭建后端服务
如果你已有自己的服务器,可以在后端实现FCM推送逻辑,客户端仅需向你的后端发送请求:
后端示例(Node.js)
const axios = require('axios'); const sendFCMPush = async (token, title, body) => { const serverKey = "你的Firebase服务器密钥"; // 从Firebase控制台获取 const url = "https://fcm.googleapis.com/fcm/send"; const message = { notification: { title, body }, token: token }; try { await axios.post(url, message, { headers: { "Content-Type": "application/json", "Authorization": `key=${serverKey}` } }); return true; } catch (error) { console.error("推送失败:", error.response.data); return false; } };
客户端修改
将原sendPushNotification方法改为请求你的后端接口:
func sendPushNotification() { guard let token = appDelegate.fcmToken else { print("FCM token not available") return } let urlString = "https://你的后端域名/api/send-push" guard let url = URL(string: urlString) else { return } var request = URLRequest(url: url) request.httpMethod = "POST" request.setValue("application/json", forHTTPHeaderField: "Content-Type") let body: [String: Any] = [ "token": token, "title": "测试推送", "body": "从SwiftUI应用发送的推送" ] request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: []) let task = URLSession.shared.dataTask(with: request) { data, response, error in if let error = error { print("请求失败: \(error.localizedDescription)") return } if let httpResponse = response as? HTTPURLResponse, httpResponse.statusCode == 200 { print("推送发送成功") } else { print("推送发送失败") } } task.resume() }
额外注意事项
- FCM Token管理:FCM Token可能过期或变化,需在
MessagingDelegate的messaging(_:didReceiveRegistrationToken:)方法中及时更新存储的Token。 - 权限处理:确保app已正确申请推送权限,同时要处理用户关闭推送权限的场景。
- 环境区分:开发阶段使用APNS沙箱环境,生产阶段切换为生产环境,确保Firebase项目配置了对应环境的APNS证书。
- 身份验证:无论是Cloud Functions还是自建后端,都建议添加用户身份验证逻辑,防止恶意调用推送接口。
内容的提问来源于stack exchange,提问作者user25626237
相关产品推荐
相关产品推荐

