iOS推送,看這篇足夠了

關於遠程推送的相關配置網上已經有足夠多的教程,這裏就不復述了。這裏講述當客戶端收到推送消息後,該怎樣對其進行相應的邏輯處理。服務器

工程的AppDelegate.m文件裏提供了以下方法:app

//當應用程序啓動後,可能須要進行其餘邏輯處理時調用的方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;

//成功註冊registerUserNotificationSettings:後,回調的方法
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings;
 
/// 註冊失敗調用
- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error;

/// 用戶贊成接收通知後,會調用此程序
- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;

//收到推送後調用的方法(iOS 10 及以上)
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler;
 
//收到推送後調用的方法(iOS 10 如下)
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler;
 
//應用掛起前調用的方法(當有電話進來或者鎖屏,應用會掛起)
- (void)applicationWillResignActive:(UIApplication *)application;
 
//當程序復原或啓動時調用的方法
- (void)applicationDidBecomeActive:(UIApplication *)application;

//應用將要進入後臺調用的方法
- (void)applicationWillEnterForeground:(UIApplication *)application;

//應用進入後臺調用的方法
-(void)applicationDidEnterBackground:(UIApplication *)application;
 
//應用將要退出
- (void)applicationWillTerminate:(UIApplication *)application;

 

首先爲應用程序註冊通知:框架

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSDictionary *remoteNotification = [launchOptions objectForKey:@"UIApplicationLaunchOptionsRemoteNotificationKey"];
    if (remoteNotification != nil) {
        self.isLaunchedByNotification = YES;
    }else{
        self.isLaunchedByNotification = NO;
    }
    self.window=[[UIWindow alloc]initWithFrame:[[UIScreen mainScreen]bounds]];
    if ([[UIDevice currentDevice].systemVersion floatValue] >= 10.0) {
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        center.delegate = self;
        [center requestAuthorizationWithOptions:(UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert) completionHandler:^(BOOL granted, NSError * _Nullable error) {
            if (!error) {
                NSLog(@"succeeded!");
            }
        }];
    } else if ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0){//iOS8-iOS9
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound) categories:nil];
        [application registerUserNotificationSettings:settings];
        [application registerForRemoteNotifications];
    } else {//iOS8如下
        [application registerForRemoteNotificationTypes: UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound];
    }
    return YES;
}

 

用戶贊成後,會調用此程序,獲取系統的deviceToken,應把deviceToken傳給服務器保存,此函數會在程序每次啓動時調用(前提是用戶容許通知):ide

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    NSLog(@"deviceToken = %@",deviceToken);
    NSString *token=[NSString stringWithFormat:@"%@",deviceToken];
    token=[token stringByReplacingOccurrencesOfString:@"<" withString:@""];
    token=[token stringByReplacingOccurrencesOfString:@">" withString:@""];
    token=[token stringByReplacingOccurrencesOfString:@" " withString:@""];
    //TODO
    //保存到本地並上傳到服務器
}

 

收到推送消息後,進行相應的邏輯處理:函數

//iOS 10 及以上
- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler {
    completionHandler(UIBackgroundFetchResultNewData);
    NSDictionary *userInfo = response.notification.request.content.userInfo;
    //程序關閉狀態點擊推送消息打開
    if (self.isLaunchedByNotification) {
        //TODO
    }
    else{
        //前臺運行
        if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
            //TODO
        }
        //後臺掛起時
        else{
            //TODO
        }
        //收到推送消息手機震動,播放音效
        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
        AudioServicesPlaySystemSound(1007);
    }
    //設置應用程序角標數爲0
    [UIApplication sharedApplication].applicationIconBadgeNumber = 9999;
    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
}
//iOS 10 如下
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    completionHandler(UIBackgroundFetchResultNewData);    
    //程序關閉狀態點擊推送消息打開
    if (self.isLaunchedByNotification) {
        //TODO
    }
    else{
        //前臺運行
        if ([UIApplication sharedApplication].applicationState == UIApplicationStateActive) {
            //TODO
        }
        //後臺掛起時
        else{
            //TODO
        }
        //收到推送消息手機震動,播放音效
        AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
        AudioServicesPlaySystemSound(1007);
    }
    //設置應用程序角標數爲0
    [UIApplication sharedApplication].applicationIconBadgeNumber = 9999;
    [UIApplication sharedApplication].applicationIconBadgeNumber = 0;
}
 

應用進入後臺時,設置角標數(應用圖標右上角小紅點,未讀消息數):學習

-(void)applicationDidEnterBackground:(UIApplication *)application{
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber:123];
}
 

實際應用:
fetch

1、註冊推送:ui

- (void)registerNotification
{
    if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 10.0)
    {
        if (@available(iOS 10.0, *)) {
            UNUserNotificationCenter * center =[UNUserNotificationCenter currentNotificationCenter];
            center.delegate=self;
            UNAuthorizationOptions options = UNAuthorizationOptionAlert|UNAuthorizationOptionSound|UNAuthorizationOptionBadge|UNAuthorizationOptionCarPlay;
            [center requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError * _Nullable error) {
                if (granted) {
                }else{
                    NSLog(@"受權失敗");
                }
            }];
        } else {
            // Fallback on earlier versions
        }
    }
    else if ([[[UIDevice currentDevice] systemVersion] floatValue]>=8.0)
    {
        UIUserNotificationSettings *sets= [UIUserNotificationSettings settingsForTypes:(UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound) categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:sets];
    }
    else
    {
        UIRemoteNotificationType type = UIRemoteNotificationTypeAlert|UIRemoteNotificationTypeBadge|UIRemoteNotificationTypeSound;
        [[UIApplication sharedApplication] registerForRemoteNotificationTypes:type];
    }
        [[UIApplication sharedApplication] registerForRemoteNotifications];
}

 

假如用戶第一次安裝拒絕推送須要提醒的,按如下方法:(例子:iOS10 )加密

  UNUserNotificationCenter *userNotificationCenter = [UNUserNotificationCenter currentNotificationCenter];  

  userNotificationCenter.delegate = self;  

//獲取通知設置信息  

 [userNotificationCenter getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {  
//用戶還未作出選擇  

  if (settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {  

     //彈出受權框  
       [userNotificationCenter requestAuthorizationWithOptions:UNAuthorizationOptionAlert + UNAuthorizationOptionBadge + UNAuthorizationOptionSound completionHandler:^(BOOL granted, NSError * _Nullable error) {  
       if (granted) {  
}
else{               //首次受權爲未受權狀態,以後爲已受權狀態 DLog(@"沒有開啓通知"); } }]; }
  else if (settings.authorizationStatus == UNAuthorizationStatusDenied){     //用戶不一樣意受權時,彈出提示(最好只彈一次)     UIAlertController *noticeNotificationAlertController = [UIAlertController alertControllerWithTitle:@"友情提示" message:@"建議您開啓通知功能,以便及時獲取相關信息" preferredStyle:UIAlertControllerStyleAlert]; [noticeNotificationAlertController addAction:[UIAlertAction actionWithTitle:@"忽略" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) { }]]; [noticeNotificationAlertController addAction:[UIAlertAction actionWithTitle:@"去開啓" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action){     NSURL *appSettingsUrl = [NSURL URLWithString:UIApplicationOpenSettingsURLString];     if ([[UIApplication sharedApplication] canOpenURL:appSettingsUrl]) { [[UIApplication sharedApplication] openURL:appSettingsUrl]; } }]]; [self.window.rootViewController presentViewController:noticeNotificationAlertController animated:YES completion:NULL]; }else{        //已受權 DLog(@"已受權通知"); }
}];  

2、本地推送:spa

iOS10以後:

//使用 UNNotification 本地通知  

+(void)registerNotification:(NSInteger )alerTime{  

// 使用 UNUserNotificationCenter 來管理通知  

    UNUserNotificationCenter* center = [UNUserNotificationCenter currentNotificationCenter];  

//需建立一個包含待通知內容的 UNMutableNotificationContent 對象,注意不是 UNNotificationContent ,此對象爲不可變對象。  

    UNMutableNotificationContent* content = [[UNMutableNotificationContent alloc] init];  

    content.title = [NSString localizedUserNotificationStringForKey:@"Hello!" arguments:nil];  

    content.body = [NSString localizedUserNotificationStringForKey:@"Hello_message_body"  arguments:nil];  

    content.sound = [UNNotificationSound defaultSound];  

// 在 alertTime 後推送本地推送  

    UNTimeIntervalNotificationTrigger* trigger = [UNTimeIntervalNotificationTrigger triggerWithTimeInterval:alerTime repeats:NO];  

    UNNotificationRequest* request = [UNNotificationRequest requestWithIdentifier:@"FiveSecond"  content:content trigger:trigger];  

//添加推送成功後的處理!  

    [center addNotificationRequest:request withCompletionHandler:^(NSError * _Nullable error) {  

     UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"本地通知" message:@"成功添加推送" preferredStyle:UIAlertControllerStyleAlert];  

     UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil];  

        [alert addAction:cancelAction];  

        [[UIApplication sharedApplication].keyWindow.rootViewController presentViewController:alert animated:YES completion:nil];  
    }];  
}  

 

iOS10之前:

+ (void)registerLocalNotificationInOldWay:(NSInteger)alertTime {  

  UILocalNotification *notification = [[UILocalNotification alloc] init];  

  // 設置觸發通知的時間  

  NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:alertTime];  

    NSLog(@"fireDate=%@",fireDate);  

    notification.fireDate = fireDate;  

  // 時區  

    notification.timeZone = [NSTimeZone defaultTimeZone];  

  // 設置重複的間隔  

    notification.repeatInterval = kCFCalendarUnitSecond;  

  // 通知內容  

    notification.alertBody =  @"該起牀了...";  

    notification.applicationIconBadgeNumber = 1;  

  // 通知被觸發時播放的聲音  

    notification.soundName = UILocalNotificationDefaultSoundName;  

  // 通知參數  

  NSDictionary *userDict = [NSDictionary dictionaryWithObject:@"開始學習iOS開發了" forKey:@"key"];  

    notification.userInfo = userDict;  

  // 通知重複提示的單位,能夠是天、周、月  

     notification.repeatInterval = NSDayCalendarUnit;  

  // 將本地通知添加到調度池,定時發送

    [[UIApplication sharedApplication] scheduleLocalNotification:notification];  

   // 當即發送

    // [[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];

}  

 

本地通知相關代理方法:

// 當App在前臺狀態下,若是有通知會調用該方法

// 當應用程序在後臺狀態下,點擊推送通知,程序從後臺進入前臺後,會調用該方法(從鎖屏界面點擊推送通知從後臺進入前臺也會執行)

// 當應用程序徹底退出時不調用該方法

- (void)application:(UIApplication *)application didReceiveLocalNotification:(nonnull UILocalNotification *)notification{

  NSLog(@"%@", notification);

  // 處理點擊通知後對應的業務

  UIApplicationState applicationState = [[UIApplication sharedApplication] applicationState];

   if (applicationState == UIApplicationStateActive) {

  // 前臺

  // 例如QQ會增長tabBar上的badgeValue未讀數量

  }

  else if (applicationState == UIApplicationStateInactive) {

  // 從前臺進入後臺

  // 例如QQ會打開對應的聊天窗口

    NSInteger applicationIconBadgeNumber = application.applicationIconBadgeNumber - 1;

    application.applicationIconBadgeNumber = applicationIconBadgeNumber >= 0 ? applicationIconBadgeNumber : 0;

  }

   [application cancelLocalNotification:notification];

}

 

// 監聽附加操做按鈕

- (void)application:(UIApplication *)application handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(nonnull UILocalNotification *)notification completionHandler:(nonnull void (^)())completionHandler {

  NSLog(@"identifier:%@", identifier); completionHandler();

}

 

// 該方法在iOS9.0後調用,iOS9.0以前調用上面那個方法

- (void)application:(UIApplication *)app handleActionWithIdentifier:(nullable NSString *)identifier forLocalNotification:(nonnull UILocalNotification *)notification withResponseInfo:(nonnull NSDictionary *)responseInfo completionHandler:(nonnull void (^)())completionHandler {

  // ====identifier:no, content:{UIUserNotificationActionResponseTypedTextKey = "not agree";}

  NSLog(@"====identifier:%@, content:%@", identifier, responseInfo);

  completionHandler();

}

 

3、遠程通知:

一、什麼是遠程推送

在聯網的狀況下,由遠程服務器推送給客戶端的通知,又稱APNs(Apple Push Notification Services)無論應用是打開仍是關閉的狀況下,都能接收到服務器推送的遠程通知在聯網狀態下,全部蘋果設備都會與蘋果服務器創建長鏈接

二、遠程推送的實現原理:

      1.打開App時: 發送UDIDBundleIDAPNs加密後返回deviceToken

      2.獲取Token後,App調用接口,將用戶身份信息和deviceToken發給服務器,服務器記錄

      3.當推送消息時, 服務器按照用戶身份信息找到存儲的deviceToken,將消息和deviToken發送給APNs

      4.蘋果的APNs經過deviceToken, 找到指定設備的指定程序, 並將消息推送給用戶

三、實現遠程推送功能的前提

      1.真機

      2.調試階段的證書

         iOS_development.cer 用於真機調試的證書

         aps_development.cer 用於真機推送調試能的證書

         xxx.mobileprovision 描述文件,記錄了可以調試的手機、電腦和程序

      3.發佈階段的證書

          iOS_distribution.cer 用於發佈app的證書

          aps.cer 用於發佈時,讓app有推送功能的證書

          xxx.mobileprovision 描述文件,記錄了可以發佈app的電腦

如何配置證書, 不在本教程內, 請讀者自行處理, 或者參考視頻教程

 

1、 註冊遠程推送並獲取DeviceToken

1.建立iOS的項目,並輸入項目名字

2.在AppDelegate中導入頭文件:

#import <UserNotifications/UserNotifications.h>

3.在application:didFinishLaunchingWithOptions方法中, 註冊遠程通知

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

 {

 //請求通知權限, 本地和遠程共用

 UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];

 [center requestAuthorizationWithOptions:UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert completionHandler:^(BOOLgranted, NSError * _Nullable error) {

  if(granted) {

   NSLog(@"請求成功");

    } else{

    NSLog(@"請求失敗");

    }

   }];

 //註冊遠程通知

 [[UIApplication sharedApplication] registerForRemoteNotifications];

 //設置通知的代理

 center.delegate = self;

 returnYES;

 } 

 

4.在接收遠程推送的DeviceToken方法中, 獲取Token

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken

{

//未來須要將此Token上傳給後臺服務器

NSLog(@"token:%@", deviceToken);

}

 

2、 iOS10以前通知的處理方法

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification

{

  //此方法已被下面的方法代替

}

-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler

{

   //iOS10以前,接收遠程通知時,無論在前臺、後臺仍是程序殺死都會調用此方法

   if (application.applicationState == UIApplicationStateActive) {

  // 前臺收到通知處理

  }else{

  //後臺或退出時點擊通知處理

  }

      completionHandler();

}

 

3、 iOS10遠程推送通知的處理方法

 當點擊了推送後, 若是你但願進行處理. 那麼在iOS10中, 還須要設置UNUserNotificationCenterdelegate, 並遵照UNUserNotificationCenterDelegate協議.

以及實現下面實現3個方法, 用於處理點擊通知時的不一樣狀況的處理

       willPresentNotification:withCompletionHandler 用於前臺運行

didReceiveNotificationResponse:withCompletionHandler 用於後臺及程序退出

didReceiveRemoteNotification:fetchCompletionHandler用於靜默推送

//設置通知的代理

center.delegate = self;

1.前臺運行 會調用的方法

前臺運行: 指的是程序正在運行中, 用戶能看見程序的界面.

iOS10會出現通知橫幅, 而在之前的框架中, 前臺運行時, 不會出現通知的橫幅.

- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void(^)(UNNotificationPresentationOptions))completionHandler { NSDictionary *userInfo = notification.request.content.userInfo; //前臺運行推送 顯示紅色Label [self showLabelWithUserInfo:userInfo color:[UIColor redColor]]; //能夠設置當收到通知後, 有哪些效果呈現(聲音/提醒/數字角標) completionHandler(UNNotificationPresentationOptionBadge | UNNotificationPresentationOptionSound | UNNotificationPresentationOptionAlert); }

 

2.後臺運行及程序退出 會調用的方法

後臺運行: 指的是程序已經打開, 用戶看不見程序的界面, 如鎖屏和按Home鍵.

程序退出: 指的是程序沒有運行, 或者經過雙擊Home鍵,關閉了程序.

1
2
3
4
5
6
7
8
9
- ( void )userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:( void (^)())completionHandler
  {
   NSDictionary *userInfo = response.notification.request.content.userInfo;
 
   //後臺及退出推送 顯示綠色Label
   [self showLabelWithUserInfo:userInfo color:[UIColor greenColor]];
 
   completionHandler();
  }

 

3.靜默推送通知 會調用的方法

靜默推送: iOS7之後出現, 不會出現提醒及聲音.

要求:

推送的payload中不能包含alertsound字段

須要添加content-available字段, 並設置值爲1

例如: {"aps":{"content-available":"1"},"PageKey」":"2"}

1
2
3
4
5
6
7
8
//若是是之前的舊框架, 此方法 前臺/後臺/退出/靜默推送均可以處理
- ( void )application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:( void (^)(UIBackgroundFetchResult))completionHandler
{
   //靜默推送 顯示藍色Label
  [self showLabelWithUserInfo:userInfo color:[UIColor blueColor]];
 
  completionHandler(UIBackgroundFetchResultNewData);
  }

 

4.處理通知的公用方法

開發中, 點擊通知的邏輯應當看本身程序的需求.

這裏爲了方便演示, 簡單的將通知的值, 經過UILabel顯示在主界面上.

1
2
3
4
5
6
7
8
9
- ( void )showLabelWithUserInfo:(NSDictionary *)userInfo color:(UIColor *)color
{
  UILabel *label = [UILabel new ];
  label.backgroundColor = color;
  label.frame = CGRectMake(0, 250, [UIScreen mainScreen].bounds.size.width, 300);
  label.text = userInfo.description;
  label.numberOfLines = 0;
  [[UIApplication sharedApplication].keyWindow addSubview:label];
}

 

iOS10本地通知:http://www.jianshu.com/p/5713fa2bfece 

對iOS的Push Notification的響應理解:https://www.jianshu.com/p/14bcec29f5c8

相關文章
相關標籤/搜索