iOS精品文章消息推送推送

iOS推送小结

2017-07-13  本文已影响363人  毅个天亮

文章的Demo地址:iOS-Push
Demo中的推送测试可以使用类似 Easy APNs Provider的工具,结合自己的证书进行测试。

00WX20170713-095411.png

1.普通推送基本设置

1.1 创建项目,开启远程推送功能

在Cababilities中打开Push Notification开关


WX20170815-184013.png

5. Notification Content Extension

Notification Content Extension 是一个定制化展示本地和远程通知的插件,开发者可以自定义其中展示的内容,常常会结合上面的Notification Service Extension插件和UNNotificationCategoryUNNotificationAction 使用做成带有交互的推送内容。

ExampleExample

整体流程为:

  1. 注册Notification Category ,其中包含Action.
  2. 推送Mutable-Content的通知,在Service Extension中下载对应的多媒体消息,重新生成通知内容,并指定通知的categoryIdentifier
  3. 用户3D-Touch推送会启动Notification Content Extension,在其中进行通知的定制化展示。
  4. 用户触发交互(即UNNotificationAction)后,在UNUserNotificationCenter 代理方法中进行处理。在Notification Content Extension中也可以进行初步处理,并决定是否将Action转发到UNUserNotificationCenter

整体效果:

ExampleExample

Demo推送内容:

{
  "aps" : {
    "alert" : {
      "title" : "Message",
      "body" : "Your message Here"
    },
    "badge" : 1,
    "content-available" : 1,
    "mutable-content" : 1,
    "catId" : "action1" // 自定义字段,
    }
}

</br>

5.1 创建Notification Content Extension

新建一个Target,选择Notification Content Extension,其BundleId应该在原项目BundleId的命名空间下。

CreateContentExtensionCreateContentExtension

创建后会增加Target的文件:


ContentExtensionFilesContentExtensionFiles

.h中可以看到其实这是一个UIViewController子类,我们可以添加各种视图。

// NotificationViewController.h
#import <UIKit/UIKit.h>

@interface NotificationViewController : UIViewController

@end
// NotificationViewController.m
@interface NotificationViewController () <UNNotificationContentExtension>

.m中可以看到这个控制器遵守UNNotificationContentExtension协议,协议中有如下方法和属性:

@protocol UNNotificationContentExtension <NSObject>

// This will be called to send the notification to be displayed by
// the extension. If the extension is being displayed and more related
// notifications arrive (eg. more messages for the same conversation)
// the same method will be called for each new notification.
- (void)didReceiveNotification:(UNNotification *)notification;

@optional

// If implemented, the method will be called when the user taps on one
// of the notification actions. The completion handler can be called
// after handling the action to dismiss the notification and forward the
// action to the app if necessary.
- (void)didReceiveNotificationResponse:(UNNotificationResponse *)response completionHandler:(void (^)(UNNotificationContentExtensionResponseOption option))completion;

// Implementing this method and returning a button type other that "None" will
// make the notification attempt to draw a play/pause button correctly styled
// for that type.
@property (nonatomic, readonly, assign) UNNotificationContentExtensionMediaPlayPauseButtonType mediaPlayPauseButtonType;

// Implementing this method and returning a non-empty frame will make
// the notification draw a button that allows the user to play and pause
// media content embedded in the notification.
@property (nonatomic, readonly, assign) CGRect mediaPlayPauseButtonFrame;

// The tint color to use for the button.
@property (nonatomic, readonly, copy) UIColor *mediaPlayPauseButtonTintColor;

// Called when the user taps the play or pause button.
- (void)mediaPlay;
- (void)mediaPause;

@end


@interface NSExtensionContext (UNNotificationContentExtension)

// Call these methods when the playback state changes in the content
// extension to update the state of the media control button.
- (void)mediaPlayingStarted __IOS_AVAILABLE(10_0) __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __OSX_UNAVAILABLE;
- (void)mediaPlayingPaused __IOS_AVAILABLE(10_0) __TVOS_UNAVAILABLE __WATCHOS_UNAVAILABLE __OSX_UNAVAILABLE;

@end

除了Require的方法之外,didReceiveNotificationResponse:completionHandler:负责处理推送Action交互,而其他的用来控制视频的播放。下面的示例中会使用到。

最下方还有一个NSExtesnsionContext类,暂时不清楚它怎么使用。

Content Extension的Info.plist中的内容:


InfoInfo

UNNotificationExtensionDefaultContentHidden,插件默认会展示推送的内容(Title、subtitle、body,不展示Attachment),通过这对键值来控制是否隐藏原始内容。

UNNotificationExtensionCategory ,值类型可以为String/Array,通知的类别,只有类别ID在此之中的通知才会进入Notification Content Extension中被处理。

UNNotificationExtensionInitialContentSizeRatio , 视图的宽高比。视图的最终大小(主要是高度),会受VC的preferredContentSize 、sb中的约束和视图高度、这个比例3者的影响。优先级从前到后下降。

5.2 编码

首先在申请通知权限成功后,设置通知的类别和Action

UNNotificationAction *action1 = [UNNotificationAction actionWithIdentifier:@"checkoutAction" title:@"查看" options:UNNotificationActionOptionAuthenticationRequired|UNNotificationActionOptionForeground];

UNTextInputNotificationAction *action2 = [UNTextInputNotificationAction actionWithIdentifier:@"replyAction" title:@"回复" options:0 textInputButtonTitle:@"发送" textInputPlaceholder:@"回复消息"];

// 此处categoryIdentifier应该是上面Info.plist中UNNotificationExtensionCategory包含的值
UNNotificationCategory *cat = [UNNotificationCategory categoryWithIdentifier:@"action1" actions:@[action1,action2] intentIdentifiers:@[] options:UNNotificationCategoryOptionNone];
                        
[center setNotificationCategories:[NSSet setWithObjects:cat, nil]];
                        
[center getNotificationCategoriesWithCompletionHandler:^(NSSet<UNNotificationCategory *> * _Nonnull categories) {
    NSLog(@"get cat:%@",categories);
}];

Notification Service Extension 中设置推送的categoryIdentifier,如果应用采用了多种Category,一般应该这个标识符包含在推送内容中。

- (void)didReceiveNotificationRequest:(UNNotificationRequest *)request withContentHandler:(void (^)(UNNotificationContent * _Nonnull))contentHandler {
    self.contentHandler = contentHandler;
    self.bestAttemptContent = [request.content mutableCopy];
    // 此处省略推送内容的其他修改和附件的下载
    // 下载完成后,使用fileUrl创建附件
    UNNotificationAttachment *atm = [UNNotificationAttachment attachmentWithIdentifier:@"" URL:url options:options error:&error];
    self.bestAttemptContent.attachments = @[atm];
    // 设置categoryIdentifier
    self.bestAttemptContent.categoryIdentifier = request.content.userInfo[@"aps"][@"catId"];
    self.contentHandler(self.bestAttemptContent);
}

Notification Content Extension 中定制视图,展示推送内容,此处以视频附件为例。

声明协议中与视频播放相关的属性,实现对应的方法。

@interface NotificationViewController () <UNNotificationContentExtension>

@property IBOutlet UILabel *label;

@property (weak, nonatomic) IBOutlet UIImageView *imageView;

@property (nonatomic, strong) AVPlayerLayer *layer;

@property (nonatomic, strong) AVPlayer *player;

@property (nonatomic, assign) UNNotificationContentExtensionMediaPlayPauseButtonType mediaPlayPauseButtonType;

@property (nonatomic, assign) CGRect mediaPlayPauseButtonFrame;

@property (nonatomic, copy) UIColor *mediaPlayPauseButtonTintColor;

@end

@implementation NotificationViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // 设置ContentSize
    self.preferredContentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 300);
}

- (void)didReceiveNotification:(UNNotification *)notification {
    // 
    self.label.text = notification.request.content.body;
    UNNotificationAttachment *atm = notification.request.content.attachments.firstObject;
    if ([atm.URL startAccessingSecurityScopedResource]) {
        self.player = [AVPlayer playerWithURL:atm.URL];
        self.layer = [AVPlayerLayer playerLayerWithPlayer:self.player];
        self.layer.frame = SomeRect;// frame自行计算,此处仅为示例
        self.layer.videoGravity = AVLayerVideoGravityResizeAspectFill;
        [self.view.layer addSublayer:self.layer];
        [atm.URL stopAccessingSecurityScopedResource];
    }
}

- (UNNotificationContentExtensionMediaPlayPauseButtonType)mediaPlayPauseButtonType {
    return UNNotificationContentExtensionMediaPlayPauseButtonTypeOverlay;
}

- (CGRect)mediaPlayPauseButtonFrame {
    CGPoint center = self.imageView.center;
    return CGRectMake(center.x - 25, center.y - 25, 50, 50);
}

- (UIColor *)mediaPlayPauseButtonTintColor {
    return [UIColor lightGrayColor];
}

- (void)mediaPlay {
    [self.player play];
}

- (void)mediaPause {
    [self.player pause];
}

@end

由于在视图初始化时,还不能知道推送内容的最终高度,因此最好以一个固定的高度呈现。上面在代码中使用preferredContentSize来设置。
代码中使用AVPlayer和AVPlayerLayer来展示视频附件,其中获取视频URL时,由于Attachment是由系统管理,在沙盒之外,我们访问URL内容时候需要先获取使用权限:

if ([atm.URL startAccessingSecurityScopedResource]) {
    ...
    [atm.URL stopAccessingSecurityScopedResource];
}
上一篇下一篇

猜你喜欢

热点阅读