ApnsPHP:在开发环境中可以推送通知,但在生产环境中无法推送

4

是的:这个问题有很多重复,但是没有一个答案能够解决我的问题。

我正在按照 Ali Hafizji 的 教程 学习如何使用 APNS 服务进行推送通知。

开发模式下测试 APNS:

  • 下载 aps_development.cer
  • 导出证书的私钥 (aps_development_key.p12)

然后,我使用以下命令(在终端中)将两者合并:

openssl x509 -in aps_development.cer -inform der -out aps_development.pem
openssl pkcs12 -nocerts -out aps_development_key.pem -in aps_development.p12
cat aps_development.pem aps_development_key.pem > final_aps_development.pem

使用服务器上的ApnsPHP,我可以成功地使用以下配置发送推送通知:

...
$push = new ApnsPHP_Push(ApnsPHP_Abstract::ENVIRONMENT_SANDBOX,'final_aps_development.pem');
$push->setRootCertificationAuthority('entrust_root_certification_authority.pem');
$push->setProviderCertificatePassphrase('mypassword');
...

一个小提示:我从https://github.com/jonathanrcarter/push2press中获取了entrust_root_certification_authority.pem文件,但正确的地址可能是https://www.entrust.net/downloads/binary/entrust_2048_ca.cer(它们本质上是相同的)。
在此情况下,应用程序在调试模式下运行(在设备上通过XCode运行),一切正常。
生产模式下测试APNS:
为了在生产模式下测试APNS,我为AdHoc分发存档了应用程序,并使用iPhone Configuration Utility将其安装到设备上。
对于aps_production.cer,我遵循了相同的过程以生成final_aps_production.pem文件。
结果,用于发送推送通知的PHP脚本返回了500 HTML状态码。
当然,$push生成已针对生产模式进行修改。
...
$push = new ApnsPHP_Push(ApnsPHP_Abstract::ENVIRONMENT_PRODUCTION,'final_aps_production.pem');
$push->setRootCertificationAuthority('entrust_root_certification_authority.pem');
$push->setProviderCertificatePassphrase('mypassword');
...

快速查看 /var/log/apache2/error.log 文件,可以发现问题所在:

PHP Fatal error:  Uncaught exception 'ApnsPHP_Exception' with message 'Unable to connect to 'ssl://gateway.push.apple.com:2195':  (0)' in /var/www/gettapro/mobile/ApnsPHP/Abstract.php:398\nStack trace:\n#0 /var/www/gettapro/mobile/ApnsPHP/Abstract.php(334): ApnsPHP_Abstract->_connect()\n#1  ....

搜索解决问题的方法,但并没有找到有效的结果(许多人都有此问题)。有许多不同的建议,甚至有些奇怪,比如将持有证书的目录的文件权限更改为775……但这些建议都没有对我起作用。我还尝试了在"ApnsPHP/Abstract.php"上进行更改(参见:https://github.com/duccio/ApnsPHP/issues/29), 但是也没有成功。
$streamContext = stream_context_create(array('ssl' => array(
             //'verify_peer' => isset($this->_sRootCertificationAuthorityFile),
            'cafile' => $this->_sRootCertificationAuthorityFile,
            'local_cert' => $this->_sProviderCertificateFile
        ))); 

这讨厌的ApnsPHP_Exception问题并没有消失。

当然,在测试生产模式时,我也确保使用了正确的设备APNS令牌 - 在调试和生产模式下,设备APNS令牌不同

无论如何:令牌不可能是问题,因为我的通知发送脚本甚至无法连接到ssl://gateway.push.apple.com:2195

尝试通过telnet连接ssl://gateway.push.apple.com:2195只是为了确保:连接很好。

很明显:这是一个证书问题。

1个回答

8

看起来 aps_production.cer 不应该像处理 aps_development.cer 一样处理。

现在到了RTM时刻

下载并安装证书到钥匙串中(双击aps_production.cer)。

从钥匙串访问中导出一个.p12版本的aps_production证书(设置密码)。

使用以下命令将其转换为.pem格式(此处需要输入密码):

openssl pkcs12 -in aps_production.p12 -out final_aps_production.pem -nodes

看到这里,一切开始正常工作,我又成为了一个快乐的露营者。

Jeremy 在这里给出了非常好的教程式指导,学习如何导出证书和密钥。你可以在SO上找到它。


1
你是在导出证书本身的.p12文件还是证书的密钥?这是你所说的它们不应该被类似地处理吗? - Jeremy
1
我的措辞在这里有点笨拙 - 可能两个证书都可以以同样的方式安装。在这种最后一种情况下,证书首先在钥匙串(OSX)中安装,然后与密钥一起导出。这样做会减少出错的可能性。 - Rok Jarc
2
哈!非常感谢这种简单明了的方法!对于任何遇到困难的人,只需忘记在线教程,花几分钟时间思考一下过程。如果你在这里,显然你的问题只是创建.PEM文件,而所有的教程都让它看起来像是涉及多个文件和命令。只需将Distribution Push aps_production.cer导入到钥匙串访问中,找到它并展开,以便您可以看到私钥,选择两者,“导出2个项目”为.p12文件。上传到服务器,SSH进去并在其上运行上面的openssl命令-完成!美妙极了。 - tylerl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接