苹果推送(push Notification)的那点儿事
2017-03-07 15:33
155 查看
苹果给我们的推送有两种,一种是本地推送,一种就是远程推送。本地推送比较简单,在项目中我们基本不会用到,不过还是大致说一下,也好更好的理解远程推送。
2.客户端接收通知
3.客户端处理通知中的数据
其实也就是这样,中间没有什么逻辑,就是你注册完之后,等着接收,接着处理通知来的数据就可以了。
[[[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];
}
至于为甚么可以这样来判断,你可以看看那几个API适用的系统版本就明白了。
(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;
*)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];
}
2.客户端拿到苹果给我们注册成功的信号(deviceToken返回成功)
3.客户端将这个deviceToken给服务端。
4.服务端把要发送的消息和设备令牌发送给苹果的消息推送服务器,即APNs.
5.APNs根据设备令牌(deviceToken)在已注册的苹果机型上(iphone,ipad,itouch,mac等)查找对应的设备,将消息发送给相应的设备。
6.客户端将接收到的消息传递给相应的应用程序,应用程序根据用户设置弹出通知信息。
1.当有通知来的时候,如果我们的APP处于杀死状态,我们点击通知的话,可能会出现这种情况,我们的launchView还没有remove掉,通知已经显现出来了,这显然是一个bug,需要处理,处理方法:
在appdelegate中声明一个变量,这个变量就是处理是不是点击通知启动的APP,初始值为NO,当APP将到前台的时候置为YES,当APP已经处于活跃状态的时候置为NO。为什么这么搞,你可以好好研究下Application中的几个代理方法的执行顺序。
2.推送的证书和bundleID和后台导入的都必须一致,如果中间没有收到推送消息,那就和后台联调,无非就是证书不对,bundleID不对啊什么的
3.苹果推送有时候会存在延迟,这个是没办法的,不用多想,我们再想也解决不了,这是苹果自身的问题
*)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];
}
}
然后在JumpToHostApp这个类中处理这个跳转逻辑,首先我们还需要加一个bool变量,为了看是不是通知来的 mNotifiNeedJump.初始化为NO,我们在移除launchView的时候调用方法:
- (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];
}
}
![](http://img.blog.csdn.net/20170307145537320?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvYmFpZHVfMzE2ODM2OTE=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)
本地推送(Local Notification)
思想:
1.客户端注册本地通知2.客户端接收通知
3.客户端处理通知中的数据
其实也就是这样,中间没有什么逻辑,就是你注册完之后,等着接收,接着处理通知来的数据就可以了。
Warning:
1.苹果系统版本号判定floatValue问题
因为苹果API更新还是挺快的,所以不同系统上的API或遭废弃,或增新API。所以需要判断系统,而判断系统的时候有一个坑,那就是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];
}
至于为甚么可以这样来判断,你可以看看那几个API适用的系统版本就明白了。
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)
远程推送相对于本地推送来说要复杂点,因为核心东西不是我们自己控制的,本地推送都是我们自己控制的,想怎么玩都可以,但是远程推送涉及到了服务端,关键是还涉及到了苹果的推送服务器。对了,我没有接第三方的推送,我是直接走的原生API,因为我看了那些第三方推送,不还是把原生的API包了一层,然后又绕回道原生,所以就自己写了,没有接第三方,直接用苹果原油API来做的推送,需要接入第三方推送的,请移步。思想:
1.客户端向苹果注册远程通知2.客户端拿到苹果给我们注册成功的信号(deviceToken返回成功)
3.客户端将这个deviceToken给服务端。
4.服务端把要发送的消息和设备令牌发送给苹果的消息推送服务器,即APNs.
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];
}
}
然后在JumpToHostApp这个类中处理这个跳转逻辑,首先我们还需要加一个bool变量,为了看是不是通知来的 mNotifiNeedJump.初始化为NO,我们在移除launchView的时候调用方法:
- (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];
}
}
实战流程:
项目设置
project->Capabilities进行设置,如下图:需要打开Push Notifications,还有下边的Background Modes->Remote Notifications注册推送证书
关于注册推送证书,可以参考我之前的一篇博客,里边是注册推送证书的流程,已经把所有步骤都用图片截取下来,点此链接:APNs消息推送开发证书创建图解。写对应的code
和本地推送基本一样,不再赘述。因为我们肯定不是只管消息来,我们还得做消息来的时候的处理,所以我另单独写了个类,专门处理那些来的消息。appdelegate中越简单越好。相关文章推荐
- Java后台向苹果APNS推送文字,图片,视频功能
- IOS成长之路-推送(通过苹果服务器)
- 苹果信息推送服务(Apple Push Notification Service)使用总结 .
- [IOS开发] 苹果推送机制APNs(一)
- 苹果推送机制APNs(一)
- 苹果推送机制(APNS)
- 基于C++ 苹果apns消息推送实现(2)
- iOS项目开发实战——实现苹果本地消息通知推送服务
- APNSWrapper,python 苹果推送
- 关于苹果推送的问题
- 苹果推送通知服务(APNs)编程
- 苹果通知推送服务(APNS)一些关键特性摘要
- APNS push 服务器端 SSL3.0 转 TLS (iPhone苹果推送服务)
- iOS:苹果推送(三)----一些示例代码和注意的问题
- 检测苹果推送证书有效性
- 关于苹果APNS推送机制中各生成文件(CSR、证书、Provisioning文件)的关系的梳理,以及各种坑
- Apple Push Notification Services (APNS)苹果推送通知服务
- 苹果证书 使用推送时报错
- 苹果推送新版iOS支持公交卡功能
- 苹果证书,推送证书流程