iOS Silent Notification ile Push Notification Silme

Gökhan Alp
KoçSistem
Published in
4 min readNov 18, 2022

Bu yazımda Firebase ve APNS aracılığıyla önceden gönderdiğimiz notification’ların nasıl silineceğini anlatacağım. Bu yazıda tıpkı Whatsappta biri mesaj sildiği zaman uygulama kapalı olsa bile ilgili notification’un silinmesi gibi silinme işi anlatılacaktır.

Bu iş için 2 şeyi sağlamanız gerekmektedir.
1- Notification geldiğinde uygulama açıkken veya kapalıyken bir kod çalıştırabilmeniz gerekmektedir.
2- Hangi notification’un silinmesi gerektiğini belirtebilmeniz gerekmektedir.

Hemen 1. madde ile başlayalım. İlk etapta yapmamız gereken şey; eğer daha eklemediyseniz AppDelegate’de didReceiveRemoteNotification metodunu eklemek.

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { 
print("didReceiveRemoteNotification called")
...
}

Eğer yukarıdaki metodu eklediyseniz test etmek için bir debug point veya loglama kodu koyup test edebilirsiniz. Devam eden anlatımdaki düzenlemeleri yapmanız halinde (aksi halde bu metod çalışmaz) uygulamaya herhangi bir push notification geldiğinde bu metod çalışacaktır. Uygulama hem foreground hemde backgroundda iken bu metoddaki kod çalışabilmektedir. Aynı zamanda hem uygulama aktifken hemde kapalıykende çalışabilecektir. Bu metodun background modda iken çalışabilmesini sağlayabilmek için Capabilities’den “Background Modes” ekleyip “Remote notifications” ‘u seçmeniz gerekmektedir.

Şimdi gelelim en önemli kısıma. Gönderdiğiniz push notification’un cihaza ulaştığı anda uygulama tarafında kod çalıştırabilmesi ve background’da çalışabilmesi için push notification içine “content-available”: true bilgisini koymanız gerekmektedir.

Unutmadan! Her ne kadar iOS tarafına content-available olarak bilgi gitse de Firebase FCM ve Apple’ın APNS’i için farklı şekilde bilgi gönderilmektedir.

APNS tarafı için (- ile content-available) :

“content-available”: trueÖrnek JSON: 
{
"aps": {
“content_available”: true,
"alert": {},
}
}

Firebase FCM tarafı için (_ ile content_available) :

“content_available”: trueÖrnek JSON:
{
“content_available”: true,
"registration_ids":["..."],
}

İkinci yapacağımız iş ise hangi notificationu sileceğimiz bilgisini eklemek ve bu şartı sağlayan notificationu silmek.

İlk etapta gönderdiğiniz her notification’ların içine custom parametre ekleyin. Ekleyeceğiniz parametreye de bir tane unique id veya herhangi bir unique bir şey ekleyin.

"notifcationCustomData": {
"pushNotificationReferanceId":233,
}

Eğer gönderdiğiniz notification’un belirttiğiniz iddeki notificationu silmesini istiyorsanız ek olarak da silmesi gerektiği görevini ileten bir bilgi daha ekleyin.

"notifcationCustomData": {
"pushNotificationReferanceId":233,
"isReferedNotificationMustRemoved":true
}

Burada mantık şöyle çalışacak siz bir referans idyi tüm notificationlarda gönderiyor olacaksınız. Belirttiğiniz idnin silinmesini istiyorsanız “isReferedNotificationMustRemoved”:true göndererek silmesini emredeceksiniz. Daha sonrasında bu idye sahip notificationları iOS tarafında kod ile siliyor olacağız.

Uygulamanın herhangi bir bildirim mesajı göndermeden gidebilmesi için APNS tarafında “alert” bilgisinin içi boş olarak gitmesi, Firebase FCM tarafında ise “notification” bilgisinin hiç gitmemesi gerekmektedir. Böylece silent notification gönderilmiş olacaktır.

APNS tarafı için full örnek:

{
"aps": {
“content_available”: true,
"alert": {},
},
"notifcationCustomData": {
"pushNotificationReferanceId":233,
"isReferedNotificationMustRemoved":true
}

}

Firebase FCM tarafı için full örnek:

{
“content_available”: true,
"registration_ids":["..."],
"notifcationCustomData": {
"pushNotificationReferanceId":233,
"isReferedNotificationMustRemoved":true
}

}

Firebase’den nasıl notification göndermemiz gerektiğini öğrendik. Şimdi sırada Xcode tarafında uygulama için kod yazmada. didReceiveRemoteNotification metodunun içine gerekli kodları yazıyor olacağız.

Asıl koda girişmeden önce işimizi daha kolay yapabilmek adına bir Serializer kullanarak Dictionary yada String olarak elde edilecek nesneleri Codable class bir modele çevirerek rahatlıkla çalışabilmemizi sağlayacağız. Bu işlem için 3. parti bir kütüphane bulup çalışabilirsiniz veya alttaki kodda ileteceğim kodu kullanarak bir Serializer yazabilirsiniz.

class Serializer {
static func convertStringToModel<T:Codable>(string: String, type: T.Type) -> T? {
guard let data = string.data(using: .utf8) else { return nil }
let model = try? JSONDecoder().decode(T.self, from: data) as T
return model
}
static func convertDictionaryToModel<T:Codable>(dictionary: [String: Any], type: T.Type) -> T? {
guard let data = try? JSONSerialization.data(withJSONObject: dictionary) else { return nil }
let model = try? JSONDecoder().decode(T.self, from: data) as T
return model
}
}

Bir de notification içine koyduğumuz notifcationCustomData bilgisini içerecek bir Codable class yazalım;

class NotifcationCustomDataModel: Codable {
var isReferedNotificationMustRemoved: Bool?
var
pushNotificationReferanceId: Int?
}

Yazacağımız kod özetle şunu sağlayacak pushNotificationReferanceId isimli referans idye sahip notificationları bulup isReferedNotificationMustRemoved isimli parametrenin true olup olmadığına bakacak. Eğer bu değer true ise referans edilen idye sahip tüm notificationların silinmesi gerekecektir. Tespit ettiğimiz bu notification’ların identifier idlerini tespit edip UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: removingIdentifiers) kodu ile silinmesini sağlayacağız.

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { 
print("didReceiveRemoteNotification called")
guard let json = userInfo["notifcationCustomData"] else { return }
let model: NotifcationCustomDataModel? = self.getNotificationModelFrom(rawValue: json)
if let isReferedNotificationMustRemoved = model?.isReferedNotificationMustRemoved, let pushNotificationReferanceId = model?.pushNotificationReferanceId, isReferedNotificationMustRemoved == true {
UNUserNotificationCenter.current().getDeliveredNotifications { notifications in
var
foundIdentifiers = [String]()
for
notification in notifications {
let
notificationModel = self.getNotificationModelFrom(rawValue: notification.request.content.userInfo["notifcationCustomData"])
if notificationModel?.pushNotificationReferanceId == pushNotificationReferanceId {
foundIdentifiers.append(notification.request.identifier)
}
}
if foundIdentifiers.count > 0 {
UNUserNotificationCenter.current().removeDeliveredNotifications(withIdentifiers: foundIdentifiers)
}
completionHandler(.noData)
}
} else {
completionHandler(.newData)
}
}
func getNotificationModelFrom(rawValue: Any?) -> NotifcationCustomDataModel? {
var model: NotifcationCustomDataModel? = nil
if
let dictionary = rawValue as? [String: Any] {
model = Serializer.convertDictionaryToModel(dictionary: dictionary, type: NotifcationCustomDataModel.self)
} else if let string = rawValue as? String {
model = Serializer.convertStringToModel(string: string, type: NotifcationCustomDataModel.self)
}
return model
}

Bütün anlatımları uyguladığınızda ilettiğiniz referans idsini içeren tüm notificationların silinmesini sağlayabileceksiniz. Bu anlatımdaki örneklerde silme işlemi yapılması için silent notification yolluyoruz ve uygulamamız didReceiveRemoteNotification içersindeki kodları çalıştırarak silme işlemini yapıyor.

Herkes için faydalı olması dileğiyle,
Gökhan ALP

--

--