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

如何在Swift中使用.p8文件生成APNS授权令牌?

APNS设备间通信相关问题解决方案

一、Swift中基于.p8文件生成APNS授权令牌(无需依赖OpenSSL)

可以直接使用Apple原生的CryptoKit框架实现,完全不需要调用openssl命令行,避免跨平台依赖问题,适合多国部署的应用。以下是完整实现代码:

import CryptoKit
import Foundation

func generateAPNSToken(teamID: String, keyID: String, p8PrivateKeyData: Data) throws -> String {
    // 解析.p8格式的ECDSA私钥
    guard let privateKey = try? P256.Signing.PrivateKey(pemRepresentation: String(decoding: p8PrivateKeyData, as: UTF8.self)) else {
        throw NSError(domain: "APNS", code: -1, userInfo: [NSLocalizedDescriptionKey: "加载P8私钥失败"])
    }
    
    // 构造JWT Header
    let header = [
        "alg": "ES256",
        "kid": keyID
    ]
    let headerData = try JSONSerialization.data(withJSONObject: header)
    let base64Header = base64URLEncode(data: headerData)
    
    // 构造JWT Payload(有效期1小时,符合APNS要求)
    let currentTime = Int(Date().timeIntervalSince1970)
    let payload = [
        "iss": teamID,
        "iat": currentTime,
        "exp": currentTime + 3600
    ]
    let payloadData = try JSONSerialization.data(withJSONObject: payload)
    let base64Payload = base64URLEncode(data: payloadData)
    
    // 生成签名输入串
    let signingInput = "\(base64Header).\(base64Payload)"
    guard let signingInputData = signingInput.data(using: .utf8) else {
        throw NSError(domain: "APNS", code: -2, userInfo: [NSLocalizedDescriptionKey: "签名输入转换为数据失败"])
    }
    
    // 生成ECDSA签名并编码
    let signature = try privateKey.signature(for: signingInputData)
    let base64Signature = base64URLEncode(data: signature.rawRepresentation)
    
    // 组合成最终的JWT令牌
    return "\(base64Header).\(base64Payload).\(base64Signature)"
}

// 辅助函数:实现JWT要求的Base64URL编码
private func base64URLEncode(data: Data) -> String {
    return data.base64EncodedString()
        .replacingOccurrences(of: "+", with: "-")
        .replacingOccurrences(of: "/", with: "_")
        .replacingOccurrences(of: "=", with: "")
}

// 使用示例
do {
    let teamID = "你的团队ID"
    let keyID = "你的P8密钥ID"
    guard let p8Path = Bundle.main.path(forResource: "AuthKey", ofType: "p8"),
          let p8Data = try? Data(contentsOf: URL(fileURLWithPath: p8Path)) else {
        fatalError("无法加载P8密钥文件")
    }
    let token = try generateAPNSToken(teamID: teamID, keyID: keyID, p8PrivateKeyData: p8Data)
    print("APNS授权令牌: \(token)")
} catch {
    print("生成令牌失败: \(error.localizedDescription)")
}

这段代码的核心是利用CryptoKit解析.p8私钥,生成符合APNS要求的JWT格式授权令牌,全程不依赖任何外部命令行工具。

二、通过AWS或Firebase实现设备间APNS通信

AWS方案

可以使用AWS Pinpoint服务实现:

  • 客户端将APNS设备令牌注册到Pinpoint项目中
  • 发送设备间消息时,调用Pinpoint的推送API,指定目标设备的令牌即可
  • Pinpoint会自动处理APNS授权令牌的生成、签名和请求发送,无需自行维护相关逻辑

Firebase方案

Firebase Cloud Messaging (FCM)支持跨平台设备间通信,包括APNS:

  • iOS客户端集成FCM SDK,将APNS设备令牌关联到Firebase实例ID
  • 发送消息时,通过FCM API指定目标设备的Firebase实例ID,FCM会自动将消息转发到APNS
  • FCM负责处理APNS的令牌管理、签名和推送流程,大幅简化开发工作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 05:32:46