Тихие толчки не доставляются в приложение на iOS 11

Я заметил, что на iOS 11 beta 2 тихие уведомления не доставляются application:didReceiveRemoteNotification:fetchCompletionHandler независимо от состояния приложения (фон / передний план).

Я реализовал UIApplicationDelegete метод application:didReceiveRemoteNotification:fetchCompletionHandler и я посылаю следующий тихий толчок

{  
  "aps": {  
    "content-available": 1  
  },  
  "mydata": {  
    "foo": "bar"  
  }  
} 

но метод делегата не вызывается на iOS 11.

Он отлично работает на других версиях iOS, и в разделе документации " Настройка молчаливого уведомления" не упоминается, что нужно что-то еще делать.

Это ошибка в iOS 11 или я пропустил что-то новое в iOS 11?

Обратите внимание, что я не говорю или не использую UserNotification рамки, которые не должны быть нужны для отправки тихих толчков.

Вот пример проекта, который иллюстрирует проблему (вам нужно установить свой собственный идентификатор пакета)

Когда вы запускаете пример проекта и отправляете вышеупомянутую полезную нагрузку в приложение, вы можете использовать консоль macOS, чтобы убедиться, что push-уведомление корректно доставляется на устройство, но не в приложение.

ОБНОВЛЕНИЕ 10.08

Похоже, что поведение является случайным. Иногда после перезапуска устройства полезная нагрузка доставляется правильно, но через некоторое время перестает работать.

Как видно на следующем снимке экрана, отправка, помеченная как 1, передается только на устройство, а нажатие 2 (после перезапуска устройства) также доставляется в приложение.

ОБНОВЛЕНИЕ 14.08 - iOS 11 Beta 6

Все то же поведение. Еще одна вещь, которая должна работать, но не работает, заключается в следующем. Когда для схемы приложения установлено значение "Ожидание запуска исполняемого файла", предполагается, что тихое нажатие активизирует приложение и запускает его в фоновом режиме.

ОБНОВЛЕНИЕ 21.08 - iOS 11 Beta 7

По-прежнему такое же поведение, а не обновления от Apple в отчете об ошибках.

ОБНОВЛЕНИЕ 29.08 - iOS 11 Beta 8

Все та же проблема. Шаги для воспроизведения, которые я использую сейчас, следующие:

  • В схеме проекта XCode выберите "Ожидание запуска исполняемого файла"
  • Добавьте точку останова в didReceiveRemoteNotification: fetchCompletionHandler
  • Запустите приложение на устройстве
  • Отправить вышеуказанный тихий толчок

Ожидается: приложение переведено из приостановленного состояния в фоновое и didReceiveRemoteNotification: fetchCompletionHandler называется

Актуально: ничего не происходит

ОБНОВЛЕНИЕ 06.09 - iOS 11 Beta 10

У меня все еще такое же глючное поведение. Билет от Apple был обновлен следующим ответом:

Отношения Apple с разработчиками 6 сентября 2017, 22:42 Engineering предоставила следующие отзывы по этой проблеме:

Мы смогли запустить пример приложения и протестировать его поведение. Мы не увидели никаких проблем, когда мы проверили это, как описано.

Толчки не гарантированно поступят в приложение, когда оно работает в фоновом режиме, и логи здесь показывают, что мы не верим, что приложение используется достаточно для его запуска.

Мы видим, что время от времени мы доставляем толчки при хороших условиях.

Мы считаем, что это ведет себя правильно.

Обновление 11.09

Мой отчет об ошибках Apple был закрыт и помечен как дубликат 33278611 который остается открытым

ОБНОВЛЕНИЕ 13.09 - iOS 11 GM

Благодаря комментариям kam800 (см. Ниже) я провел дополнительное тестирование и получил эти наблюдения:

Кажется, в iOS 11 появился новый демон dasd DuetActivitySchedulerDaemon которая либо полностью отбрасывает передачу данных, либо задерживает доставку данных:

Доставка отложена

Консольные журналы

default 13:11:47.177547 +0200   dasd    DuetActivitySchedulerDaemon CANCELED: com.apple.pushLaunch.net.tequilaapps.daylight:C03A65 <private>!   lifecycle   com.apple.duetactivityscheduler
default 13:11:47.178186 +0200   dasd    DuetActivitySchedulerDaemon Removing a launch request for application <private> by activity <private>   default com.apple.duetactivityscheduler
default 12:49:04.426256 +0200   dasd    DuetActivitySchedulerDaemon Advancing start date for <private> by 6.5 minutes to Wed Sep 13 12:55:31 2017   default com.apple.duetactivityscheduler
default 13:21:40.593012 +0200   dasd    DuetActivitySchedulerDaemon Activity <private>: Optimal Score 0.6144 at <private> (Valid Until: <private>)  scoring com.apple.duetactivityscheduler
default 13:21:40.594528 +0200   dasd    DuetActivitySchedulerDaemon Setting timer (isWaking=1, activityRequiresWaking=0) between <private> and <private> for <private>  default com.apple.duetactivityscheduler

Отложенные вопросы доставки

  • Когда принудительная доставка данных откладывается и приложение запускается, принудительная доставка данных доставляется только по достижении даты доставки, которая может составить несколько минут в будущем. Это полностью исключает необходимость использования данных, чтобы контент нового приложения был готов к следующему запуску. Я приведу здесь еще раз документацию Apple:

"Тихие уведомления улучшают работу пользователя, помогая поддерживать приложение в актуальном состоянии, даже если оно не запущено".

  • Когда два отсылки данных отправляются в приостановленное приложение, они откладываются iOS 11 вместо непосредственного пробуждения приложения. Когда время доставки достигнуто, доставляется только последний поток данных! Предыдущие сообщения теряются и не доставляются с помощью метода делегата, что приводит к потере данных.

Доставка отменена

Консольные журналы

default 13:35:05.347078 +0200   dasd    DuetActivitySchedulerDaemon com.apple.pushLaunch.net.tequilaapps.daylight:C03A65:[
    {name: ApplicationPolicy, policyWeight: 50.000, response: {Decision: Must Not Proceed, Score: 0.00}}
 ], FinalDecision: Must Not Proceed}    scoring com.apple.duetactivityscheduler

Отмененные проблемы с доставкой

Что ж, в этом случае передача данных полностью теряется и никогда не доставляется на iOS 11, хотя она была доставлена ​​правильно на iOS 10.

ОБНОВЛЕНИЕ 19.09 - iOS 11 GM

Я также заметил, что когда приложение находится на переднем плане, а уведомление не доставляется приложению, в консоли отображаются следующие журналы:

default 08:28:49.354824 +0200   apsd    apsd    <private>: Received message for enabled topic '<private>' onInterface: NonCellular with payload '<private>' with priority 10 for device token: NO   courier-oversized   com.apple.apsd

fault   08:33:18.128209 +0200   dasd    Foundation  <NSXPCConnection: 0x151eee460> connection from pid 55: Exception caught during decoding of received message, dropping incoming message.
Exception: Exception while decoding argument 0 (#2 of invocation):
Exception: value for key 'NS.objects' was of unexpected class 'NSNull'. Allowed classes are '{(
    NSArray,
    NSData,
    NSString,
    NSNumber,
    NSDictionary,
    NSUUID,
    _DASActivity,
    NSSet,
    _DASFileProtection,
    NSDate,
    NWParameters,
    NWEndpoint
)}'.    general com.apple.foundation.xpc

13 ответов

Так заметки о выпуске iOS 11.1 beta 1 говорят

iOS 11.1 beta 1 только что была выпущена, и в них упоминается: "Решения, связанные с уведомлениями • Тихие push-уведомления обрабатываются чаще. (33278611)

Я сделал несколько тестов, и это, кажется, действительно исправлено:

Приостановлено состояние

Когда я запускаю приложение в режиме ожидания и отправляю тихий толчок, приложение возвращается в фоновый режим и didReceiveRemoteNotification:fetchCompletionHandler делегат называется.

Состояние переднего плана

Таким же образом, когда приложение находится на переднем плане и отправляется тихий push, делегат, кажется, вызывается, как и ожидалось. Это случайно не работало в предыдущих версиях iOS 11, поэтому я подтвердлю это после дополнительных испытаний.

Я просто хотел добавить сюда свои 2 цента, так как меня тоже коснулась эта проблема, и я заметил, что Apple закрыла несколько радаров по этому вопросу, заявив, что они не могут воспроизвести. Интересная вещь, которую я обнаружил, состоит в том, что толчки будут доставлены, если приложение будет фоновым, пока оно подключено к отладчику.

Если я отключу отладчик, отключу телефон, запустлю приложение и отправлю полезную нагрузку без вывода сообщений, я вижу, что приложение НЕ разбудило. Я вижу в журнале консоли, что система отменяет доставку полезных данных в мое приложение.

Я представил радар с небольшим примером приложения, которое воспроизводит проблему. Я также ясно отметил в радаре, что человек, работающий с моим билетом, не должен запускать приложение, подключенное к отладчику, чтобы воспроизвести проблему. Вот ссылка: https://bugreport.apple.com/web/?problemID=34461063

Надеемся, что это приведет к некоторому прогрессу в этом вопросе.

Похоже, новое поведение iOS 11. iOS 11 beta 10 предоставляет несколько описательных журналов по этой проблеме:

default 23:18:51.806011 +0200   dasd    com.apple.pushLaunch.com.acme.Acme:F7E7D0:[
    {name: ApplicationPolicy, policyWeight: 50.000, response: {Decision: Can Proceed, Score: 0.50}}
    {name: BatteryLevelPolicy, policyWeight: 1.000, response: {Decision: Can Proceed, Score: 0.87, Rationale: [{batteryLevel == 62}]}}
    {name: DeviceActivityPolicy, policyWeight: 5.000, response: {Decision: Can Proceed, Score: 0.20}}
 ] sumScores:52.279483, denominator:81.410000, FinalDecision: Can Proceed FinalScore: 0.642175}
default 23:18:51.806386 +0200   dasd    'com.apple.pushLaunch.com.acme.Acme:F7E7D0' has compatibility score of 1.000000 with 'com.apple.CFNetwork-cc-111-79:E7272D'. Relaxing scores.
default 23:18:51.806855 +0200   dasd    'com.apple.pushLaunch.com.acme.Acme:F7E7D0' CurrentScore: 0.642175, ThresholdScore: 0.738454 DecisionToRun:0

Похоже, что каждое тихое нажатие доставляется в iOS, но демон dasd использует несколько политик, чтобы решить, следует ли доставлять тихое нажатие в приложение (например, уровень заряда батареи). Вчера вечером мне удалось получить один тихий толчок, но в то время мой iPhone был подключен к зарядному устройству - возможно, показатель BatteryLevelPolicy был достаточно высок, чтобы получить этот один тихий толчок.

Apple не предоставляет официальной информации об этом поведении на стороне iOS, есть только информация о регулировании на стороне сервера:

Беззвучные уведомления не предназначены для того, чтобы держать ваше приложение активным в фоновом режиме, а также для высокоприоритетных обновлений. APN рассматривают тихие уведомления как низкоприоритетные и могут полностью ограничить их доставку, если общее количество становится чрезмерным. Фактические ограничения являются динамическими и могут изменяться в зависимости от условий, но старайтесь не отправлять более нескольких уведомлений в час.

Я держу пальцы скрещенными, они изменили это поведение, потому что это исправило бы мое приложение:) С другой стороны, это изменение хорошо - одна из многих вещей делает батарею iPhone более долговечной, чем телефоны Android.

Примечания к выпуску бета-версии iOS 11.1 включают: Уведомления Решенные проблемы Тихие push-уведомления обрабатываются чаще. (33278611)

iOS 11.1 Beta 2 также содержит

Notifications
Resolved Issues
• Silent push notifications are processed more frequently. (33278611)

в примечаниях к выпуску - сейчас опробую.

ОБНОВЛЕНИЕ - 11.10.2017 - iOS 11.1 Beta 2

После двухдневного использования нашего приложения в "реальных сценариях" похоже, что в этой версии iOS есть реальное улучшение. Я осторожно начинаю верить, что это исправлено.

Apple Developer Relations просто добавила комментарий к моему радару:

Мы считаем, что эта проблема решена в последней бета-версии iOS 11.2.

Пожалуйста, протестируйте последнюю бета-версию iOS. Если у вас все еще есть проблемы, пожалуйста, обновите ваш отчет об ошибках с любыми соответствующими журналами или информацией, которая могла бы помочь нам исследовать.

https://developer.apple.com/download/

в настоящее время устанавливается iOS 11.2 beta - будет тестировать поведение молча

iOS 11.4.1, Swift 4

У меня были проблемы с тихими толчками, не прибывающими (из CloudKit), и я попробовал все, что все упоминали здесь. Тогда я решил попробовать установить бланк alertBody к моему CKNotificationInfo() объекты как это:

let info = CKNotificationInfo()
info.shouldSendContentAvailable = true
info.alertBody = ""

Это сделало отправку посылок с более высоким приоритетом (но они все еще были молчаливыми посылками), и я больше не получал сообщение об ошибке в журналах своего устройства о том, что нажатие игнорировалось.

Я надеюсь, что это помогает кому-то.:)

У меня была похожая проблема с моим приложением, до iOS 10 я получал push-уведомления и application:didReceiveRemoteNotification:fetchCompletionHandler были вызваны правильно. Но при обновлении до iOS 11 перестали работать push-уведомления.

Проблема с моим кодом была, хотя я использовал content-available: 1 и mutable-content: 1 в полезных данных push-уведомлений, опция Background Fetch не была включена. Но это работало отлично до iOS 10.

Убедитесь, что вы включили обе эти возможности

После включения возможности Background Fetch теперь она работает

Так что это действительно ошибка в iOS 11, и теперь она исправлена ​​в iOS 11 beta 3. application:didReceiveRemoteNotification:fetchCompletionHandler теперь вызывается правильно, когда тихий толчок получен как на переднем, так и на заднем плане.

ОБНОВИТЬ

Нет, это не исправлено и все еще происходит в iOS бета 3 и 4

В качестве обходного пути Мы добавляем ключ "уведомления" и внутри "заголовка" с пустой строкой в ​​качестве значения. Это пробуждение обратного вызова didReceive в appDelegate.

Я получаю ту же проблему для некоторых уведомлений (не обязательно молчать).

После просмотра всех обновлений и ответов я могу добавить два обновления, которые могут помочь:

  • Я обнаружил, что доступ UIApplication.shared.isRegisteredForRemoteNotifications Метод при получении уведомления приводит к остановке приложения, не сообщая ничего Xcode. Проверьте, выполняется ли какой-либо код после получения уведомления о доступе к методу. ( isRegisteredForRemoteNotifications, блокирующий пользовательский интерфейс с помощью semaphore_wait_trap).

    • Я обнаружил, что у меня была ошибка синтаксического анализа push-уведомлений из-за "title-loc-args" : [3333] не принимая 3333 буквально, но принимая его как строку "title-loc-args" : ["3333"], Это заставило весь мой интерфейс зависнуть после того, как я получил доступ к описанному выше методу, только на iOS 11, он работает на iOS 12.
  • Я также узнал, что с точно таким же кодом он работает без проблем на iOS 12.0 (16A5366a). Но на iOS 11 это происходит.

На момент написания этого ответа я столкнулся с той же проблемой, что и ответ Билла Дунай.

Мое требование состояло в том, чтобы получать тихие уведомления, когда приложение находится на переднем плане, и ничего, когда приложение находится в фоновом режиме / не работает. И мой обходной путь был этим. Я не использую значки, поэтому установка его на ноль не проблема для меня.

{
    "aps" : {
        "badge" : 0,
        "sound" : ""
    },
    "mydata": {  
        "foo": "bar"  
    }  
}

Обратите внимание, что я намеренно не использую "контент-доступный". Параметр, который заставляет логику оптимизации iOS активировать задержку / отмену доставки уведомления.

Этот жанр проблемы, кажется, лет, и продолжается. Мое приложение работало хорошо (после долгих усилий), но с 11* тихие уведомления настолько ненадежны. Оба тестовых приложения на переднем плане, оба в режиме отладки, все работает. Отключите один и запустите вне отладчика, и iOS отменяет уведомление с "Удаление запроса на запуск приложения по активности" . Разочарование.

Я прочитал так много веток, с таким количеством мыслей, но без истинных ответов. Для двух предопределенных приложений, и единственным отличием является режим отладки, это кажется просто... неправильным.

В моем случае тихие уведомления использовались для обновления пользовательского интерфейса после того, как работа была выполнена на сайте сервера, поэтому было неприятно иметь не релевантный контент в приложении. Поскольку наша полезная нагрузка для уведомлений в режиме без вывода сообщений содержит даже заголовок и текст, я реализую эти методы для получения рабочих уведомлений в активном / неактивном приложении, без зарядки и с отключенным фоновым обновлением приложения и даже в состоянии низкого энергопотребления.

Чтобы это работало, я добавляю делегата и создаю расширение с UNUserNotificationCenterDelegate протокол и willPresent notification (iOS 10+), который запускается каждый раз с правильной полезной нагрузкой. Чтобы не показывать уведомление, когда приложение активно, просто завершите звонок со значком или звуком. Я закончил с чем-то вроде этого

    import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
    var window: UIWindow?

    // MARK: - Lifecycle
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        UNUserNotificationCenter.current().delegate = self
        return true
    }

    //this was only method to handle notifications before
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any],
                     fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
        //process silent notification
        completionHandler(UIBackgroundFetchResult.newData)
    }
}

extension AppDelegate : UNUserNotificationCenterDelegate {
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        //proces notification when app is active with `notification.request.content.userInfo`
        if UIApplication.shared.applicationState == .active {
            completionHandler(.badge)
        }else {
            completionHandler(.alert)
        }
    }
}

И чтобы работать с этими состояниями, когда приложение работает в фоновом режиме, а тихие уведомления не вызывают мои методы, я получаю уведомления непосредственно из центра уведомлений. applicationDidBecomeActive от:

UNUserNotificationCenter.current().getDeliveredNotifications { (notifications) in
            debugLog(message: "unprocessed notification count: \(notifications.count)")
            if notifications.count > 0 {
                notifications.forEach({ (notification) in
                    DispatchQueue.main.async {
                        //handle `notification.request.content.userInfo`
                    }
                })
            }
        }

В моем случае "Обновление приложений в фоновом режиме" было отключено в настройках iPhone. Из-за этого push-уведомление было доставлено на устройство, но не в приложение. Включение фонового обновления приложения получает в приложении тихий толчок.

Это может быть не реальный ответ на этот вопрос, на всякий случай, если кому-то понадобится проверить.

Другие вопросы по тегам