iOS學習筆記22-推送通知 – iPhone手機開發 iPhone軟體開發教學課程

一、推送通知

推送通知就是向用戶推送一條信息來通知用戶某件事件,可以在應用退到後臺後,或者關閉後,能夠通過推送一條消息通知用戶某件事情,比如版本更新等等。

推送通知的常用應用場景:

一些任務管理APP,會到任務時間即將到達時,通知你該做任務瞭。健身APP定時提醒你應該健身瞭。買過電影票,提前半個小時通知你,電影即將開場。當你QQ或微信收到信息時,即使退到後臺,也可以收到信息通知你。電商APP,推送一條消息通知我們有新品上架等等。

推送通知的常用展示樣式:

屏幕頂部顯示一塊橫幅在鎖屏界面顯示一塊橫幅更新APP圖標數字播放音效屏幕中間彈出一個UIAlertView

推送通知分為:

本地推送通知:
不需要聯網,在APP代碼中推送的通知,確定知道未來某個時間點應該提醒用戶什麼
【開發人員在APP內部通過代碼發生 = 本地推送通知】遠程推送通知:
需要聯網,是由服務器推送的通知,不確定未來某個時間點應該提醒用戶什麼
【服務器可以確定通知時間和內容 = 遠程推送通知】

使用原則:誰確定通知時間和內容,誰就可以發生

二、本地推送通知

本地推送通知步驟:

 

在iOS8以後使用本地推送通知,需要得到用戶的許可創建UILocalNotification本地通知對象,並設置必要屬性開始本地推送通知:

 

第一種方法,延時推送,根據本地通知對象的fireDate設置進行本地推送通知

[[UIApplication shareApplication] scheduleLocalNotification:notification];

第二種方法,立刻推送,忽略本地通知對象的fireDate設置進行本地推送通知

[[UIApplication shareApplication] presentLocalNotificationNow:notification];

4- 監聽用戶點擊通知:

APP處於前臺,此時不會彈框通知用戶,但會調用對應的代理方法 :

-(void)application:(UIApplication *)application didReceiveLocalNotification;

APP處於後臺,屏幕上方會彈出橫幅,用戶點擊橫幅後,會進入前臺,調用上面的代理方法。 APP已關閉,屏幕上方會彈出橫幅,用戶點擊橫幅後,會啟動APP,調用以下方法:

-(BOOL)application:(UIApplication *)application 
            didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
/* 通過參數launchOptions獲取本地推送通知內容 */
UILocalNotification *local = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];

5- 調用UIApplication的對象方法,取消本地推送通知:

/* 取消指定的本地推送通知 */
-(void)cancelLocalNotification:(UILocalNotification *)notification;
/* 取消全部本地推送通知 */
-(void)cancelAllLocalNotification;
以下是實例代碼:
1. 註冊通知代碼以及UIAlertView顯示通知方法代碼
- (BOOL)application:(UIApplication *)application 
        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
    //因為是storyboard啟動,這裡就沒有其他啟動代碼瞭

    //iOS8.0以後,如果需要使用推送通知,需要得到用戶許可
    if (application.currentUserNotificationSettings.types == UIUserNotificationTypeNone) {
        //註冊通知,有橫幅通知、應用數字通知、應用聲音通知
        UIUserNotificationSettings * setting = 
              [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert |
                                                           UIUserNotificationTypeBadge |
                                                           UIUserNotificationTypeSound
                                                categories:nil];
        [application registerUserNotificationSettings:setting];
    } else {
        //當APP關閉後接收到通知,在啟動中獲取本地推送通知對象
        UILocalNotification *notification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
        [self showLocalNotification:notification];
    }
    return YES;
}
/* 彈框UIAlertView顯示本地通知的信息 */
- (void)showLocalNotification:(UILocalNotification *)notification
{
    /* 顯示本地通知 */
    NSDictionary *userInfo = notification.userInfo;
    NSString *title = @"本地通知";
    NSString *msg = userInfo[@"msg"];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title 
                                                    message:msg 
                                                   delegate:nil 
                                          cancelButtonTitle:@"取消" 
                                          otherButtonTitles:@"確定", nil];
    [alert show];
    //移除本地通知
    [[UIApplication sharedApplication] cancelLocalNotification:notification];
}
2. 創建本地通知代碼
/* 創建一個本地通知 */
- (UILocalNotification *)makeLocalNotification{
    //創建本地推送通知對象
    UILocalNotification *notification = [[UILocalNotification alloc] init];
    //設置調用時間
    notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:10.0];//通知觸發的時間,10s以後
    notification.repeatInterval = NSCalendarUnitMinute;//每隔多久重復發一次本地通知
    //設置通知屬性
    notification.alertBody = @"最近添加瞭諸多有趣的特性,是否立即體驗?";//通知主體
    notification.applicationIconBadgeNumber = 1;//應用程序圖標右上角顯示的消息數
    notification.alertAction = @"打開應用"; //待機界面的滑動動作提示
    notification.alertLaunchImage = @"Default";//通過點擊通知打開應用時的啟動圖片,這裡使用程序啟動圖片
    notification.soundName = UILocalNotificationDefaultSoundName;//收到通知時播放的聲音,默認消息聲音
    //設置用戶信息
    notification.userInfo = @{ @"id":@1, 
                               @"user":@"Kenshin Cui", 
                               @"msg":@"我來瞭一發本地通知"};//綁定到通知上的其他附加信息
    return notification;
}

如果需要每天的中午12點準時本地推送怎麼辦呢?
就像這麼辦,修改fireDaterepeatInterval屬性

NSDateFormatter *formatter1 = [[NSDateFormatter alloc]init];  
[formatter setDateFormat:@"yyyy-MM-dd HH-mm-sss"];  
NSDate *resDate = [formatter dateFromString:@"2016-04-09 12-00-00"];
notification.fireDate = resDate;//設定為明天中午12點觸發通知
//記得設置當前時區,沒有設置的話,fireDate將不考慮時區,這樣的通知會不準確
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.repeatInterval = NSCalendarUnitDay;//每隔一天觸發一次
3. 監聽用戶點擊
/* 註冊本地通知完成會調用,即用戶點擊確定授權後調用 */
- (void)application:(UIApplication *)application 
        didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    //在這裡我們嘗試發送本地推送通知
    if (notificationSettings.types != UIUserNotificationTypeNone) {
        UILocalNotification *notification = [self makeLocalNotification];
        //延遲調用通知
        [application scheduleLocalNotification:notification];
        //立刻發送通知
        //[application presentLocalNotificationNow:notification];
    }
}
/* 應用還在運行,無論前臺還是後臺,都會調用該方法處理通知 */
- (void)application:(UIApplication *)application 
        didReceiveLocalNotification:(UILocalNotification *)notification
{
    if( notification ) {
        [self showLocalNotification:notification];
    }
}
/* 應用進入前臺,去除應用邊角數字顯示 */
- (void)applicationWillEnterForeground:(UIApplication *)application {
    //去除應用邊角數字
    [application setApplicationIconBadgeNumber:0];
}

本地通知彈出通告欄和應用邊角數字變化

顯示本地通知

三、遠程推送通知

iOS遠程消息推送的工作機制

iOS遠程消息推送步驟:

應用服務提供商從服務器端把要發送的消息設備令牌(device token)發送給蘋果的消息推送服務器APNs。 APNs根據設備令牌在已註冊的設備(iPhone、iPad、iTouch、Mac等)查找對應的設備,將消息發送給相應的設備。客戶端設備接將接收到的消息傳遞給相應的應用程序,應用程序根據用戶設置彈出通知消息。

下面是更詳細的流程:

遠程推送詳細流程圖

所有的蘋果設備,在聯網狀態下,都會和蘋果服務器APNs建立一個長連接
* 長連接:服務器可以向客戶端發送消息,保證數據的即時性,但比較占用資源
* 短連接:服務器無法主動向客戶端發消息,會話結束後,就立即釋放資源,節省資源

遠程推送通知就是借助蘋果設備與APNs服務器之間的長連接,借助APNs服務器講消息發送給客戶端。vcD4NCjxoNiBpZD0=”遠程推送通知實現的條件”>
遠程推送通知實現的條件:

必須有真機,隻有真機具備UDID,才能生成deviceToken設備令牌需要開發推送Cer證書

證書的申請請參考:iOS學習筆記21-推送證書與秘鑰申請

deviceToken的生成算法隻有Apple掌握,為瞭確保算法發生變化後仍然能夠正常接收服務器端發送的通知,每次應用程序啟動都重新獲得deviceToken

遠程推送通知步驟:

iOS8以後,使用遠程通知,需要請求用戶授權註冊遠程通知成功後會調用以下方法,獲取deviceToken設備令牌:

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

3- 把deviceToken設備令牌發送給服務器,時刻保持deviceToken是最新的
4- 監聽遠程推送通知:

-(void)application:(UIApplication *)application 
          didReceiveRemoteNotification:(NSDictionary *)userInfo;
下面是實例代碼:
1. 註冊遠程推送通知代碼:
- (BOOL)application:(UIApplication *)application 
        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
   //iOS8.0以後,如果需要使用本地推送通知,需要得到用戶許可
    if (![application isRegisteredForRemoteNotifications]) {
        UIUserNotificationSettings * setting = 
              [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert |
                                                           UIUserNotificationTypeBadge |
                                                           UIUserNotificationTypeSound
                                                categories:nil];
        [application registerUserNotificationSettings:setting];
        //註冊遠程推送通知
        [application registerForRemoteNotifications];
    }
    return YES;
}
2. 註冊成功調用代碼:
/* 註冊遠程推送通知成功會調用 ,在此接收設備令牌deviceToken */
- (void)application:(UIApplication *)application 
        didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    [self addDeviceToken:deviceToken];
}
/* 保存deviceToken,並同步服務器上保存的deviceToken,以便能正確推送通知 */
- (void)addDeviceToken:(NSData *)deviceToken
{
    NSString *key = @"DeviceToken";
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    //取出原來的deviceToken,進行比較
    NSData *oldToken = [defaults objectForKey:key];
    if ([oldToken isEqualToData:deviceToken]) {
        //存入新的deviceToken
        [defaults setObject:deviceToken forKey:key];
        [defaults synchronize];
        //發送網絡請求到服務器,說明deviceToken發生瞭改變
        [self sendDeviceTokenWithOldDeviceToken:oldToken newDeviceToken:deviceToken];
    }
}
/* 發送網絡請求到服務器,說明deviceToken發生瞭改變,服務器那邊也要同步改變 */
- (void)sendDeviceTokenWithOldDeviceToken:(NSData *)oldToken newDeviceToken:(NSData *)newToken
{
    //發送到服務器,下面是服務器的一個接口
    NSString *urlStr = @"https://192.168.1.101/RegisterDeviceToken.aspx";
    urlStr = [urlStr stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
    NSURL *url = [NSURL URLWithString:urlStr];
    //POST網絡請求
    NSMutableURLRequest *requestM = [NSMutableURLRequest requestWithURL:url];
    requestM.HTTPMethod = @"POST";
    //POST請求的請求體
    NSString *bodyStr = [NSString stringWithFormat:@"oldToken=%@&newToken=%@",oldToken,newToken];
    requestM.HTTPBody = [bodyStr dataUsingEncoding:NSUTF8StringEncoding];
    //使用會話來發送網絡請求
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDataTask *dataTask = 
          [session dataTaskWithRequest:requestM 
                     completionHandler:^(NSData *data,NSURLResponse *response,NSError *error){
        if(!error){
            NSLog(@"Send Success !");
        } else {
            NSLog(@"Send Failure, error = %@",error.localizedDescription);
        }
    }];
    //網絡請求任務啟動
    [dataTask resume];
}
3. 監聽遠程推送通知:
/* 收到遠程推送通知時會調用 */
- (void)application:(UIApplication *)application 
        didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    NSString *title = @"遠程推送通知";
    NSString *msg = userInfo[@"msg"];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title 
                                                    message:msg 
                                                   delegate:nil 
                                          cancelButtonTitle:@"取消" 
                                          otherButtonTitles:@"確定", nil];
    [alert show];
}

四、第三方遠程推送

上面的遠程推送過程如果覺得實現比較麻煩,你可以使用第三方推送,例如:

極光推送( JPush ),我隻用過這個,界面還不錯,這不是在打廣告! 個推 騰訊信鴿

具體的集成步驟及使用方法,請查看對應的官方文檔,非常詳細。

 

 

發佈留言