首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 綜合知識

PHP 实现 iOS 消息推送(APNs)服务端完整指南

     編輯:PHP 綜合知識

前置准备

  1. Device Token:iOS 设备注册推送时返回的 64 位十六进制字符串(含空格需去除)。
  2. CK.pem 证书:从 Apple Developer 导出的 .p12 转换而来,含客户端证书与私钥。
    openssl pkcs12 -in cert.p12 -out ck.pem -nodes -clcerts
  3. Passphrase:导出 .p12 时设置的密码(如无则留空)。

核心推送脚本 testpush.php

<?php
// ===== 配置区 =====
$deviceToken = '6ad7b13fb05e6137a46a60ea421e50164b701671cc176f7033bb9ef438a8aef9'; // 去除空格
$passphrase  = 'jetson';                       // 证书密码
$message     = 'A test message!';              // 推送文案
$badge       = 4;                              // 角标数字
$sound       = 'Duck.wav';                     // 提示音文件名(需打包在 App 中)
$isSandbox   = true;                           // true=沙箱/开发环境,false=生产环境
// ===================

// 1. 构建 APNs Payload
$body = [
    'aps' => [
        'alert' => $message,
        'badge' => $badge,
        'sound' => $sound,
    ],
    // 可扩展自定义字段
    'custom_key' => 'custom_value',
];
$payload = json_encode($body);

// 2. 创建 SSL 上下文
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);

// 3. 连接 APNs 网关
$gateway = $isSandbox
    ? 'ssl://gateway.sandbox.push.apple.com:2195'
    : 'ssl://gateway.push.apple.com:2195';

$fp = stream_socket_client($gateway, $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx);
if (!$fp) {
    exit("连接失败: $err $errstr\n");
}
echo "连接成功\n";

// 4. 组装二进制协议包 (APNs 二进制协议格式)
// Command(1) | Token Length(2) | Token(32) | Payload Length(2) | Payload
$token = pack('H*', str_replace(' ', '', $deviceToken));
$msg = chr(0) . pack('n', 32) . $token . pack('n', strlen($payload)) . $payload;

// 5. 发送
fwrite($fp, $msg);
echo "发送完成: $payload\n";

fclose($fp);
?>

关键点解析

环节说明
Payload 大小APNs 限制 4KB (iOS 8+) / 2KB (旧版),超长会被拒收。
Token 格式必须为 64 位十六进制,去除空格后用 pack('H*', ...) 转二进制。
证书路径local_cert 指向 ck.pem 绝对路径,确保 PHP 进程可读。
持久连接生产环境建议使用 STREAM_CLIENT_PERSISTENT 复用连接,减少握手开销。
错误处理APNs 不返回即时响应,需另行部署 Feedback Service 或使用 HTTP/2 API 获取错误码。

进阶:HTTP/2 版 APNs (推荐)

Apple 2016 年推出基于 HTTP/2 的新 API,支持多路复用、即时响应、JWT 认证(无需证书文件)。PHP 可用 curl (>=7.46) 或 swoole/http2-client 实现。

<?php
// 简易 HTTP/2 推送示例 (需 PHP 7.0+ & curl 7.46+)
$apnsHost = 'api.sandbox.push.apple.com'; // 生产: api.push.apple.com
$url = "https://$apnsHost/3/device/$deviceToken";

$headers = [
    'apns-topic: com.your.bundle.id',
    'apns-priority: 10', // 立即送达
    'authorization: bearer ' . getJwtToken(), // 需自行实现 JWT 签名
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
// $httpCode 200=成功, 410=Token失效, 400=Payload错误等
?>

常见坑与排查

  • 推送收不到:检查证书环境匹配(开发证书对沙箱,生产证书对生产),Token 是否对应环境。
  • 中文乱码:确保 JSON 编码未转义 Unicode (JSON_UNESCAPED_UNICODE),且文件保存为 UTF-8。
  • 连接超时:服务器需开放 2195/443 端口出站,检查防火墙/安全组。
  • 证书过期:APNs 证书有效期 1 年,需定期更新。

结语

本文提供基于 TCP 二进制协议的经典实现,适合快速验证、老项目维护。新项目强烈建议迁移至 HTTP/2 API,享受更佳的可靠性、可观测性与无证书管理优势。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved