基于C#在.NET Framework 4.0中使用APNS推送无接收问题咨询
问题根因排查
- 目标服务器地址配置错误:代码中
TcpClient ("Production", port)传入的是字符串常量"Production"而非有效的APNS服务域名,请求根本没有发送到苹果的推送服务器。 - 协议与端口不匹配:你使用的是苹果已废弃的旧版二进制APNS协议,该协议对应的生产环境域名是
gateway.push.apple.com、端口为2195,开发环境域名是gateway.sandbox.push.apple.com、端口为2195;当前代码用的443端口是新版HTTP/2 APNS接口的端口,二进制格式的请求发到443端口会被苹果服务直接丢弃,不会返回错误信息,因此你看不到异常。 - 证书加载逻辑存在缺陷:.NET Framework 4.0原生对PEM格式证书的兼容性较差,加载PEM时很可能仅读取了公钥未加载私钥,导致TLS认证未通过;同时你没有读取服务端返回的错误数据,无法感知到认证失败的情况。
- 缺少错误校验逻辑:旧版二进制APNS协议在推送失败时会返回6字节的错误数据包,你写完请求数据后直接关闭连接,没有读取服务端返回内容,所有错误都被静默忽略。
修复方案
- 修正服务器地址与端口
根据你使用的环境替换TcpClient的参数:
- 生产环境:
new TcpClient("gateway.push.apple.com", 2195) - 开发环境:
new TcpClient("gateway.sandbox.push.apple.com", 2195)
更换证书格式为P12
从苹果开发者后台导出带私钥的P12格式证书,替换现有的PEM证书加载逻辑,.NET Framework 4.0对P12/PFX格式的证书兼容性更好,不会出现私钥丢失的问题。添加错误读取逻辑
写完推送数据后不要立刻关闭连接,先读取SslStream返回的错误信息,确认推送结果。校验基础参数
- 确认device token和当前证书环境匹配:生产证书不能使用开发环境生成的device token,反之亦然
- 确认payload格式符合APNS规范,必须包含
aps根节点,通知相关配置都放在aps节点内
修正后参考代码
int port = 2195; var payload = JsonHelper.Serialize(notification); // 替换为自己的P12证书路径 String certificatePath = "apns.p12"; X509Certificate2 clientCertificate = new X509Certificate2(System.IO.File.ReadAllBytes(certificatePath), "密码", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); X509Certificate2Collection certificatesCollection = new X509Certificate2Collection(clientCertificate); // 开发环境替换为gateway.sandbox.push.apple.com TcpClient client = new TcpClient("gateway.push.apple.com", port); SslStream sslStream = new SslStream(client.GetStream(), false, new RemoteCertificateValidationCallback(ValidateServerCertificate), null); try { sslStream.AuthenticateAsClient("gateway.push.apple.com", certificatesCollection, (SslProtocols)3072, false); MemoryStream memoryStream = new MemoryStream(); BinaryWriter writer = new BinaryWriter(memoryStream); writer.Write((byte)0); writer.Write((byte)0); writer.Write((byte)32); writer.Write(HexStringToByteArray(deviceToken.ToUpper())); writer.Write((byte)0); writer.Write((byte)payload.Length); byte[] b1 = System.Text.Encoding.UTF8.GetBytes(payload); writer.Write(b1); writer.Flush(); byte[] array = memoryStream.ToArray(); sslStream.Write(array); sslStream.Flush(); // 新增:读取服务端返回的错误信息 byte[] readBuffer = new byte[6]; int readBytes = sslStream.Read(readBuffer, 0, readBuffer.Length); if (readBytes > 0) { byte status = readBuffer[1]; // status=0为成功,其他值对应不同错误,可自行对照苹果APNS旧版协议文档排查 } } catch(Exception ex) { // 新增异常捕获,记录报错信息 } finally { client.Close(); sslStream.Dispose(); }
内容的提问来源于stack exchange,提问作者vITs
相关产品推荐
相关产品推荐

