Некоторые устройства не получают push-уведомления Apple
Я использую расширенный формат уведомлений Apple для iOS, а также использую решение PHP, описанное в этом сообщении: /questions/38724205/php-apple-rasshirennoe-push-uvedomlenie-chtenie-oshibki-otveta/38724217#38724217
Опыт на этом этапе заключается в том, что когда я отправляю push-уведомление, некоторые устройства получают сообщение, а некоторые - нет. Результаты противоречивы. Иногда устройство X получит уведомление, а иногда устройство X не получит. Я регистрирую все, и я не получаю никаких сообщений об ошибках.
Любые мысли о том, что происходит, были бы очень полезны.
4 ответа
Решение в ответе, с которым вы связаны, имеет проблему. Он пытается прочитать ответ об ошибке после отправки каждого сообщения, но чтение немедленно возвращается и не ждет, когда ответ станет доступным. Хотя это более эффективно, чем ожидание ответа о потенциальной ошибке в течение X миллисекунд после каждого сообщения, вы можете пропустить ответ об ошибке, и Apple может разорвать соединение, не зная, что произошла какая-либо ошибка.
Хотя я не могу дать вам код для решения вашей проблемы, я дам вам несколько советов.
Вот логика, которую вы должны использовать (согласно Apple), но мне не удалось заставить ее работать надежно (по крайней мере, в моей реализации Java):
Производительность push-уведомлений и проверка ошибок
Если вы видите пропускную способность ниже 9 000 уведомлений в секунду, ваш сервер может выиграть от улучшенной логики обработки ошибок.
Вот как проверить наличие ошибок при использовании расширенного двоичного интерфейса. Продолжайте писать, пока запись не удастся. Если поток снова готов к записи, отправьте уведомление и продолжайте. Если поток не готов к записи, посмотрите, доступен ли поток для чтения.
Если это так, прочитайте все, что доступно из потока. Если вы вернули ноль байтов, соединение было закрыто из-за ошибки, такой как недопустимый байт команды или другой ошибки синтаксического анализа. Если вы получите обратно шесть байтов, это ответ об ошибке, который вы можете проверить по коду ответа и идентификатору уведомления, вызвавшего ошибку. Вам нужно будет отправить каждое уведомление после этого еще раз.
После того, как все было отправлено, выполните последнюю проверку на наличие сообщения об ошибке.
Прерванное соединение может пройти некоторое время от APN до вашего сервера только из-за обычной задержки. Можно отправить более 500 уведомлений, прежде чем произойдет сбой записи из-за разрыва соединения. Около 1700 операций записи уведомлений могут завершиться неудачей только потому, что канал заполнен, поэтому просто повторите попытку, как только поток снова будет готов к записи.
Теперь вот где компромиссы становятся интересными. Вы можете проверять ответ об ошибке после каждой записи, и вы сразу же обнаружите ошибку. Но это приводит к значительному увеличению времени, необходимого для отправки пакета уведомлений.
Токены устройств должны быть почти все действительными, если вы правильно их захватили и отправляете в правильную среду. Поэтому имеет смысл оптимизировать, если сбои будут редкими. Вы получите гораздо лучшую производительность, если дождетесь сбоя записи или завершения пакета, прежде чем проверять ответ об ошибке, даже считая время для повторной отправки отброшенных уведомлений.
Ничто из этого не относится к APN, это относится к большинству программ на уровне сокетов.
Если выбранный вами инструмент разработки поддерживает несколько потоков или межпроцессное взаимодействие, у вас может быть поток или процесс, постоянно ожидающий ответ об ошибке и сообщающий главному отправляющему потоку или процессу, когда он должен сдаться и повторить попытку.
Это взято из Технического примечания Apple: Устранение неполадок Push-уведомлений.
Я не знаю, как вы обнаруживаете в PHP, что запись не удалась, но когда это происходит, вы должны попытаться написать уведомление о сбое еще раз, и, если это произойдет снова, попытаться прочитать ответ об ошибке и закрыть соединение.
Если вам удастся прочитать ответ об ошибке, вы будете знать, какое уведомление не удалось, и вы будете знать тип ошибки (наиболее вероятная ошибка - 8 - недопустимый токен устройства). Код в ответе, на который вы ссылались, ничего не делает после выявления этой ошибки. Если после написания 100 сообщений вы получите ответ об ошибке для 80-го сообщения, вам необходимо повторно отправить сообщения с 81 по 100, так как Apple никогда не получала их. В моем случае (Java-сервер) мне не всегда удается прочитать ответ об ошибке (иногда я получаю сообщение об ошибке при попытке прочитать ответ из сокета). В этом случае я могу только отправлять следующие уведомления (и не могу знать, какие уведомления были фактически получены Apple). Вот почему важно, чтобы ваша база данных была чистой от недопустимых токенов.
Если вы храните свою базу данных в чистоте (т.е. храните в ней только те токены устройств, которые были отправлены в ваше приложение Apple, и все они принадлежат одной и той же среде push-уведомлений - либо песочнице, либо рабочей среде), вы не должны встретить недопустимых токенов устройств.
Я столкнулся с аналогичной проблемой с вашей при реализации серверной части push-уведомлений в Java. Я не мог достоверно получить все сообщения об ошибках, возвращаемые Apple.
Я обнаружил, что в Java есть способ отключить алгоритм TCP Nagle, который вызывает буферизацию нескольких сообщений перед отправкой их в пакетном режиме в Apple. Хотя Apple рекомендует нам использовать алгоритм Nagle (по соображениям производительности), я обнаружил, что когда я отключаю его, а затем пытаюсь прочитать ответ от Apple после каждого отправляемого им сообщения, мне удается получить 100% ответов об ошибках (я проверил это, написав процесс, имитирующий сервер APNS).
Отключив алгоритм Nagle и медленно отправляя уведомления по одному и пытаясь прочитать ответ об ошибке после каждого сообщения, вы можете найти все недействительные токены в вашей БД и удалить их. Как только вы узнаете, что ваша БД чиста, вы можете включить алгоритм Nagle и быстро возобновить отправку уведомлений, не потрудившись прочитать ответы об ошибках от Apple. Затем, когда вы получаете сообщение об ошибке при записи сообщения в сокет, вы можете просто создать новый сокет и повторить отправку только последнего сообщения.
Нет никакой гарантии, что push-уведомления будут доставлены, даже если сервер APNS их принял.
Что касается вашего сервера, push-уведомления запускаются и забываются; нет способа узнать, в каком состоянии находится уведомление после того, как вы отправили его в APNS. Время доставки также может варьироваться от секунд до получаса.
Кроме того, iPhone пользователя не всегда может получать push-уведомления. Они могут находиться в сети WiFi, которая не позволяет устанавливать соединения с APNS, поскольку требуемые порты заблокированы. Или телефон может быть выключен.
APNS попытается доставить последнее уведомление, полученное для этого устройства, когда оно вернется в режим онлайн, но оно будет пытаться ограниченное время. По истечении этого времени push-уведомление будет потеряно навсегда!
В моем случае, во время разработки, некоторые APN не были получены на одном устройстве (я тестировал с PushMeBaby).
Я удалил со своего устройства все предыдущие профили обеспечения, связанные с моим проектом, и с этого момента все прошло нормально. Для этого перейдите в Настройки> Профили.
Возможно, у меня был какой-то конфликт с профилями, так как проект, над которым я работаю, с тех пор изменил идентификатор пакета и профили обеспечения.
Я также столкнулся с этой проблемой в моем нескольких приложениях. Причина, по которой некоторые устройства не получают push-уведомления, может быть:
- Использование сервера APNS для песочницы с производственным сертификатом APNS. -> Пожалуйста, проверьте это
- И разработанные и производственные предварительные профили установлены на устройстве. -> Удалите оба предварительных, и тогда вам придется ждать по крайней мере 24 часа, чтобы Apple также удалила токен устройства со своего сервера.