iOS 10 Rich Media Push Notification (Media Attachment) in Objective-C
Solution 1
your code is ok, it just expects a different push notification data format:
Try replacing this part:
// Create the payload body
$body['aps'] = array(
'alert' => $message,
'sound' => 'default',
'mutable-content' => 1,
'category'=> "pusher"
);
$body['data'] = array(
'mediaUrl' => "http://www.alphansotech.com/wp-content/uploads/2015/12/Push-notification-1.jpg",
'mediaType' => "jpg"
);
with:
$body = array(
'aps' => array(
'alert' => 'Rich notification',
'sound' => 'default',
'mutable-content' => 1
),
'mediaUrl' => 'https://upload.wikimedia.org/wikipedia/commons/thumb/2/2a/FloorGoban.JPG/1024px-FloorGoban.JPG',
'mediaType' => 'image'
);
Please note, that image should be accessible via https://
Solution 2
Additional caveat for this not to work is having the Notification Service
Deployment Target
value that's not supported by your test device.
In my case the Notification Service template had automatically set its Deployment Target
to 10.2
while my test device is 10.1
I wasted hours configuring my extension setup while its already working all along!
Mohammad Ashraf Ali
Software engineer at NotifyVisitors with a passion for developing ios apps. Love to share what I learn with the rest of the developer community at StackOverflow.
Updated on June 12, 2022Comments
-
Mohammad Ashraf Ali almost 2 years
I want to add Media especially images and videos in iOS 10 Push notification but images are not working in push. How to do that in Objective-C? My Code is as follows:
AppDelegate.h
#import <UIKit/UIKit.h> #import <CoreLocation/CoreLocation.h> #import <UserNotifications/UserNotifications.h> @interface AppDelegate : UIResponder <UIApplicationDelegate,CLLocationManagerDelegate,UNUserNotificationCenterDelegate> @property (strong, nonatomic) UIWindow *window; @end
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { if(SYSTEM_VERSION_LESS_THAN( @"10.0" )) { [[UIApplication sharedApplication] registerUserNotificationSettings:[UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge) categories:nil]]; [[UIApplication sharedApplication] registerForRemoteNotifications]; } else{ UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; center.delegate = self; [center requestAuthorizationWithOptions:(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge) completionHandler:^(BOOL granted, NSError * _Nullable error) { if( !error ) { [[UIApplication sharedApplication] registerForRemoteNotifications]; // required to get the app to do anything at all about push notifications NSLog( @"Push registration success." ); } else { NSLog( @"Push registration FAILED" ); NSLog( @"ERROR: %@ - %@", error.localizedFailureReason, error.localizedDescription ); NSLog( @"SUGGESTIONS: %@ - %@", error.localizedRecoveryOptions, error.localizedRecoverySuggestion ); } }]; } } -(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { NSString * token = [NSString stringWithFormat:@"%@", deviceToken]; //Format token as per need: token = [token stringByReplacingOccurrencesOfString:@" " withString:@""]; token = [token stringByReplacingOccurrencesOfString:@">" withString:@""]; token = [token stringByReplacingOccurrencesOfString:@"<" withString:@""]; NSLog(@"Device Token is \n%@",token); } -(void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { NSLog(@"Error:%@",error); } -(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo { if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO( @"10.0" )) { [self application:application didReceiveRemoteNotification:userInfo fetchCompletionHandler:^(UIBackgroundFetchResult result){}]; } else { /// previous stuffs for iOS 9 and below. I've shown an alert wth received data. } } -(void) application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void(^)(UIBackgroundFetchResult))completionHandler { // iOS 10 will handle notifications through other methods if( NOTIFY_VISITORS_SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO( @"10.0" ) ) { NSLog( @"iOS version >= 10. Let NotificationCenter handle this one." ); // set a member variable to tell the new delegate that this is background return; } NSLog( @"HANDLE PUSH, didReceiveRemoteNotification: %@", userInfo ); // custom code to handle notification content if( [UIApplication sharedApplication].applicationState == UIApplicationStateInactive ) { NSLog( @"INACTIVE" ); completionHandler( UIBackgroundFetchResultNewData ); } else if( [UIApplication sharedApplication].applicationState == UIApplicationStateBackground ) { NSLog( @"BACKGROUND" ); completionHandler( UIBackgroundFetchResultNewData ); } else { NSLog( @"FOREGROUND" ); completionHandler( UIBackgroundFetchResultNewData ); } } - (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { NSLog( @"Handle push from foreground" ); // custom code to handle push while app is in the foreground NSLog(@"%@", notification.request.content.userInfo); } - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler { NSLog( @"Handle push from background or closed" ); // if you set a member variable in didReceiveRemoteNotification, you will know if this is from closed or background NSLog(@"%@", response.notification.request.content.userInfo);
Then I've added a new target Notification Service Extension as following:
NotificationService.h
#import <UserNotifications/UserNotifications.h> @interface NotificationService : UNNotificationServiceExtension @end
NotificationService.m
#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[@"mediaUrl"]; NSString *mediaType = userInfo[@"mediaType"]; if (mediaUrl == nil || mediaType == nil) { [self contentComplete]; return; } // load the attachment [self loadAttachmentForUrlString:mediaUrl withType:mediaType 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) { NSLog(@"%@", error.localizedDescription); } 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(@"%@", attachmentError.localizedDescription); } } completionHandler(attachment); }] resume]; } @end
and my Notification Service Extension Info.plist is:
And I'm using php Script to send push notification as follows:
TestPush.php
<?php // Put your device token here (without spaces): $deviceToken = 'my device tocken goes here'; // Put your private key's passphrase here: $passphrase = 'mypassphase'; // Put your alert message here: $message = 'Test iOS 10 Media Attachment Push'; //////////////////////////////////////////////////////////////////////////////// $ctx = stream_context_create(); stream_context_set_option($ctx, 'ssl', 'local_cert', 'ck.pem'); stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase); stream_context_set_option($ctx, 'ssl', 'cafile', 'entrust_2048_ca.cer'); // Open a connection to the APNS server $fp = stream_socket_client( 'ssl://gateway.sandbox.push.apple.com:2195', $err, $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx); if (!$fp) exit("Failed to connect: $err $errstr" . PHP_EOL); echo 'Connected to APNS' . PHP_EOL; // Create the payload body $body['aps'] = array( 'alert' => $message, 'sound' => 'default', 'mutable-content' => 1, 'category'=> "pusher" ); $body['data'] = array( 'mediaUrl' => "http://www.alphansotech.com/wp-content/uploads/2015/12/Push-notification-1.jpg", 'mediaType' => "jpg" ); // Encode the payload as JSON $payload = json_encode($body); // Build the binary notification $msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload; // Send it to the server $result = fwrite($fp, $msg, strlen($msg)); if (!$result) echo 'Message not delivered' . PHP_EOL; else echo 'Message successfully delivered' . PHP_EOL; // Close the connection to the server fclose($fp);
Sharing Images and file are hosted on server and push will send its link to show it.
Can anyone help me please.
-
Mohammad Ashraf Ali over 7 yearsIt is working but I'm unable to play youtube video while I have given embed code link. I want to update my code that should support all image, video and audio format.
-
Mohammad Ashraf Ali over 7 yearsI want to play video in push but it is not supporting in above code how to do that can you help me to play video from above code.
-
Ramakrishna over 7 years@Ashraf can you provide any sample demo links to know about the usage and project creation for the rich push notifications??
-
Mohammad Ashraf Ali over 7 yearsto see demo of Rich Media Attachment in Push notification see this link
-
nevan king about 7 yearsCaught by this too.
-
Mehul almost 7 yearsPerfect answer.
-
Swati almost 5 yearsthis helped a lot. Thanks
-
MRizwan33 over 2 yearssuper bro. saved a day.