В PHP, как вы используете fread (), чтобы проверить, есть ли ответ об ошибке при отправке расширенных push-уведомлений?
Я прочитал документы Apple, пару неопределенных сообщений через Google, и пару вопросов / ответов здесь о SO, но это все еще было очень запутанным.
Вот что я посмотрел на: http://developer.apple.com/library/mac/#documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/IPhoneOSClientImp/IPhoneOSClientImp.html Ошибка чтения из расширенного push-уведомления Apple с уведомлением Push iPhone от iPhone – ответ об ошибке проблема
Я собираюсь ответить на свой вопрос ниже, основываясь на том, что: (1) я нашел это очень запутанной темой, и (2) мне пришлось собрать информацию вместе с большим количеством проб и ошибок, чтобы заставить ее работать, и (3) это сообщение в блоге, в котором говорится, что это рекомендуется: http://blog.stackoverflow.com/2011/07/its-ok-to-ask-and-answer-your-own-questions/
Когда вы отправляете push-уведомление, есть несколько проблем:
Если есть проблема, Apple отключит вас, но вы об этом не знаете. Когда вы используете базовые уведомления, нет способа узнать, все ли они отправлены или нет. РЕШЕНИЕ: В этом весь смысл использования расширенного уведомления, а затем проверка на ответ об ошибке. Обратите внимание, что мы будем использовать «ORDER BY id» в запросе базы данных, а затем использовать идентификатор в качестве идентификатора, который мы отправляем в уведомлении. Таким образом, если есть проблема, мы точно знаем, какая строка в db вызвала проблему (и, следовательно, мы знаем, когда Apple отключило нас и прекратила отправку уведомлений). Затем мы можем продолжить отправку Push-уведомлений во все строки после строки, вызвавшей проблему, без необходимости повторной отправки тех, на которые мы уже отправили.
Apple НЕ отправляет ответ, если все в порядке, так что это может привести к тому, что ваш сценарий приостановится и будет вечно ждать, пока fread () ждет данных, которые не будут появляться. РЕШЕНИЕ: нужно установить stream_set_blocking в 0, чтобы fread всегда возвращался сразу. Обратите внимание, что это вызывает еще одну незначительную проблему, которую fread может вернуть до получения ответа об ошибке, но см. Обходной путь в коде, который нужно просто приостановить в течение 1/2 секунды после завершения всей вашей отправки, а затем еще раз проверить fread ,
Вы можете отправлять несколько push-уведомлений намного быстрее, чем получать ответ об ошибке, чтобы вернуться к вам. РЕШЕНИЕ: Опять же, это одно и то же обходное решение, упомянутое выше … пауза в течение 1/2 секунды. ПОСЛЕ того, как все ваши посылки завершены, а затем проверьте fread еще раз.
Вот мое решение с использованием PHP, в котором рассматриваются все мои проблемы, с которыми я столкнулся. Его довольно простой, но выполняет свою работу. Я протестировал его, отправив сразу несколько уведомлений, а также отправил 120 000 за один раз.
<?php /* * Read Error Response when sending Apple Enhanced Push Notification * * This assumes your iOS devices have the proper code to add their device tokens * to the db and also the proper code to receive push notifications when sent. * */ //database $host = "localhost"; $user = "my_db_username"; $pass = "my_db_password"; $dbname = "my_db_name"; $con = mysql_connect($host, $user, $pass); if (!$con) { die('Could not connect to database: ' . mysql_error()); } else { mysql_select_db($dbname, $con); } // IMPORTANT: make sure you ORDER BY id column $result = mysql_query("SELECT id,token FROM `device_tokens` ORDER BY id"); //Setup notification message $body = array(); $body['aps'] = array('alert' => 'My push notification message!'); $body['aps']['notifurl'] = 'http://www.myexampledomain.com'; $body['aps']['badge'] = 1; //Setup stream (connect to Apple Push Server) $ctx = stream_context_create(); stream_context_set_option($ctx, 'ssl', 'passphrase', 'password_for_apns.pem_file'); stream_context_set_option($ctx, 'ssl', 'local_cert', 'apns.pem'); $fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT, $ctx); stream_set_blocking ($fp, 0); //This allows fread() to return right away when there are no errors. But it can also miss errors during last seconds of sending, as there is a delay before error is returned. Workaround is to pause briefly AFTER sending last notification, and then do one more fread() to see if anything else is there. if (!$fp) { //ERROR echo "Failed to connect (stream_socket_client): $err $errstrn"; } else { $apple_expiry = time() + (90 * 24 * 60 * 60); //Keep push alive (waiting for delivery) for 90 days //Loop thru tokens from database while($row = mysql_fetch_array($result)) { $apple_identifier = $row["id"]; $deviceToken = $row["token"]; $payload = json_encode($body); //Enhanced Notification $msg = pack("C", 1) . pack("N", $apple_identifier) . pack("N", $apple_expiry) . pack("n", 32) . pack('H*', str_replace(' ', '', $deviceToken)) . pack("n", strlen($payload)) . $payload; //SEND PUSH fwrite($fp, $msg); //We can check if an error has been returned while we are sending, but we also need to check once more after we are done sending in case there was a delay with error response. checkAppleErrorResponse($fp); } //Workaround to check if there were any errors during the last seconds of sending. usleep(500000); //Pause for half a second. Note I tested this with up to a 5 minute pause, and the error message was still available to be retrieved checkAppleErrorResponse($fp); echo 'DONE!'; mysql_close($con); fclose($fp); } //FUNCTION to check if there is an error response from Apple // Returns TRUE if there was and FALSE if there was not function checkAppleErrorResponse($fp) { //byte1=always 8, byte2=StatusCode, bytes3,4,5,6=identifier(rowID). Should return nothing if OK. $apple_error_response = fread($fp, 6); //NOTE: Make sure you set stream_set_blocking($fp, 0) or else fread will pause your script and wait forever when there is no response to be sent. if ($apple_error_response) { //unpack the error response (first byte 'command" should always be 8) $error_response = unpack('Ccommand/Cstatus_code/Nidentifier', $apple_error_response); if ($error_response['status_code'] == '0') { $error_response['status_code'] = '0-No errors encountered'; } else if ($error_response['status_code'] == '1') { $error_response['status_code'] = '1-Processing error'; } else if ($error_response['status_code'] == '2') { $error_response['status_code'] = '2-Missing device token'; } else if ($error_response['status_code'] == '3') { $error_response['status_code'] = '3-Missing topic'; } else if ($error_response['status_code'] == '4') { $error_response['status_code'] = '4-Missing payload'; } else if ($error_response['status_code'] == '5') { $error_response['status_code'] = '5-Invalid token size'; } else if ($error_response['status_code'] == '6') { $error_response['status_code'] = '6-Invalid topic size'; } else if ($error_response['status_code'] == '7') { $error_response['status_code'] = '7-Invalid payload size'; } else if ($error_response['status_code'] == '8') { $error_response['status_code'] = '8-Invalid token'; } else if ($error_response['status_code'] == '255') { $error_response['status_code'] = '255-None (unknown)'; } else { $error_response['status_code'] = $error_response['status_code'] . '-Not listed'; } echo '<br><b>+ + + + + + ERROR</b> Response Command:<b>' . $error_response['command'] . '</b> Identifier:<b>' . $error_response['identifier'] . '</b> Status:<b>' . $error_response['status_code'] . '</b><br>'; echo 'Identifier is the rowID (index) in the database that caused the problem, and Apple will disconnect you from server. To continue sending Push Notifications, just start at the next rowID after this Identifier.<br>'; return true; } return false; } ?>
Не уверен, что содержимое вашего кода, но вы должны попробовать ApnsPHP, он хорошо протестирован, отлично работает и способен обрабатывать все возможные исключения и ошибки для вас.
Другие альтернативы
https://github.com/sebastianborggrewe/PHP-Apple-Push-Notification-Server https://github.com/bortuzar/PHP-Mysql—Apple-Push-Notification-Server
Тестировали 2 из 3-х примеров и не имели проблемы с внедрением и управлением ошибками.
благодаря
🙂