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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:34:59