Rich Push & Rich Push Content Extensions

IOS 10+ ile birlikte artık push bildirimlerinde rich content yapısına geçilebilmektedir. OS’un uygulamalara sağlamış olduğu bildirim alanında gösterilebilecek content içerikleri şu an için şu şekildedir;

  • .png, .jpeg, .jpg vb imaj dosyaları
  • .gif dosyaları
  • .wav, .aaf, .caf, .mp3, vb ses dosyaları
  • .mp4 vb video dosyaları
  • Custom aksiyonları olan yazılı veya emojili butonlar
  • Uygulama logosu
  • Uygulama ismi veya emoji başlıkları
  • Bildirim alanını dismiss etmek için kapatma-silme butonu

Rich push gösterimi için olması gereken yapılar ise şu şekildedir;

  • Uygulamaya ait application ve bundle id
  • Push için oluşturulmuş .p12, .cer sertifika ve .mobileprovision dosyaları
  • Minimum iOS10+ deployment target özelliği
  • Rich push extension özelliği
  • APN ile gönderilen payload json bloğu
  • Kod içinde APNe push kaydı yapılması
  • Bildirimlerin alınması için kod yapısının geliştirilmesi
  • Rich push görsellerinin vb dosyaların arka planda çekilmesinin sağlanması
  • İstenirse payload içersinde iOS10+ ile eklenen ek özellikler
  • İstenirse uygulama içinde istenirse dışında iken gelen pushların gösterilmesi veya aksiyon alınması
  • İstenirse rich push content özelliği

Rich push ile yapılabilecekler ise şu şekildedir;

  • Bildirim alanında thumbnail olarak gösterilebilecek görsel alanları
  • Bildirim içinde uygulama logosu-başlığı-emoji yazısı
  • Bildirim içinde gösterilmek istenen content dosyalarının arka planda çekilmesini sağlayacak fetch yapısı
  • İstenirse bildirim alanında eklenebilecek custom butonlar
  • Custom butonlara basınca kilit ekranında, backgroundda uygulamaya girmeden veya uygulamaya yönlendirme yaparak çalışması özelliği
  • Bildirimlerin komple dismiss edilebilmesi-tek tek kapatılabilmesi
  • Bildirimlerde okunmayanların komple listesinin alınması ve silinebilmesi
  • Bildirim görsel alanında detaylı görünüm
  • Bİldirim alanında istenirse yazı yazıp bir işlem yapabilme
  • İstenirse rich push content özelliği
  • İstenirse bildirimlere eklenebilecek butonlarla carousel gibi çalışabilecek görsel geçişlerinin sağlanması
  • İstenirse iOS 10+ da geçerli olacak şekilde uygulama içinde veya dışında iken gelen pushların gösterilmesi veya aksiyon alınması
  • İstenirse bildirim içinde bold yazıların yazılabilmesi

Bu yazımda eski push gösterimi ve push yapısının çalıştırılması ile ilgili bilgi vermek yerine rich push üzerine daha çok bilgi vereceğim. Minimum versiyon olarak iOS 10+ kuralı olmakla beraber temelden ileri seviyeye doğru geçiş yapacağız.

IOS10+ ile birlikte gelen UNUserNotificationCenter classı üzerinde tüm işlemler yapılmalı ve register-receive metotları uygulama kodlarına eklenmelidir. Eğer uygulamanız iOS 8-9 destekler bir haldeyse eski user notification registration özelliğini kodda korumanız da gerekecektir.

https://developer.apple.com/documentation/usernotifications/unusernotificationcenter

Rich push extension yapısının yaratılması
Xcode içinde uygulamanıza ait Target kısmında ekleme yaparak açılan aiağıdaki pencerede Notification Service Extension templateını seçiyoruz.

Burada her uygulamanın bir application ve bundle idsi, sertifika ve provizyon dosyaları olduğu gibi yaratacağımız notification service extension targetının da bundle idsi, sertifika ve provizyon dosyaları oluşturulmalıdır. Bunun için Apple developer hesabından rich push targetı için ana uygulamaya ait application alanından bir bundle id ve buna bağlı provizyon dosyaları oluşturup burada açılan pencerede bu bilgileri eklemelisiniz.

Not: Eğer bu işlemleri yapmadan notification service extension (NSE) yapısını oluşturup build etmeye çalışırsanız hata verecek ve sign aşamasında fail oluşacaktır. Her NSE özellikli uygulamada 2 tane bundle id, developer ve distribution olmak üzere 2şer tane provizyon ve developer ve distribution olmak üzere sertifika dosyaları bulunmalıdır.

Arka planda content dosyalarının çekilmesi ve gösterilmesi
Açılan NSE classında aşağıdaki kod yapısı eklenmelidir.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#import "NotificationService.h"

@interface NotificationService ()

@property (nonatomic, strong) void (^contentHandler)(UNNotificationContent *contentToDeliver);
@property (nonatomic, strong) UNMutableNotificationContent *bestAttemptContent;

@end

@implementation NotificationService

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
   self.contentHandler = contentHandler;
   self.bestAttemptContent = [request.content mutableCopy];

   // Modify the notification content here...
   //self.bestAttemptContent.body = [NSString stringWithFormat:@"%@ [modified]", self.bestAttemptContent.body];

   // check for media attachment, example here uses custom payload keys mediaUrl and mediaType
   NSDictionary *userInfo = request.content.userInfo;
   if (userInfo == nil) {
      [self contentComplete];
      return;
   }

   NSString *mediaUrl = userInfo[@"attachmentUrl"];
   // NSString *mediaType = userInfo[@"mediaType"];

   // mediaUrl = @"https://pbs.twimg.com/media/CaSyHXPUMAA-1mo.jpg";
   // mediaUrl = @"http://lifeimprovementmedia.com/wp-content/uploads/2015/12/developing-a-brand.jpg";
   // mediaUrl = @"http://orig00.deviantart.net/a7f4/f/2016/021/d/2/ikon_png_pack_by_aug19th-d9oqur6.png";
   // mediaUrl = @"https://upload.wikimedia.org/wikipedia/commons/e/e5/HTTPS_icon.png";
   // mediaUrl = @"http://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4";
   // mediaUrl = @"http://www.barbneal.com/wp-content/uploads/bugs01.mp3";//big data
   // mediaUrl = @"http://ageheureux.a.g.pic.centerblog.net/e561f9cf.gif";
   // mediaUrl = @"http://clips.vorwaerts-gmbh.de/VfE_html5.mp4";

   if (mediaUrl == nil) {//if (mediaUrl == nil || mediaType == nil) {//
      [self contentComplete];
      return;
   }

   // load the attachment
   [self loadAttachmentForUrlString:mediaUrl withType:nil completionHandler:^(UNNotificationAttachment *attachment) {
      if (attachment) {
         self.bestAttemptContent.attachments = [NSArray arrayWithObject:attachment];
      }
      [self contentComplete];
   }];
}

- (void)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.
   [self contentComplete];
}

- (void)contentComplete {
   self.contentHandler(self.bestAttemptContent);
}

- (NSString *)fileExtensionForMediaType:(NSString *)type {
   NSString *ext = type;

   if ([type isEqualToString:@"image"]) {
      ext = @"jpg";
   }

   if ([type isEqualToString:@"video"]) {
      ext = @"mp4";
   }

   if ([type isEqualToString:@"audio"]) {
      ext = @"mp3";
   }

   return [@"." stringByAppendingString:ext];
}

- (void)loadAttachmentForUrlString:(NSString *)urlString withType:(NSString *)type completionHandler:(void(^)(UNNotificationAttachment *))completionHandler {

   __block UNNotificationAttachment *attachment = nil;

   NSURL *attachmentURL = [NSURL URLWithString:urlString];

   // NSString *fileExt = [self fileExtensionForMediaType:type];
   // NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
   // [[session downloadTaskWithURL:attachmentURL
   // completionHandler:^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) {
   // if (error != nil) {

   // } else {
   // NSFileManager *fileManager = [NSFileManager defaultManager];
   // NSURL *localURL = [NSURL fileURLWithPath:[temporaryFileLocation.path stringByAppendingString:fileExt]];
   // [fileManager moveItemAtURL:temporaryFileLocation toURL:localURL error:&error];
   //
   // NSError *attachmentError = nil;
   // attachment = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:localURL options:nil error:&attachmentError];
   // if (attachmentError) {
   // NSLog(@"HOPIEXT-attachment error:%@", attachmentError.localizedDescription);
   // }
   // }
   // completionHandler(attachment);
   // }] resume];

   NSArray *tempArray = [urlString componentsSeparatedByString:@"."];
   if (tempArray.count > 0) {
      NSString *fileExt = [tempArray objectAtIndex:tempArray.count-1];
      fileExt = [@"." stringByAppendingString:fileExt];

      NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
      [[session downloadTaskWithURL:attachmentURL completionHandler:^(NSURL *temporaryFileLocation, NSURLResponse *response, NSError *error) {
         if (error) {

         }
         else {
            NSFileManager *fileManager = [NSFileManager defaultManager];
            NSURL *localURL = [NSURL fileURLWithPath:[temporaryFileLocation.path stringByAppendingString:fileExt]];
            [fileManager moveItemAtURL:temporaryFileLocation toURL:localURL error:&error];

            NSError *attachmentError = nil;
            attachment = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:localURL options:nil error:&attachmentError];
            if (attachmentError) {
               // istenirse dummy görsel cekilebilir
            }
         }
         completionHandler(attachment);
      }] resume];
   }
   else {
      // istenirse dummy görsel cekilebilir
   }
}

Bu şekilde payload içersinde iletilecek content ve attachment değerlerindeki content dosyaları bu kod yardımıyla arka planda indirlecektir. Buradaki extensionın amacı ana uygulama yapısındaki aşağıdaki push alma yapısına ekstra özellik getirip dosyayı indirmek ve bildirim içinde otomatik görseli göstermektir.

Push geldiğinde aşağıdaki kod tarafından push alınacak ve NSE kısmında görsel indirilecektir. İndirme başarıyla tamamlanırsa iOS 10+ üzerinde rich push yapısı düzgün şekilde çalışacaktır. Görselin indirilmesinden sonraki aşama artık OS kontrolüne geçmektedir ve uygulama artık bu aşamadan sonra herhangi bir şey yapmamaktadır.

1
2
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
}

Veya

1
2
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo{
}

Bildirim alanındaki ilgili alanlar
IOS10+ rich push yapısında OSun developerlara sağlamış olduğu alanlar görseldeki gibidir;

Burada rich push alanında uygulama ikonu, uygulama ismi görülmektedir. Uygulama isim kısmına istenirse uygulama ismi değiştirilerek gelen pushtaki yazı da değiştirilebilmektedir. Sağ tarafta bildirimin ne zaman geldiği veya bildirim açıldığında bildirimi silme-dismiss etme butonu OS tarafından çıkarılmaktadır.

Payload kısmında bold olmayacak şekilde bir yazı yazmak için atılan payload yapısında eskiden olduğu şekilde body kısmına yazının yazılması yeterlidir.

Payload alanında content tagi 1 ve attachment-url taginde görsele ait url olursa yeni rich push content alanında ilgili görsel görünecektir. İndirme işlemi yukarıdaki kodda arka planda extension aracılığıyla yapılırken bir sorun oluşursa rich push alanında content hiçbir şekilde gösterilmemektedir. Bu görselde örneğin video gösterilmekte.

Buradaki görsellerde ise sağ tarafta indirilen görselin thumbnail hali görünmektedir. Bunun için uygulamanın ayrıcalıklı olarak yapmış oldupğu bir şey bulunmamaktadır. İndirilen ana görsel indrikten sonra eğer kullanıcı rich push alanını detaylıca görmek için çekmemişse thumbnail OS aracılığıyla görünmektedir.

Rich push yapısı ile body kısmında iletilen yazı dışında bold olarak yazması istenen yazılar varsa payloada title-subtitle gibi yazılar eklenmelidir. Bu şekilde title-subtitle payload içinde gelirse OS kendiliğinden bu yazıları bold yapmaktadır. Şu anda bunun en bariz örneği WhatsApp uygulamasında bulunuyor. Bir mesaj geldiğinde gönderen ismi bold ve iç mesaj düz text şeklindedir.

Rich push yapısıyla beraber iletilecek payload boyutu arttırıldığından artık daha uzun yazılar gösterebilmek mümkün.

https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html

İletilecek payload yapısı şu şekilde olmalıdır;

1
2
3
4
5
6
7
8
9
10
{ "aps": {
      "alert": "Hello!",
      "sound": "default",
      "mutable-content": 1,
      "badge": 1
   },
   "data": {
      "attachment-url": "https://example.com/attachment.jpg "
   }
}

Read more at https://www.pluralsight.com/guides/swift/creating-ios-rich-push-notifications#q9FVDXBrZViGdltY.99

Bildirim alanında eklenebilecek butonlar ve aksiyon eklenmesi

Yeni rich push gösterim alanında developer isterse custom butonlar ekleyebilir. Bunun için payload yapısı şu şekilde olmalıdır;

1
2
3
4
5
6
7
8
9
10
11
{ "aps": {
      "alert": "Hello!",
      "sound": "default",
      "mutable-content": 1,
      "badge": 1,
      "category": "myCategoryName"
   },
   "data": {
      "attachment-url": https://example.com/attachment.jpg
   }
}

Read more at https://www.pluralsight.com/guides/swift/creating-ios-rich-push-notifications#q9FVDXBrZViGdltY.99

Info.plist dosyasında ise ekleyeceği buton sayısı kadar alttaki gibi category yapısı eklemek durumunda;

Kodda ise aşağıdaki değişiklikleri yapmak zorunda;

1
2
3
4
5
6
let meowAction = UNNotificationAction(identifier: "meow", title: "Meow", options: [])
let pizzaAction = UNNotificationAction(identifier: "pizza", title: "Pizza?", options: [])

let category = UNNotificationCategory(identifier: "myCategoryName", actions: [meowAction, pizzaAction], intentIdentifiers: [], options: [])

UNUserNotificationCenter.current().setNotificationCategories([category])

Read more at https://www.pluralsight.com/guides/swift/creating-ios-rich-push-notifications#q9FVDXBrZViGdltY.99

Burada option kısmındaki alan boş olsa da istenirse doldurulabilir. Options kısmında bu butona basılınca uygulama arka planda mı işlemini yapacak veya ön plana açıp mı yapacak karar verilebilir. Uygulama ön planda işlem yapacak ise kilit ekranından şşifre alarak mı bu işlemi yapmalı veya direkt içeri mi girmeli karar verilebilir. Arka planda işlem yapacak tiplerde şifre sorulmadan direkt geçilmektedir.

Her buton için category ve her category için de category id gerekmektedir. Bunlar developerın belirleyeceği custom yazı olabilir. Bu değişiklikler yapılınca artık görünecek butonlar aşağıdaki şekildedir;

Burada butonlara basınca aksiyon alınması için ise aşağıdaki şekilde bir işlem yapılmalıdır. Bunun için categoryye ait categori id actionIdentifier ile kontrol edilip hangi butondan basılma aksiyonu geldiği anlaşılıp ilgili işlem yaptırılabilir;

1
2
3
4
5
6
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

   if response.actionIdentifier == "meow" { ... }
   if response.actionIdentifier == "pizza" { ... }
   completionHandler()
}

Read more at https://www.pluralsight.com/guides/swift/creating-ios-rich-push-notifications#q9FVDXBrZViGdltY.99

Bildirim görsel alanında detaylı görünüme geçiş

Yukarıdaki görsellerdeki gibi üstten gelen bildirimlerde yukarıdan aşağıya çekince veya notification centerdaki bildirimlerde sağdan sola çekip Görüntüle deyince bildirim için detaylı görünüme gecilmektedir ve content görseli görüntülenebilmektedir. Bu esnada görseller ortaya büyük halleriyle çıktığı gibi custom butonlarda görünür olacaktır.

Bildirim normal görünümündeyken yukardan aşağıya çekince bildirim altında iOS 10 öncesinde maksimum iki buton ve iOS 10+ ile maksimum 4 buton gösterilebilmektedir. Bu sayılardan daha fazla buton veya aksiyon istenirse önerim More veya Uygulamaya git gibisinden son bir buton eklemek ve kullanıcıyı uygulamaya yöneltmektir. Gerekirse burada kullanıcıya uygulama içinde ana ekranda pushtan gelindiğinden custom bir pencere ve diğer seçenekler çıkartılabilir.

Bildirimlerdeki custom butonlara yazı yazılabileceği gibi emoji karakterlerde eklemek mümkün. Örn. Swarm uygulamasında Beğen yerine kalp ikonu koymaları gibi.

Bunları şu şekilde görebiliriz;

Payload yapısındaki yenilikler ve bildirim ekranına yansıyışları

  • Payload yapısında boyut artışı yukarıdaki linkteki gibi iOS10+ ile sağlanmıştır: Artık daha fazla karakterde yazı atılabiliyor.
  • Payload içinde title ve subtitle gibi tagler eklendiğinde yazıların istenirse bold olması sağlandı. Burada title ve subtitle yazılarının görünümünü uygulama değil OS yapmaktadır. Bu nedenle üstten bildirim görünümlerinde, bildirimin çekince açılan detaylı görünümlerinde veya görüntüle deyince açılan alanlarda veya notification centerda görüntülerken nasıl görüneceği sadece OS kontrolündedir.
  • Category tagiyle buton eklenebilmektedir.


Bildirimlerin silinmesi ve dismiss edilmesi

  • IOS10+ ile birlikte uygulamaya gelen bildirimlerin toplu silinebilmesi mümkün kılınmaya başlandı. Bunun için linkteki
    -getDeliveredNotificationsWithCompletionHandler:; metodu kullanılmalıdır. https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649520-getdeliverednotifications
  • Bildirimlerin kendi identifier-id değerlerine göre tek tek silinebilmesi için -removeDeliveredNotificationsWithIdentifiers; metodu kullanılmalıdır. https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649500-removedeliverednotificationswith?language=objc
  • Bildirimlerin toplu şekilde kodda silinebilmesi için; -removeAllDeliveredNotifications; metodu kullanılmalıdır. https://developer.apple.com/documentation/usernotifications/unusernotificationcenter/1649502-removealldeliverednotifications?language=objc
  • Bildirimlerin sağ üst tarafındaki X kapatma-silme butonuyla bildirimler dismiss edilebilmektedir.
  • Rich push tipinde bir bildirim yapabilmek için aşağıdaki kod yapısına benzer bir yapı kodunuzda bulunması gerekmektedir;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
    [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];

    [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
       if (!error && granted) {
          UNNotificationAction *pushAction1 = [UNNotificationAction actionWithIdentifier:[NSString stringWithFormat:@"%i",100] title:@"Görüntüle" options:UNNotificationActionOptionForeground];

          UNNotificationAction *pushAction2 = [UNNotificationAction actionWithIdentifier:[NSString stringWithFormat:@"%i",101] title:@"Favorile"
    options:UNNotificationActionOptionNone];

          UNNotificationCategory *pushCategoryFor1 = [UNNotificationCategory categoryWithIdentifier:[NSString stringWithFormat:@"%i",1] actions:@[pushActionForShowCampaign, pushActionForFavoriteCampaign] intentIdentifiers:@[] options:UNNotificationCategoryOptionNone];

          [center setNotificationCategories:[[NSSet alloc] initWithObjects:pushCategoryForCampaignDetailPage, nil]];

          dispatch_sync(dispatch_get_main_queue(), ^{
             [[UIApplication sharedApplication] registerForRemoteNotifications];
          });
       }
       else {

       }
    }];

Burada options kısmında aşağıdaki tiplerde optionlar kurulabilmektedir;

  • UNNotificationActionOptionAuthenticationRequired -> kilit ekranında cihazın şifresinin sorulması ve ardından push yönlenmesinin-işlemlerinin gerçekleşmesi için
  • UNNotificationActionOptionDestructive -> push altında yazısı kırmızı renkli buton kullanmak için (bunlar genellikle cancel-dismiss gibi işlevleri olan butonlar için kullanılıyor)
  • UNNotificationActionOptionForeground -> bildirimdeki butona basınca uygulamayı ön plana alıp yönlenmelerin gerçekleşmesi için
  • UNNotificationActionOptionNone -> bu kullanılırsa butona basınca backgroundda işlem yapmak için kullanılıyor. Uygulama ön plana gelmiyor ve direkt kod içinde ilgili metoda düşüp kullanıcının aksiyonu gerçekleştiriliyor. Bunun için aşağıdaki kodlar kullanılabilir;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    //iOS8+
    -(void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void (^)())completionHandler {
       [self handleActionOnPushNotification:userInfo identifier:identifier];
       completionHandler();
    }



    //iOS9+
    -(void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler {
       [self handleActionOnPushNotification:userInfo identifier:identifier];
       completionHandler();
    }



    //iOS10+
    //Called to let your app know which action was selected by the user for a given notification.
    -(void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler{
       NSDictionary *userInfo = response.notification.request.content.userInfo;
       [self handleActionOnPushNotification:userInfo identifier:response.actionIdentifier];
       completionHandler();
    }

Category alanında da options bulunmaktadır ve bunun da değerleri olarak aşağıdaki değerler kullanılabiliyor;

  • UNNotificationCategoryOptionNone -> default değeri
  • UNNotificationCategoryOptionCustomDismissAction -> bildirimlerin dismiss actionlarını customlaştırmak için. Burada bildirimin dismiss edilmesi durumunda kod içine yansıyacak şekilde bir geliştirme yapılabilir. Ancak bildirimin dismiss edildiği bilgisi pratikte koda yansımamaktadır.
  • UNNotificationCategoryOptionAllowInCarPlay -> car play uygulamaları için

Bunları şu şekilde görebiliriz;

Rich push bildirim alanında yazı yazabilme

Bunun için UNNotificationAction classından türeyen UNTextInputNotificationAction classı tipinde bir action yaratılmalıdır. Aşağıdaki metot yardımıyla bildirimi çekip detayını açınca yazı yazma alanı otomatik çıkacaktır.

Burada bildirimde yazı alanını açmak için kullanılan buton içi yazıyı, text alanı yanına yazacak butondaki yazıyı ve text alanında hiçbir şey yazmadan önce görünecek placeholder yazısını değiştirebiliyoruz.

1
+(instancetype)actionWithIdentifier:(NSString *)identifier title:(NSString *)title options:(UNNotificationActionOptions)options textInputButtonTitle:(NSString *)textInputButtonTitle textInputPlaceholder:(NSString *)textInputPlaceholder;

Butona basınca kod tarafına aşağıdaki parametrelerle OS yazıları yansıtmaktadır;

1
-(void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo withResponseInfo:(NSDictionary *)responseInfo completionHandler:(void (^)())completionHandler

Bunları şu şekilde görebiliriz;

Rich Push Content Extension yapısının yaratılması

Öncelikle rich push content extension yapısının yine Target altından eklenmesi gerekmektedir. Alttaki görüntü ile eklenmelidir;

Ardından yine NSEdeki gibi bu template yapısı için de Apple Developer tarafında 1 bundle id ve developer-distribution için 1er sertifika ve developer-distribution için 1er provizyon oluşturup bu targeta eklenmelidir. Aksi durumda kod derlenmeyecek ve rich push content extension (NCE) sign etmeyecektir.

Bildirim content alanında carouselimsi bir yapı kurma

Yukarıdaki NCE yapısını kurduktan sonra yine aynı NSEdeki gibi background fetch özelliği kullanılacaktır. Bunun dışında bildirim altına yukarıda bahsetmiş olduğum gibi bir action button daha eklenmelidir. Kullanıcı bu butona basınca bildirim içindeki content alanındaki görsel başka bir görsel ile yer değiştirilecektir.

Not: Buradaki yapı ile content alanındaki görsel carouselimsi bir yapıya sahip olmuş oluyor. IOSta şu an için görsel alanında sağa-sola swipe edip görseli değiştirme gibi bir yapı bulunmuyor.

Bir buton yardımıyla görsel değişikliği yapmak için aşağıdaki kod yapısı kullanılmalıdır;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#import "NotificationViewController.h"
#import <UserNotifications/UserNotifications.h>
#import <UserNotificationsUI/UserNotificationsUI.h>

@interface NotificationViewController () <UNNotificationContentExtension>

@property IBOutlet UIButton *button;

-(IBAction)customButtonPressed:(id)sender;

@end

@implementation NotificationViewController

-(void)viewDidLoad {
   [super viewDidLoad];
   // Do any required interface initialization here.
}

-(void)didReceiveNotification:(UNNotification *)notification {
NSDictionary *userInfo = notification.request.content.userInfo;
[self.button setTitle:notification.request.content.body forState:UIControlStateNormal];
}

-(void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(UNNotificationContentExtensionResponseOption))completion{
   if ([response.actionIdentifier isEqualToString:[NSString stringWithFormat:@"%i",PUSH_ACTION_IDENTIFIER_CHANGE_BUTTON]]) {
      [self.button setTitle:@"changed" forState:UIControlStateNormal];

      completion(UNNotificationContentExtensionResponseOptionDismiss);
   }
}

-(IBAction)customButtonPressed:(id)sender {
   UIAlertController *alertvc = [UIAlertController alertControllerWithTitle:@"Custom button" message:@"pressed" preferredStyle:UIAlertControllerStyleAlert];
   [self presentViewController:alertvc animated:YES completion:nil];
}

@end

NCE yaratıldığında custom content alanı göstermek için bu push tipine bir action eklendiğinden kullanıcı bu action buttona basınca aksiyon alıp NCE aracılığıyla content alanına etki edebilecektir.

NCE oluşturulduktan sonra developera bir storyboard oluşturulmaktadır. Bu storyboarda örneğin aşağıdaki gibi bir ayrı button ekleyelim;

  • Bildirime ait action butonuna (content içindeki değil) basılınca yaratacağımız action ile belirli tipteki istediğimiz aksiyonu kullanıcıya aldırabiliriz.
  • Action butonuna basılınca content içindeki butonun yazısını değiştirme veya arkadaki örneğin yeşil imaj alanını değiştirme (caroselimsi yapı), vb. şeyler yapılabilir.

Not: IOSta Content alanındaki butona veya herhangi bir şeye kullanıcının basması veya aksiyon alması şu an için mümkün değildir.

Uygulama içinde veya dışındayken gelen rich pushların gösterilmesi

Gelen rich pushlar genel olarak kullanıcı uygulama içinde değilken (arka plandayken veya killken) gelmekte ve üstten OS tarafından gösterilmektedir.

Burada kullanıcıya uygulama içindeyken gelen pushları üstten yine de göstermek istenirse aşağıdaki metot koda eklenmelidir;

1
2
3
4
5
//Called when a notification is delivered to a foreground app.
-(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler{
   NSDictionary *userInfo = notification.request.content.userInfo;
   completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
}

IOS 10+ ile artık notification centera ait arayüz ile (uygulama arkada iken üstten gelen bildirim alanı ile aynı) kullanıcı uygulama içinde olsa bile bildirimi görebilmekte ve haberi olabilmektedir. Hatta burada üstte görünen bildirime basıp aksiyon alabilmektedir veya yukardan aşağıya bildirimi çekip action buttonları gösterebilmekteyiz.

IOS10+ ile yeni UNNotification classından aşağıdaki şekillerde detaylı user info bilgilerini alıp kullanabilmekteyiz. Burada UNNotificationResponse gibi classlar kullanılabilir;

1
NSDictionary *userInfo = response.notification.request.content.userInfo;