概述
苹果给我们的推送有两种,一种是本地推送,一种就是远程推送。本地推送比较简单,在项目中我们基本不会用到,不过还是大致说一下,也好更好的理解远程推送。
本地推送(Local Notification)
思想:
Warning:
1.苹果系统版本号判定floatValue问题
[[[UIDevicecurrentDevice]systemVersion]floatValue];
乍一看是没有什么问题的,因为我整天都是这么写的啊,可是,floatValue确实有这个问题,单精度,相对而言精确度提高,也会带来一定的麻烦,比如我们手机系统是10.0,float之后可能会变成9.998796,但是如果一个人手机系统是10,而我肯定是想让他走10的API的,可是因为判断出问题,导致只能走iOS9的API,那么通知就注册不成,从而用不了通知了。有些同学说没有遇到我说的这种情况啊,那是你没遇到,floatValue确实有这个问题的,所以我们在判断系统版本的时候是不能用这个来做的,怎么弄呢?
代码:
if ([applicationrespondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
[[UIApplicationsharedApplication]registerForRemoteNotifications];
if ([UNUserNotificationCentercurrentNotificationCenter]) {
//iOS 10
[[UNUserNotificationCentercurrentNotificationCenter]setDelegate:self];
UNUserNotificationCenter *center = [UNUserNotificationCentercurrentNotificationCenter];
[centerrequestAuthorizationWithOptions:UNAuthorizationOptionAlert |UNAuthorizationOptionBadge | UNAuthorizationOptionSoundcompletionHandler:^(BOOL granted,NSError *_Nullable error) {
if (granted) {
DebugLog(@"notification push open succeed");
}else {
//reminder user to open the push notification
}
}];
}else {
//ios8~ios10以下
[[UIApplicationsharedApplication]registerForRemoteNotifications];
[[UIApplicationsharedApplication]registerUserNotificationSettings:[UIUserNotificationSettingssettingsForTypes:UIUserNotificationTypeAlert |UIUserNotificationTypeBadge | UIUserNotificationTypeSound categories:nil]];
}
}else {
//ios8以下
[[UIApplicationsharedApplication]registerForRemoteNotificationTypes:UIUserNotificationTypeSound |UIUserNotificationTypeBadge |UIUserNotificationTypeAlert];
}
2.不同位置拿推送来的userInfo
在iOS中如果点击一个弹出通知(或者锁屏界面滑动查看通知),默认会自动打开当前应用。由于通知是由系统调度,那么此时进入应用有两种情况,如果应用程序完全退出,那么会调用“- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions”方法;如果此时应用程序还在运行,前台或者后台,那么会调用“- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification”方法,如果是前者,那么信息回调就放在nofication.userInfo中,但是当我们已经退出了程序,我们可以这样操作:
UILocalNotification *notification = [launchOptions valueForKey:UIApplicationLaunchOptionsLocationKey];
NSDictionary *userInfo = notification.userInfo;
核心代码
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
if ([applicationrespondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
[[UIApplicationsharedApplication]registerForRemoteNotifications];
if ([UNUserNotificationCentercurrentNotificationCenter]) {
//iOS 10
[[UNUserNotificationCentercurrentNotificationCenter]setDelegate:self];
UNUserNotificationCenter *center = [UNUserNotificationCentercurrentNotificationCenter];
[centerrequestAuthorizationWithOptions:UNAuthorizationOptionAlert |UNAuthorizationOptionBadge |UNAuthorizationOptionSoundcompletionHandler:^(BOOL granted,NSError * _Nullable error) {
}];
}else {
//ios8~ios10以下
[[UIApplicationsharedApplication]registerForRemoteNotifications];
[[UIApplicationsharedApplication]registerUserNotificationSettings:[UIUserNotificationSettingssettingsForTypes:UIUserNotificationTypeAlert |UIUserNotificationTypeBadge |UIUserNotificationTypeSoundcategories:nil]];
}
}else {
//ios8以下
[[UIApplicationsharedApplication]registerForRemoteNotificationTypes:UIUserNotificationTypeSound |UIUserNotificationTypeBadge |UIUserNotificationTypeAlert];
}
UILocalNotification *notification = [launchOptionsvalueForKey:UIApplicationLaunchOptionsLocationKey];
NSDictionary *userInfo = notification.userInfo;
NSLog(@"_________%@",userInfo);
returnYES;
}
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
NSLog(@"............%@",notification.userInfo);
}
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings {
if (notificationSettings.types !=UIUserNotificationTypeNone) {
// add local notification
[selfaddLocalNotification];
}
}
- (void)applicationWillEnterForeground:(UIApplication *)applicationNS_AVAILABLE_IOS(4_0) {
[[UIApplicationsharedApplication]setApplicationIconBadgeNumber:0];
}
#pragma mark - private function
- (void)addLocalNotification {
UILocalNotification *localNotification = [[UILocalNotificationalloc]init];
localNotification.fireDate = [NSDatedateWithTimeIntervalSinceNow:10];
localNotification.repeatInterval =2;
localNotification.repeatCalendar = [NSCalendarcurrentCalendar];
localNotification.alertBody =@"本地通知来了,你准备好打开了吗?";
localNotification.applicationIconBadgeNumber =1;
localNotification.alertAction =@"打开应用";
localNotification.alertLaunchImage =@"Default";
localNotification.userInfo =@{@"id":@1,@"user":@"Yao"};
[[UIApplicationsharedApplication]scheduleLocalNotification:localNotification];
}
#pragma mark ---- remove notification
- (void)removeNotification {
[[UIApplicationsharedApplication]cancelAllLocalNotifications];
}
远程推送(Remote Notification)
思想:
5.APNs根据设备令牌(deviceToken)在已注册的苹果机型上(iphone,ipad,itouch,mac等)查找对应的设备,将消息发送给相应的设备。
6.客户端将接收到的消息传递给相应的应用程序,应用程序根据用户设置弹出通知信息。
Warning:
本地推送的注意事项同样适用于远程推送,在这里就不重复说上边的两个注意事项,远程推送还有几个点需要注意
1.当有通知来的时候,如果我们的APP处于杀死状态,我们点击通知的话,可能会出现这种情况,我们的launchView还没有remove掉,通知已经显现出来了,这显然是一个bug,需要处理,处理方法:
在appdelegate中声明一个变量,这个变量就是处理是不是点击通知启动的APP,初始值为NO,当APP将到前台的时候置为YES,当APP已经处于活跃状态的时候置为NO。为什么这么搞,你可以好好研究下Application中的几个代理方法的执行顺序。
2.推送的证书和bundleID和后台导入的都必须一致,如果中间没有收到推送消息,那就和后台联调,无非就是证书不对,bundleID不对啊什么的
3.苹果推送有时候会存在延迟,这个是没办法的,不用多想,我们再想也解决不了,这是苹果自身的问题
核心代码:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//注册消息通知
//因为会出现floatValue问题,所以判断系统版本号可以这样比较
if ([applicationrespondsToSelector:@selector(isRegisteredForRemoteNotifications)]) {
[[UIApplicationsharedApplication]registerForRemoteNotifications];
if ([UNUserNotificationCentercurrentNotificationCenter]) {
//iOS 10
[[UNUserNotificationCentercurrentNotificationCenter]setDelegate:self];
UNUserNotificationCenter *center = [UNUserNotificationCentercurrentNotificationCenter];
[centerrequestAuthorizationWithOptions:UNAuthorizationOptionAlert |UNAuthorizationOptionBadge |UNAuthorizationOptionSoundcompletionHandler:^(BOOL granted,NSError * _Nullable error) {
if (granted) {
DebugLog(@"notification push open succeed");
}else {
//reminder user to open the push notification
}
}];
}else {
//ios8~ios10以下
[[UIApplicationsharedApplication]registerForRemoteNotifications];
[[UIApplicationsharedApplication]registerUserNotificationSettings:[UIUserNotificationSettingssettingsForTypes:UIUserNotificationTypeAlert |UIUserNotificationTypeBadge |UIUserNotificationTypeSoundcategories:nil]];
}
}else {
//ios8以下
[[UIApplicationsharedApplication]registerForRemoteNotificationTypes:UIUserNotificationTypeSound |UIUserNotificationTypeBadge |UIUserNotificationTypeAlert];
}
NSDictionary *userInfo = [launchOptionsobjectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (userInfo) {
[mUIManagerControllerserverPushDataWithApplicationState:application.applicationStateuserInfoData:userInfoneedJump:YES];
}
returnYES;
}
//注册成功远程通知
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
//保存token然后传服务端
}
//注册失败远程通知
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
NSString *errorStr = [NSStringstringWithFormat:@"%@",error];
DebugLog(@"get token failed,error:%@",errorStr);
}
//ios10以下走
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
//iOS10以下不管是在前台还是后台 当有推送来的时候都是在这里接收的
//这里的JumpToHostApp是一个单例,专门处理通知来后跳转的逻辑
[[JumpToHostApp sharedInstance] serverPushDataWithApplicationState:application.applicationStateuserInfoData:userInfoneedJump:mAPNSStart];
}
注意:这又是一个bug:当手机系统是10.0.几的时候可能会走下边这个方法,而不会走iOS10及以上的方法
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
//iOS10有些手机可能是通过这个方法来接收推送数据的
DebugLog(@"push information is %@",userInfo); //按需处理
}
//iOS10及以上
// The method will be called on the delegate only if the application is in the foreground. If the method is not implemented or the handler is not called in a timely manner then the notification will not be presented. The application can choose to have the notification presented as a sound, badge, alert and/or in the notification list. This decision should be based on whether the information in the notification is otherwise visible to the user.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler__IOS_AVAILABLE(10.0)__TVOS_AVAILABLE(10.0)__WATCHOS_AVAILABLE(3.0) {
completionHandler(UNNotificationPresentationOptionAlert);
[[JumpToHostApp sharedInstance]serverPushDataWithApplicationState:UIApplicationStateActiveuserInfoData:notification.request.content.userInfoneedJump:mAPNSStart];
}
// The method will be called on the delegate when the user responded to the notification by opening the application, dismissing the notification or choosing a UNNotificationAction. The delegate must be set before the application returns from applicationDidFinishLaunching:.
- (void)userNotificationCenter:(UNUserNotificationCenter *)center
:(UNNotificationResponse *)response withCompletionHandler:(void(^)())completionHandler__IOS_AVAILABLE(10.0)__WATCHOS_AVAILABLE(3.0)__TVOS_PROHIBITED {
//do somer avaiable.it has some qusetion.
completionHandler();
[[JumpToHostApp sharedInstance]serverPushDataWithApplicationState:UIApplicationStateBackground userInfoData:response.notification.request.content.userInfoneedJump:mAPNSStart];
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
mAPNSStart =YES;
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
mAPNSStart =NO;
NSInteger badge = [[UIApplicationsharedApplication]applicationIconBadgeNumber];
if (badge >0) {
badge =0;
[[UIApplicationsharedApplication]setApplicationIconBadgeNumber:badge];
}else {
[[UIApplicationsharedApplication]setApplicationIconBadgeNumber:1];
[[UIApplicationsharedApplication]setApplicationIconBadgeNumber:0];
}
}
- (void)removeLaunchView
{
[selfinitUIFrame];
if (mNotifNeedJump ==YES) {
[selfserverPushDataWithApplicationState:[UIApplicationsharedApplication].applicationStateuserInfoData:mUserInfoDicneedJump:YES];
}
else {
mNotifNeedJump =YES;
}
}
方法实现,有些消息是打开APP后需要弹框的,有些消息是APP打开后需要跳转到对应界面的
- (void)serverPushDataWithApplicationState:(UIApplicationState)applicationState userInfoData:(NSDictionary *)userInfo needJump:(BOOL)jump {
if (jump) {
if (mNotifNeedJump ==YES) {
[selfparserPushData:userInfobJump:YES];//可以跳跳到对应的View
}else {
mNotifNeedJump =YES;
}
}else {
//显示弹框也就是APP处于活跃状态下
[selfparserPushData:userInfobJump:NO];
}
}
实战流程:
项目设置
注册推送证书
写对应的code
最后
以上就是矮小蛋挞为你收集整理的苹果推送(push Notification)的那点儿事的全部内容,希望文章能够帮你解决苹果推送(push Notification)的那点儿事所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复