0%

使用 PHP 实现 APNs

反馈请联系hertz@hertzwang.com,谢谢

参考 iOS 消息推送(VOIP)

准备

操作步骤

  1. 下载推送证书,加入到 钥匙串,并将文件改名为 aps_development.cer 放入本文件夹;
  2. 从 钥匙串 将证书导出为 p12 格式,更名为 aps_development.p12 放入本文件夹;
  3. 修改 push.php 文件中的配置;
  4. 终端执行 init.py 初始化证书;
  5. 终端执行 php push.php 发送(默认为开发环境)。

注: 执行完 python 脚本终端会输出以下内容,若没有则表示操作有误,请重新操作

Enter Import Password:
MAC verified OK
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

常见问题及解决

  1. 证书相关查看上面的 参考

  2. 不能导出 p12

    说明该证书不是这台机器颁发的,解决方案是找到那台机器拿到 p12 文件,或者重新生成证书(慎用)。

  3. SSL3_GET_SERVER_CERTIFICATE:certificate verify failed / Warning: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages: error:14094410:SSL routines:SSL3_READ_BYTES

    下载 entrust_2048_ca.cer 证书 放至本文件夹

文件说明

  • aps_development.cer

    推送证书,分 DevelopmentProduction 两种,从 开发官方下载

  • aps_development.p12

    私钥,官方下载的推送证书(aps_development.cer)加入钥匙串后导出

  • aps_cert.pem

    推送证书(aps_development.cer)的 pem 格式

  • aps_key.pem

    私钥(aps_development.p12)的 pem 格式

  • aps.pem

    合成文件,推送证书(pem 格式)和私钥(pem 格式)的合成文件

有兴可查看下面的 init.py

  • entrust_2048_ca.cer

    这个不太确认…是个CA证书,有了解的可以联系hertz@hertzwang.com

测试推送

  1. 使用网站 http://pushtry.com/
  2. Easy APNs Provider - 推送测试工具

init.py

# -*- coding: utf-8 -*-
import os

def main():
  # 将 aps_development.cer 转成 pem 格式
  os.system('openssl x509 -in aps_development.cer -inform DER -out aps_cert.pem -outform PEM')
  # 将 aps_development.p12 格式的私钥转换成 aps_key.pem
  print('请输入导出时的密码,无密码按回车继续,然后设置 PEM pass phrase\nPlease enter the password of the export, no password to press enter to continue, setting PEM pass phrase.\n')
  os.system('openssl pkcs12 -nocerts -out aps_key.pem -in aps_development.p12')
  # 合成
  os.system('cat aps_cert.pem aps_key.pem > aps.pem')
  print('证书初始化结束/The certificate initialization done.')

main()

push.php

<?php

// token:设备注册成功后 application:didRegisterForRemoteNotificationsWithDeviceToken: 中查看,去除空格
$deviceToken = '1ff8a0af52b48748c7628609a812f15d1c961df4bb04e618def369996a7e72ae';

// passphrase:私钥密码
$passphrase = 'qwe123';

// 数值:显示在 icon 上
$badge = 0;

// 环境 TRUE-开发,FALSE-正式
$devPlatform = TRUE;

// 推送信息设置
$message = '推送消息'; // 推送消息

////////////////////////////////////////////////////////////////////////////////

// 设置上下文
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'aps.pem'); // 设置证书
stream_context_set_option($ctx, 'ssl', 'cafile', 'entrust_2048_ca.cer'); // 设置CA证书
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase); // 设置私钥密码

// 打开一个 APNs 的连接,开发环境 gateway.sandbox.push.apple.com:2195 正式环境 gateway.push.apple.com:2195
$sslPath = 'ssl://gateway.sandbox.push.apple.com:2195';

if ($devPlatform == FALSE) {
    $sslPath = 'ssl://gateway.push.apple.com:2195';
}

$fp = stream_socket_client(
    $sslPath, $err,
    $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);

if (!$fp)
    exit("Failed to connect: $err $errstr" . PHP_EOL);

echo 'Connected to APNS' . PHP_EOL;

// 封装推送信息
$body['aps'] = array(
    'alert' => $message,
    'sound' => 'default',
    'badge' => $badge,
);

// 转为 JSON 格式
$payload = json_encode($body);

// 转为二进制
$msg = chr(0).pack('n', 32).pack('H*', $deviceToken).pack('n', strlen($payload)).$payload;

// 发送至 Apple 服务器
$result = fwrite($fp, $msg, strlen($msg));

if (!$result)
    echo 'Message not delivered' . PHP_EOL;
else
    echo 'Message successfully delivered' . PHP_EOL;

// 关闭连接
fclose($fp);

?>