APNS показывает только одно ожидающее уведомление

Я успешно внедрил службу push-уведомлений для своего приложения ios. Я сгенерировал необходимые сертификаты и код работает. Проблема возникает, когда устройство отключено от Интернета и получает некоторые уведомления (которые находятся в состоянии ожидания и не отображаются), затем, когда устройство снова подключено к Интернету... отображается только одно из ожидающих уведомлений APNS Push. Я использую php для своего бэкэнда и NotificationServiceExtension для вложений и т. Д.

Вот мой php код

public static function sendAPNS($token,$data)
    {
      print_r($token);
      $apnsServer = 'ssl://gateway.push.apple.com:2195';
      $privateKeyPassword = 'password-here';
      /* Device token */
      $deviceToken = $token;
      $pushCertAndKeyPemFile = 'nameofthefile.pem';
      $stream = stream_context_create();
      stream_context_set_option($stream, 'ssl', 'passphrase', $privateKeyPassword);
      stream_context_set_option($stream, 'ssl', 'local_cert', $pushCertAndKeyPemFile);
      $connectionTimeout = 20;
      $connectionType = STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT;
      $connection = stream_socket_client($apnsServer, $errorNumber, $errorString, $connectionTimeout, $connectionType, $stream);




        /*Alert array eg. body, title etc */
      $alertArray = [];
      $alertArray["body"] = $data["body"];
      $alertArray["title"] =$data["title"];


      $messageBody['aps'] = array(
        'alert' => $alertArray,
        'sound' => 'default',
        'category'=> 'customUi',
        'mutable-content'=>1

      );
      /*User Info*/
      $messageBody["attachment-url"] = $data["url"];
      $messageBody["type_code"] = $data["type_code"];
      $messageBody["ref_id"] = $data["ref_id"];
      $messageBody["user_to"] =$data["user_to"];

      /*Could be here*/



      $payload = json_encode($messageBody);

       print_r($payload);
      $notification = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
      $wroteSuccessfully = fwrite($connection, $notification, strlen($notification));


      fclose($connection);
    }

Расширение моего сервиса выглядит следующим образом:

class NotificationService: UNNotificationServiceExtension {

var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?

override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
    self.contentHandler = contentHandler
    bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

    if let bestAttemptContent = bestAttemptContent {


        var defaultsUser: UserDefaults = UserDefaults(suiteName: "group.shared.com.plates215")!
        if let countNot = defaultsUser.value(forKey: "notUniversal")
        {
            var   IntcountNot = countNot as! Int
            IntcountNot = IntcountNot + 1
            var sum: NSNumber = NSNumber(value: IntcountNot)
            bestAttemptContent.badge = sum
            defaultsUser.set(IntcountNot, forKey: "notUniversal") 

        }

        if let photo = bestAttemptContent.userInfo["attachment-url"] as? String
        {
            updateReadNots(userID: (bestAttemptContent.userInfo["user_to"] as? String)!)
            let url = NSURL(string: photo);
            var err: NSError?
            var imageData :NSData = try! NSData(contentsOf: url! as URL)
            var bgImage = UIImage(data:imageData as Data)

            if let attachment = UNNotificationAttachment.create(identifier: "colo", image: bgImage!, options: nil)
            {
                bestAttemptContent.attachments = [attachment]
                contentHandler(bestAttemptContent)
            }


        }




    }

}


override func serviceExtensionTimeWillExpire() {
    // Called just before the extension will be terminated by the system.
    // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
    if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
        contentHandler(bestAttemptContent)
    }
}
func updateReadNots(userID: String)
{
    var url: String = "api-url"
    let session: URLSession = URLSession(configuration: URLSessionConfiguration.default)
    var urlDown = URL(string: url)
    let downloadTask = session.downloadTask(with: urlDown!) { (url, rsp, error) in


    }
    downloadTask.resume()


}

     }

    extension UNNotificationAttachment {

static func create(identifier: String, image: UIImage, options: [NSObject : AnyObject]?) ->  UNNotificationAttachment? {
    let fileManager = FileManager.default
    let tmpSubFolderName = ProcessInfo.processInfo.globallyUniqueString
    let tmpSubFolderURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(tmpSubFolderName, isDirectory: true)
    do {
        try fileManager.createDirectory(at: tmpSubFolderURL, withIntermediateDirectories: true, attributes: nil)
        let imageFileIdentifier = identifier+".png"
        let fileURL = tmpSubFolderURL.appendingPathComponent(imageFileIdentifier)
        guard let imageData = UIImagePNGRepresentation(image) else {
            return nil
        }
        try imageData.write(to: fileURL)
        let imageAttachment = try UNNotificationAttachment.init(identifier: imageFileIdentifier, url: fileURL, options: options)
        return imageAttachment
    } catch {
        print("error " + error.localizedDescription)
    }
    return nil
}
  }

РЕШЕНИЕ
Что касается ссылки @Li Sim, это то, что я сделал... каждое уведомление, которое я отправляю с моего сервера, содержит не только последнее уведомление, но также и каждое непрочитанное уведомление, разделенное знаком \ n. И тогда уведомления ios правильно отображают их. Чтобы отслеживать уведомления о прочтении и непрочитанных сообщениях, в моем back_end имеется ключ read_status, который обновляется сразу после получения уведомления в NotificationContentExtension ( https://developer.apple.com/documentation/usernotifications/unnotificatio nserviceextension). Он используется для изменения содержимого и выполнения некоторого кода при получении push-кода apns. Надеюсь, это поможет кому-то в будущем:)

1 ответ

Решение

Это поведение задокументировано Apple ранее. Ссылка на документ: https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html

Если устройство находится в автономном режиме, отправка запроса уведомления, нацеленного на это устройство, приводит к отклонению предыдущего запроса. Если устройство долгое время остается в автономном режиме, все его сохраненные уведомления в APN удаляются.

Хотя я не знаком с этим, (извините за это) вот несколько постов, которые я нашел полезными для вашей проблемы: Как WhatsApp получает несколько уведомлений, когда APNS сохраняет только один, если устройство находится в автономном режиме?

Надеюсь, что-то из этого получится. Другой способ, о котором я могу подумать, - это использовать LocalNotifications, совместимое с автономным режимом, но вам нужно будет найти способ отследить, какое уведомление не прочитано пользователем. (Возможно статус некоего)

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