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

使用PushSharp发送iOS推送通知失败问题求助

排查PushSharp APN推送的Invalid DeviceToken/ConnectionError问题

我来帮你一步步拆解这个问题——从错误信息和代码来看,Invalid DeviceToken是核心触发点,虽然你说已经确认Token无误,但咱们还是从几个常见的“隐形坑”入手排查:

1. 先确认DeviceToken的“绝对纯净”

有时候我们获取的DeviceToken会带有多余的格式字符,比如设备端返回的原始Token可能是<f38205ce...>,或者复制时带了空格/换行。建议在代码里先做一次强制清理:

var cleanToken = tokenId.Trim().Replace("<", "").Replace(">", "").Replace(" ", "");

再把cleanToken传入推送逻辑,避免格式问题触发Token无效错误。

2. 证书环境与APNs服务器必须严格匹配

你代码里用的是**Sandbox(沙箱)**环境,但要确保:

  • 你的.p12证书是**开发环境(Development)**生成的,不是生产环境(Production)证书
  • 测试设备上的App是用开发证书打包安装的,不是App Store/Ad Hoc包
    沙箱环境和生产环境完全隔离,证书与服务器不匹配会直接导致连接失败,进而抛出ConnectionError。可以尝试切换环境测试:把ApnsServerEnvironment.Sandbox改成Production,同时替换对应的生产证书,看是否能正常推送。

3. Payload格式有两个明显错误

你手动拼接JSON的方式容易出问题:

  • badge字段值是字符串"1",但APNs要求这个字段必须是数字类型
  • 字符串拼接时的转义错误:" Title " + message + \",\"body\"这里的引号转义混乱,会导致Payload格式无效

建议改用JObject直接构建Payload,彻底避免手动拼接的错误:

var payload = new JObject(
    new JProperty("aps", new JObject(
        new JProperty("alert", new JObject(
            new JProperty("title", $"Title {message}"),
            new JProperty("body", $"Body {message}")
        )),
        new JProperty("badge", 1) // 注意这里是数字,不是字符串
    ))
);

4. PushSharp版本的兼容性问题

PushSharp已经多年没有维护了(最后一次更新是2016年),而Apple的APNs协议早已升级到HTTP/2,旧版本的PushSharp可能仍在使用过时的二进制协议,这会导致连接被APNs服务器拒绝。

如果可以的话,建议更换更活跃的库,比如:

  • ApnsClient(专门针对APNs的轻量库)
  • Microsoft.Azure.NotificationHubs(微软官方的推送服务,支持APNs)

如果一定要继续用当前版本,确保你的项目启用了TLS 1.2及以上(Apple要求的最低加密版本),可以在代码开头添加:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;

5. 证书完整性与密码验证

  • 确认.p12证书的密码"BrumbySolution99"完全正确:可以双击证书文件,输入密码尝试导入到本地证书存储,验证是否能正常导入
  • 确保证书包含完整的证书链:导出证书时要选择“包含所有证书路径中的证书”,如果只导出了个人证书,APNs服务器会因为证书链不完整拒绝连接

修复后的示例代码

把上面的优化点整合后,代码大概是这样:

public void SendAppleNotification(string tokenId, string message)
{
    // 强制启用TLS 1.2+
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;

    byte[] appleCert = null;
    try
    {
        appleCert = File.ReadAllBytes("F:\\Dev\\ap.p12");
        System.Diagnostics.Debug.WriteLine("OK LECTURE APPLE CERT");
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("Exception lecture: " + ex.Message);
        return; // 证书加载失败直接退出
    }

    // 清理DeviceToken
    var cleanToken = tokenId.Trim().Replace("<", "").Replace(">", "").Replace(" ", "");

    // 确认环境与证书匹配
    var config = new ApnsConfiguration(ApnsConfiguration.ApnsServerEnvironment.Sandbox, appleCert, "BrumbySolution99");
    var apnsBroker = new ApnsServiceBroker(config);

    // 优化错误日志,更容易定位问题
    apnsBroker.OnNotificationFailed += (notification, aggregateEx) =>
    {
        aggregateEx.Handle(ex =>
        {
            if (ex is ApnsNotificationException notificationException)
            {
                System.Diagnostics.Debug.WriteLine($"Apple Notification Failed: ID= {notificationException.Notification.Identifier} Code= {notificationException.ErrorStatusCode}");
                System.Diagnostics.Debug.WriteLine($"Inner Error: {notificationException.InnerException?.Message}");
            }
            else if (ex is ApnsConnectionException connectionEx)
            {
                System.Diagnostics.Debug.WriteLine($"APNs Connection Failed: {connectionEx.Message}");
            }
            else
            {
                System.Diagnostics.Debug.WriteLine($"Unknown Error: {ex.ToString()}");
            }
            return true;
        });
    };

    apnsBroker.OnNotificationSucceeded += (notification) =>
    {
        System.Diagnostics.Debug.WriteLine("APPLE NOTIFICATION SENT");
    };

    apnsBroker.Start();

    // 用JObject构建正确的Payload
    var payload = new JObject(
        new JProperty("aps", new JObject(
            new JProperty("alert", new JObject(
                new JProperty("title", $"Title {message}"),
                new JProperty("body", $"Body {message}")
            )),
            new JProperty("badge", 1)
        ))
    );

    apnsBroker.QueueNotification(new ApnsNotification
    {
        DeviceToken = cleanToken,
        Payload = payload
    });

    // 等待所有推送任务完成后再停止Broker
    apnsBroker.Stop(true);
}

额外排查建议

  • 确保测试设备在线,并且已经授予App推送通知权限
  • 检查服务器防火墙,确认可以访问沙箱服务器gateway.sandbox.push.apple.com:2195和反馈服务器feedback.sandbox.push.apple.com:2196

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 04:09:06