PHP实现iOS推送通知失效 求适配新协议的可行代码及方案
iOS推送失效调试方案(适配APNs HTTP/2协议)
为什么需要HTTP/2?
Apple从iOS 10开始强制要求APNs推送使用HTTP/2协议,替代旧的二进制协议。HTTP/2提供更明确的错误反馈、多路复用能力,是当前唯一官方支持的推送协议,这也是你必须采用它的核心原因。
第一步:用openssl s_client命令行调试
既然服务器curl不支持SSL,先通过openssl s_client验证服务器到APNs的连通性,同时模拟推送请求:
1. 验证HTTP/2连接
执行以下命令(替换证书路径,开发环境替换为sandbox地址):
openssl s_client -connect api.push.apple.com:443 -cert /path/to/your/certificate.pem -key /path/to/your/private-key.pem -alpn h2
若连接成功,输出中会包含ALPN protocol: h2,说明服务器支持HTTP/2并能和APNs建立SSL连接。
2. 发送测试推送请求
连接成功后,在交互模式下输入以下HTTP/2请求(替换device-token、topic和推送内容):
POST /3/device/<device-token> HTTP/2 Host: api.push.apple.com apns-topic: <your-app-bundle-id> { "aps": { "alert": "测试推送", "sound": "default" } }
注:证书验证模式下无需
Authorization头,APNs会通过SSL证书识别应用。输入完后按两次回车发送请求,观察返回状态码:
- 200:推送成功
- 400/403/410等:对应具体错误,可查阅Apple官方文档定位问题
第二步:PHP调试代码(适配HTTP/2 + OpenSSL)
以下是基于PHP openssl扩展的APNs推送代码,无需依赖curl的HTTP2支持,直接通过SSL连接发送HTTP/2请求:
<?php // 配置参数 $isProduction = true; // 生产环境设为true,开发环境设为false $deviceToken = "你的设备推送token"; $bundleId = "你的App Bundle ID"; $certPath = "/path/to/your/certificate.pem"; $certPassphrase = "证书密码(无则留空)"; // 选择APNs服务器地址 $apnsHost = $isProduction ? "api.push.apple.com" : "api.sandbox.push.apple.com"; $apnsPort = 443; // 构建推送内容 $payload = json_encode([ "aps" => [ "alert" => "PHP调试测试推送", "sound" => "default" ] ]); // 初始化SSL上下文,指定HTTP/2协议 $context = stream_context_create([ "ssl" => [ "local_cert" => $certPath, "passphrase" => $certPassphrase, "verify_peer" => true, "verify_peer_name" => true, "alpn_protocols" => ["h2"] ] ]); // 建立SSL连接 $socket = stream_socket_client( "ssl://{$apnsHost}:{$apnsPort}", $errno, $errstr, 60, STREAM_CLIENT_CONNECT, $context ); if (!$socket) { die("连接失败: {$errstr} ({$errno})"); } // 构建HTTP/2请求 $request = "POST /3/device/{$deviceToken} HTTP/2\r\n"; $request .= "Host: {$apnsHost}\r\n"; $request .= "apns-topic: {$bundleId}\r\n"; $request .= "Content-Length: " . strlen($payload) . "\r\n\r\n"; $request .= $payload; // 发送请求并读取响应 fwrite($socket, $request); $response = fread($socket, 4096); echo "响应内容:\n" . $response . "\n"; // 关闭连接 fclose($socket); ?>
代码说明:
- 用
stream_socket_client建立SSL连接,通过alpn_protocols强制使用HTTP/2 - 直接构建HTTP/2格式请求,避免依赖curl的HTTP2扩展支持
- 响应中包含的HTTP状态码和错误信息,可直接用于定位问题
常见排查点
- 连接失败:检查证书路径、密码是否正确,服务器防火墙是否开放443端口出站权限
- 返回403:确认证书绑定的Bundle ID与推送
topic一致,证书是否过期 - 返回410:设备token已失效,需重新获取用户设备的推送token
内容的提问来源于stack exchange,提问作者Ondrej
相关产品推荐
相关产品推荐

