一、开启APNS
1.创建证书 见证书创建
2.Xcode 设置 开启后台状态模式
二、代码实现
1.注册APNS 在需要实现的类中注册apns,非必需AppDelegate。
-(void)requestAPNS:(void(^)(BOOL grant))finish{
UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
[center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert | UNAuthorizationOptionBadge | UNAuthorizationOptionSound) completionHandler:^(BOOL granted, NSError * _Nullable error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (granted) {
[[UIApplication sharedApplication] registerForRemoteNotifications];
} else {
NSLog(@"APNSPush注册失败,用户不允许");
}
finish(granted);
});
}];
center.delegate = self;
}
注册通知,会弹出一次提示框,点击是否允许后,以后不会弹出。 以上是iOS 10之后的注册方式,之前的为:
if (version >= 8.0){
UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeNone|UIUserNotificationTypeSound | UIUserNotificationTypeBadge | UIUserNotificationTypeAlert categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:setting];
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
注册回调 注册通知后系统会在AppDelegate中回调:
- (void)application:(UIApplication *)app didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
}
deviceToken是该设备apns的标记,这样就能准确的将某条消息推送到该设备。获取的token上传到app 对应的推送后台,这样后台就会知晓该设备,或将app 用户和该token 建立联络。整个推送逻辑是:app 后台推送消息->苹果apns服务,这个需要相关接口+推送证书,apns服务再将消息推送到设备端,设备端拿到消息内容后根据需求进行下一步处理。
2 消息接收 消息到达设备后,app 处于非活跃时会展示通知:
[UIApplication sharedApplication].applicationState!=UIApplicationStateActive
点击通知 会走 AppDelegate 的方法:
- (void)application:(UIApplication *)app didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler
{
completionHandler(UIBackgroundFetchResultNewData);
}
点击app 点击app,不会走以上方法,此时,如果app是重新启动,可以在launchOptions 拿到消息内容;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
}
如果app已经启动(即非活跃->入活跃状态),消息怎么拿到,下边 扩展Extension 会讲到。
iOS 10 之后的代理 iOS 10之后可实现 UNUserNotificationCenter 的代理 ,iOS 10之前app 处于活跃时不会展示通知,之后在代理中根据需求实现是否展示:
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(nonnull void (^)(UNNotificationPresentationOptions))completionHandler{
NSLog(@"...");
completionHandler(UNNotificationPresentationOptionBadge|UNNotificationPresentationOptionSound|UNNotificationPresentationOptionAlert);
}
同样代理提供了点击后的方法,如果实现将不再走AppDelegate 中的didReceiveRemoteNotification方法,这样的好处是便于在其他类中集中处理apns。当然不实现还会继续走AppDelegate 中的方法。
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void(^)(void))completionHandler{
NSDictionary* userInfo = response.notification.request.content.userInfo;
completionHandler();
}
红点设置及注销apns app打开后设置icon红点数:
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
如果app用户退出登录不需要再推送,则注销apns:
-(void)stopRotemNotification
{
[[UIApplication sharedApplication] unregisterForRemoteNotifications];
}
三、Extension
iOS 10之后可以增加 NotificationServiceExtension,来截获消息,在展示通知前对消息做一些处理,如给通知栏加图片,增加附件,网络请求等;走完了NotificationServiceExtension 中的方法后,再走app中通知相关的方法。另外可以将此消息传给app,这样就可以解决app不点击拿不到消息的问题。为什么说:将此消息传给app,因为Extension 相对你的app是个独立的app,可以说是个副app。既然是单独的app,那么就需要和你的主app,用group id建立联络;同样主、副app共享的数据已需要建立联络;用到的代码也是独立的,虽然Extension 的代码在同一个工程目录下,但不能用主app 的代码,这时要么建立动态库公用,要么复制一份代码到Extension下,所以Extension中尽量不要牵扯的太多,不然工程复杂度加倍,上线的ipa 包体加倍。
1.创建group id Extension 数据共享前提:需在开发者中心创建app groups-> 添加到对应app的id中->同时设置项目和Extension的app groups
2.NotificationServiceExtension
实现的前提是app 后台发送的通知中有"mutable-content" 值为1;如:
"aps" : {"sound" : "default",
"content-available" : "1",
"alert" : "内容s的方式",
"mutable-content" : "1",
"category" : "",
"badge" : 1
}
1.创建NotificationServiceExtension,配置group id 设置对应的group id
2.处理事件 3.选择目标工程,运行Extension
3.NotificationContentExtension 使用 NotificationContentExtension 自定义UI,通知到达后“下拉通知”依照需求展示通知内容,并进行交互。需要设置category"。
1.创建 2. category ,在ContentExtension下生成的info.plist中进行(多个或一个)设置 3.处理事件 、UI设置、时间响应。示例: 4.含有Extension 的app打包:直接打包你的app,在输出时会自动将你的Extension,打到一起。
四、数据共享
NSUserDefaults、CoreData的,Extension 与主app数据共享。
1.NSUserDefaults 使用initWithSuiteName:方法来获取一个NSUserDefaults对象,在主、副app中存取数据:
NSUserDefaults *userDefaults = [[NSUserDefaults alloc] initWithSuiteName:@"你的group id"];
[userDefaults setValue:@"value" forKey:@"key"];
[userDefaults valueForKey:@"key"];
1.CoreData* 就是把创建CoreData 代码中的:
[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
换成即可使用
[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"你的group id"]
四、文件共享
Extension 有些处理逻辑的代码、类等和主app一样,少的话可以复制代码到Extension 的文件中。多的话点击文件的.m文件,在 Xcode 的右侧工具栏中的找到 Target Membership 勾选 Extension 名,把它们加到 Extension Target 中,引入.h 文件即可。 如果公用文件中,还有其他import 的文件,都需要进行以上操作。 这样如果文件太多,可以将公用的文件做成动态库进行使用。
最后,如果Extension 中牵扯的太多,公用文件中又包含动、静态库、其他文件等,多层套用,如果没有好的规划和文件管理思维,建议不要公用了,复制代码吧
|