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

时间:2022-09-02 11:03:36

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:

我想在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);

Then I've added a new target Notification Service Extension as following:

然后我添加了一个新的目标Notification Service Extension如下:

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: Objective-C中的iOS 10 Rich Media推送通知(媒体附件)

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

And I'm using php Script to send push notification as follows:

我正在使用php Script发送推送通知,如下所示:

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.

任何人都可以帮助我。

2 个解决方案

#1


4  

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://

请注意,该图片应通过https://访问

#2


7  

Additional caveat for this not to work is having the Notification Service Deployment Target value that's not supported by your test device.

另外需要注意的是,测试设备不支持Notification Service Deployment Target值。

In my case the Notification Service template had automatically set its Deployment Target to 10.2 while my test device is 10.1

在我的情况下,Notification Service模板在我的测试设备为10.1时自动将其部署目标设置为10.2

I wasted hours configuring my extension setup while its already working all along!

我浪费了几个小时来配置我的扩展设置,而它一直在工作!

#1


4  

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://

请注意,该图片应通过https://访问

#2


7  

Additional caveat for this not to work is having the Notification Service Deployment Target value that's not supported by your test device.

另外需要注意的是,测试设备不支持Notification Service Deployment Target值。

In my case the Notification Service template had automatically set its Deployment Target to 10.2 while my test device is 10.1

在我的情况下,Notification Service模板在我的测试设备为10.1时自动将其部署目标设置为10.2

I wasted hours configuring my extension setup while its already working all along!

我浪费了几个小时来配置我的扩展设置,而它一直在工作!