APNs 消息已发送但未在 iOS 设备上接收 [英] APNs messages are delivered but not received on iOS device

查看:24
本文介绍了APNs 消息已发送但未在 iOS 设备上接收的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经建立了一个转发/调度服务,它按照 Apple 所述/推荐的方式与 APNs 保持开放连接,以防止 DoS 检测并且证书正在工作......

I have set up a forwarding / dispatch service which holds an open connection to the APNs as stated / recommended by Apple to prevent DoS detection and the certificate is working...

我连接成功并且消息发送成功,但是在iOS设备(iPhone)上没有收到消息......(?!?)发送的字节数等于fwrite返回的(字节数)数.

I am connected successfully and messages are sent successfully, but messages are not received on the iOS device (iPhone)... (?!?) The number of bytes sent are equal to the number (of bytes) fwrite returns.

最后,消息可能包含特定国家/地区的字符.APNs 如何处理?以及如何将这些字符发送到 APNs 服务器?

Finally, the messages might contain country specific characters. How the the APNs handle that? and how should this characters be sent to the APNs server?

无论有没有转发服务,我都尝试过,但没有运气.:-(

I have tried both with and without the forwarding service, but without luck. :-(

在代码片段中删除了对日志的所有调用,以避免混淆.这意味着粘贴的日志消息无法直接映射到代码片段中,但应该可以猜测"日志消息的来源.

All calls to the log are removed in the code snippets to avoid confusing. This means that the log messages pasted cannot be mapped directly into the code snippets, but it should be possible to "guess" from where log messages come.

请帮助我解决这些问题.提前致谢

Please help me regarding these issues. Thanks in advance

连接方式如下:

$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', $certPath);
stream_context_set_option($ctx, 'ssl', 'passphrase', $passPhrase);
$this->apn_link = stream_socket_client($url, $err, $errstr, 60,                                       STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, $ctx);
/* ... */

在侦听转发服务上的套接字的循环中:

Inside a loop that listens on the socket on the forwarding service:

foreach ($changed as $changed_socket) {
    while(isset($changed_socket) && socket_recv($changed_socket, $buf, 1024, 0) >= 1)
    {
        $buf = trim($buf);
        if ($buf != '') {
            $this->msg2apn($buf);
        }
    }
}
/* ... */

我进一步以这种方式发送消息:

Further I send messages in this way:

public function msg2apn($msg) {
if (isset($this->apn_link)) {
    while(!$result = fwrite($this->apn_link, $msg, strlen($msg))) {
        usleep(400000); //400 msec
    }

    if ($result) {
        fflush($this->apn_link);
        return True;
    }
}
}

发送到转发服务的消息:

Messages sent to the forwarding service:

private function send_pn_iosproxy($msg) {
    $address = IOS_APNPROXY_HOST;
    $port = IOS_APNPROXY_PORT;
    $fp = fsockopen($address,$port);
    if (!$fp) {
        elog("Connection to [".$address.":".$port."] could not be established");
        return False;
    }
    $result = fwrite($fp, $msg, strlen($msg));

    if (isset($fp)) fflush($fp);
    if (isset($fp)) fclose($fp);
    return True;
}

对于每个设备令牌,都会通过以下方式生成一条消息:

For each device token a message is generated in the following way:

$payload = '{"aps":{"alert":"'.$message['message'].'","badge" : "1","sound":"default"}}';

foreach($deviceTokens as $deviceToken) {
// Build the binary notification
$msg = chr(0) . pack('n', 32) . base64_decode($deviceToken) . pack('n',    strlen($payload)) . $payload;

// see function above
$result = $this->send_pn_iosproxy($msg);

if ($result) {
    ilog("Message delivered");
    dlog("DeviceToken[$deviceToken], Payload[$payload]");
} else {
    wlog("Message not properly delivered");
    dlog("Msg[$msg]");
    dlog("DeviceToken[$deviceToken], Payload[$payload]");
}
}

来自 logdisp 的日志消息来自转发服务,而来自日志的日志消息来自 app-/web 服务器.Web 服务器使用 127.0.0.1/localhost 连接到转发服务,因此 Web 服务器和转发服务器托管在同一台物理计算机上.

Log messages from logdisp are from the forwarding service, while log messages from the log are from the app-/web server. The web server connects to the forwarding service using 127.0.0.1/localhost hence the web server and the forwarding server is hosted on the same physical computer.

[2015-08-27 11:19:03] log.DEBUG: pn::send_pn_ios()  [] []
[2015-08-27 11:19:03] log.DEBUG: pn::send_pn_iosproxy()  [] []
[2015-08-27 11:19:03] log.INFO: Message delivered  [] []
[2015-08-27 11:19:03] logdisp.DEBUG: Client [127.0.0.1] connected [] []
[2015-08-27 11:19:03] log.DEBUG: DeviceToken[djYBbJepT8NOPKgLd5FoGOog9jxY8LcpQhCGaXAkqy0=], Payload[{"aps":{"alert":"message","badge" : "1","sound":"default"}}]  [] []
[2015-08-27 11:19:03] logdisp.DEBUG: Message buf[...{"aps":{"alert":"message","badge" : "1","sound":"default"}}] from ip[127.0.0.1]  [] []
[2015-08-27 11:19:03] log.DEBUG: pn::send_pn_iosproxy()  [] []
[2015-08-27 11:19:03] logdisp.DEBUG: dispatcher::msg2apn() [] []
[2015-08-27 11:19:03] log.INFO: Message delivered  [] []
[2015-08-27 11:19:03] logdisp.DEBUG: SUCCESS msg2apn, written[107], sent[107] [] []
[2015-08-27 11:19:03] log.DEBUG: DeviceToken[7FH3vRMfmb3qRBOaKY30GT/+82jU/6kx7RhBJq2Ihw8=], Payload[{"aps":{"alert":"message","badge" : "1","sound":"default"}}]  [] []
[2015-08-27 11:19:03] log.DEBUG: pn::send_pn_iosproxy()  [] []
[2015-08-27 11:19:03] log.INFO: Message delivered  [] []
[2015-08-27 11:19:03] log.DEBUG: DeviceToken[b+20wASQBp9lD08l1+EY3CHJjcCl1UBWNmSeI1c9ouQ=], Payload[{"aps":{"alert":"message","badge" : "1","sound":"default"}}]  [] []
[2015-08-27 11:19:03] log.DEBUG: pn::send_pn_iosproxy()  [] []
[2015-08-27 11:19:03] log.INFO: Message delivered  [] []
[2015-08-27 11:19:03] log.DEBUG: DeviceToken[Yya0lH080lz6fL2B/1UexOenBLyAJIp3zgSGgV9F5ms=], Payload[{"aps":{"alert":"message","badge" : "1","sound":"default"}}]  [] []
[2015-08-27 11:19:04] logdisp.DEBUG: Client [127.0.0.1] connected [] []
[2015-08-27 11:19:04] logdisp.DEBUG: Message buf[...{"aps":{"alert":"message","badge" : "1","sound":"default"}}] from ip[127.0.0.1]  [] []
[2015-08-27 11:19:04] logdisp.DEBUG: dispatcher::msg2apn() [] []
[2015-08-27 11:19:04] logdisp.DEBUG: SUCCESS msg2apn, written[107], sent[107] [] []
[2015-08-27 11:19:05] logdisp.DEBUG: Client [127.0.0.1] connected [] []
[2015-08-27 11:19:05] logdisp.DEBUG: Message buf[...{"aps":{"alert":"message","badge" : "1","sound":"default"}}] from ip[127.0.0.1]  [] []
[2015-08-27 11:19:05] logdisp.DEBUG: dispatcher::msg2apn() [] []
[2015-08-27 11:19:05] logdisp.DEBUG: SUCCESS msg2apn, written[107], sent[107] [] []
[2015-08-27 11:19:07] logdisp.DEBUG: Client [127.0.0.1] connected [] []
[2015-08-27 11:19:07] logdisp.DEBUG: Message buf[...{"aps":{"alert":"message","badge" : "1","sound":"default"}}] from ip[127.0.0.1]  [] []
[2015-08-27 11:19:07] logdisp.DEBUG: dispatcher::msg2apn() [] []
[2015-08-27 11:19:07] logdisp.DEBUG: SUCCESS msg2apn, written[107], sent[107] [] []

我尝试发送两种有效载荷:

I tried to sent two kinds of payload:

{"aps" : {"alert" : "message","badge" : "1","sound" : "default"}} 
{"aps" : { "alert" : { "title" : "My Title", "body" : "My Message" }, "badge" : 2, "sound" : "default" } }

重新生成证书后,我现在在连接时遇到以下错误:

After regenerating the certificates, I do now get the following errors when connecting:

[vagrant@server backend-src]$ php -f dispatcher.php
Log path: [/srv/backend/log/log.txt], Log level: [0],
Binding info: address[127.0.0.1], port[6060]
Connecting to [ssl://gateway.push.apple.com:2195], using certificate [/srv/backend/htdocs/ios_distribution.pem] and passphrase[?]
PHP Warning:  stream_socket_client(): Failed to enable crypto in /vagrant/backend-src/dispatcher.php on line 182
PHP Warning:  stream_socket_client(): unable to connect to ssl://gateway.push.apple.com:2195 (Unknown error) in /vagrant/backend-src/dispatcher.php on line 182
Warning: stream_socket_client(): unable to connect to ssl://gateway.push.apple.com:2195 (Unknown error) in /vagrant/backend-src/dispatcher.php on line 182
Connect failed error[0 ] to url [ssl://gateway.push.apple.com:2195] with certicate [/srv/backend/htdocs/ios_distribution.pem]

我现在可以连接了!这里的原因很简单.证书的路径不正确.但是,在具有新证书的设备上仍未收到推送通知.

I am now able to connect! The reason here was simple. The path to the certificates was incorrect. However push notifications are still not received on the devices with the new certificate.

应用程序是否需要使用新证书发布/发布才能运行???无论是开发还是生产都没有在设备上收到消息???

Does the App need to be published / release with the new certificate before it will work??? Neither on development nor on production are messages received on the device???

最后,它成功接收了沙盒和生产/临时令牌的消息.

Finally, it succeeded receiving messages for both sandbox and production / ad-hoc tokens.

// 64 chars token
// Sandbox and productions tokens have the same length and 
// they cannot be distinguished    
$deviceToken='1234567890123456789012345678901234567890123456789012345678901234';

$body['aps'] = array('alert' => 'Sample message', 'sound' => 'default');
$payload = json_encode($body);

$deviceToken = str_replace(' ', '', $deviceToken);
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;

fwrite($apn_link, $msg, strlen($msg));
fflush($apn_link);

请勿在生产中混合使用沙盒和生产设备令牌!

Do NOT mix sandbox and production device tokens on production!

APN 生产环境不允许使用沙盒令牌当已使用沙盒令牌.

The APN production environment does not allow sandbox tokens and it silently stops delivering messages to production tokens when a sandbox token has been used.

推荐答案

// 64 chars token
// Sandbox and productions tokens have the same length and 
// they cannot be distinguished    
$deviceToken='1234567890123456789012345678901234567890123456789012345678901234';

$body['aps'] = array('alert' => 'Sample message', 'sound' => 'default');
$payload = json_encode($body);

$deviceToken = str_replace(' ', '', $deviceToken);
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;

fwrite($apn_link, $msg, strlen($msg));
fflush($apn_link);

请勿在生产中混合使用沙盒和生产设备令牌!

Do NOT mix sandbox and production device tokens on production!

APN 生产环境不允许使用沙箱令牌,并且在使用了沙箱令牌时,它会以静默方式停止向生产令牌传递消息.

The APN production environment does not allow sandbox tokens and it silently stops delivering messages to production tokens when a sandbox token has been used.

这篇关于APNs 消息已发送但未在 iOS 设备上接收的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆