1. 程式人生 > >iOS訊息推送機制

iOS訊息推送機制

96  Little_Dragon  2015.10.05 22:33*  字數 1253  閱讀 17337 評論 36

推送通知跟NSNotification不同
1.NSNotification是抽象的,不可見的
2.推送通知是可見的

iOS中提供了2中推送通知
1.本地推送通知(Local Notification)
2.遠端推送通知(Remote Notification)

推送的作用:可以讓不在前臺執行的app,告知客戶app內部發生的事情.(QQ訊息推送,微信訊息推送等等)

推送通知的呈現效果:
1.在螢幕頂部顯示的一條橫幅
2.在螢幕中間彈出一個UIAlertView
3.在鎖屏介面顯示一塊橫幅
4.跟新app圖示的數字
5.播放音效

本地通知

1.不需要伺服器支援(無需聯網)就能發出的推送通知
2.使用場景: 定時類任務(鬧鐘,簡單的遊戲等等)

本地通知推送的實現很簡單:
1.建立本地推送通知物件
[[UILocalNotification alloc] init]建立一個本地通知
2.設定本地通知的相關屬性
必須設定的屬性
2.1.推送通知的觸發時間(何時發出推送通知)
@property(nonatomic,copy) NSDate *fireDate


2.2.推送通知的具體內容
@property(nonatomic,copy) NSString *alertBody
2.3.在鎖屏時顯示的動作標題(完整測標題:"滑動來" + alertAction)
@property(nonatomic,copy) NSString *alertAction
2.4.設定鎖屏介面alertAction是否有效
localNote.hasAction = YES;
2.5.app圖示數字
@property(nonatomic,assign) NSInteger applicationIconBadgeNumber
2.6.排程本地推送通知(排程完畢後,推動通知會在特定時間fireDate發出)
[[UIApplication shareApplication] scheduleLocalNotification:ln]

可以進行設定的設定
2.7.設定通知中心通知的標題
localNote.alertTitle = @"222222222222";
2.8.設定音效(如果不設定就是系統預設的音效, 設定的話會在mainBundle中查詢)
localNote.soundName = @"buyao.wav";
2.9.每隔多久重複發一次推送通知
@property(nonatomic) NSCalendarUnit repeatInterval
2.10.點選推送通知開啟app時顯示的啟動圖片(mainBundle 中提取圖片)
@property(nonatomic,copy) NSSring *alertLaunchImage
2.11.附加的額外資訊
@property(nonatomic,copy) NSDictionary *userInfo
2.12.時區
@property(nonatomic,copy) NSTimeZone *timeZone
(一般設定為[NSTimeZone defaultTimeZone],跟隨手機的時區)

--程式碼實現過程:


本地通知.gif
/*
 @property(nonatomic,copy) NSDate *fireDate;
 @property(nonatomic,copy) NSTimeZone *timeZone; 時區
 
 @property(nonatomic) NSCalendarUnit repeatInterval; 重複間隔(列舉)
 @property(nonatomic,copy) NSCalendar *repeatCalendar; 重複日期(NSCalendar)
 
 @property(nonatomic,copy) CLRegion *region 設定區域(設定當進入某一個區域時,發出一個通知)
 
 @property(nonatomic,assign) BOOL regionTriggersOnce YES,只會在第一次進入某一個區域時發出通知.NO,每次進入該區域都會發通知
 
 @property(nonatomic,copy) NSString *alertBody;      
 
 @property(nonatomic) BOOL hasAction;                是否隱藏鎖屏介面設定的alertAction
 @property(nonatomic,copy) NSString *alertAction;    設定鎖屏介面一個文字
 
 @property(nonatomic,copy) NSString *alertLaunchImage;   啟動圖片
 @property(nonatomic,copy) NSString *alertTitle
 
 @property(nonatomic,copy) NSString *soundName;
 
 @property(nonatomic) NSInteger applicationIconBadgeNumber;
 
 @property(nonatomic,copy) NSDictionary *userInfo; // 設定通知的額外的資料
 */

- (IBAction)addLocalNote:(id)sender {
    // 1.建立一個本地通知
    UILocalNotification *localNote = [[UILocalNotification alloc] init];
    
    // 2.設定本地通知的一些屬性(通知發出的時間/通知的內容)
    // 2.1.設定通知發出的時間
    localNote.fireDate = [NSDate dateWithTimeIntervalSinceNow:5.0];
    // 2.2.設定通知的內容
    localNote.alertBody = @"吃飯了嗎?";
    // 2.3.設定鎖屏介面的文字
    localNote.alertAction = @"檢視具體的訊息";
    // 2.4.設定鎖屏介面alertAction是否有效
    localNote.hasAction = YES;
    // 2.5.設定通過點選通知開啟APP的時候的啟動圖片(無論字串設定成什麼內容,都是顯示應用程式的啟動圖片)
    localNote.alertLaunchImage = @"111";
    // 2.6.設定通知中心通知的標題
    localNote.alertTitle = @"222222222222";
    // 2.7.設定音效
    localNote.soundName = @"buyao.wav";
    // 2.8.設定應用程式圖示右上角的數字
    localNote.applicationIconBadgeNumber = 1;
    // 2.9.設定通知之後的屬性
    localNote.userInfo = @{@"name" : @"張三", @"toName" : @"李四"};
    
    // 3.排程通知
    [[UIApplication sharedApplication] scheduleLocalNotification:localNote];
}

當訊息被推送過來時,我們需要點選推送訊息,來完成一些特定的任務.不如更新介面什麼的(監聽本地推送通知的點選)

當用戶點選本地推送通知的時候,會自動開啟app,這裡有2種情況

1.app沒有關閉,只是一直隱藏在後臺
讓app進入前臺,並會呼叫AppDelegate的下面的方法(並非重新啟動app)

點選本地通知.gif
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
----程式碼實現

- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
    // 在這裡寫跳轉程式碼
    // 如果是應用程式在前臺,依然會收到通知,但是收到通知之後不應該跳轉
    if (application.applicationState == UIApplicationStateActive) return;
    
    if (application.applicationState == UIApplicationStateInactive) {
        // 當應用在後臺收到本地通知時執行的跳轉程式碼
        [self jumpToSession];
    }
    
    NSLog(@"%@", notification);
}

- (void)jumpToSession
{
    UILabel *redView = [[UILabel alloc] init];
    redView.backgroundColor = [UIColor redColor];
    redView.frame = CGRectMake(0, 100, 300, 400);
    redView.numberOfLines = 0;
    // redView.text = [NSString stringWithFormat:@"%@", launchOptions];
    [self.window.rootViewController.view addSubview:redView];
}

2.app已經被關閉(程序被殺死)

點選本地通知.gif
啟動app,啟動完畢會呼叫AppDelegate的下面的方法
- (BOOL)application:(UIApplication *)application didFinishLaunchWithOptions:(NSDictionary *)launchOptions;
launchOptions引數通過UIApplicationLaunchOptionsLocalNotificationKey取出本地推送通知物件
需要特別注意的是: 在iOS8.0以後本地通知有了一些變化,如果要使用本地通知,需要得到使用者的許可.
didFinishLaunchWithOptions方法中新增如下程式碼:


#define IS_iOS8 ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)

 if (IS_iOS8) {
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
        [application registerUserNotificationSettings:settings];
    }

-----程式碼實現相關操作

#define IS_iOS8 ([[UIDevice currentDevice].systemVersion floatValue] >= 8.0)

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    /*
     UIUserNotificationTypeNone    = 0,      不發出通知
     UIUserNotificationTypeBadge   = 1 << 0, 改變應用程式圖示右上角的數字
     UIUserNotificationTypeSound   = 1 << 1, 播放音效
     UIUserNotificationTypeAlert   = 1 << 2, 是否執行顯示橫幅
     */
    
    [application setApplicationIconBadgeNumber:0];
    
    if (IS_iOS8) {
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound categories:nil];
        [application registerUserNotificationSettings:settings];
    }
    
    // 如果是正常啟動應用程式,那麼launchOptions引數是null
    // 如果是通過其它方式啟動應用程式,那麼launchOptions就值
    if (launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]) {
        // 當被殺死狀態收到本地通知時執行的跳轉程式碼
        // [self jumpToSession];
        UILabel *redView = [[UILabel alloc] init];
        redView.backgroundColor = [UIColor redColor];
        redView.frame = CGRectMake(0, 100, 300, 400);
        redView.numberOfLines = 0;
        redView.text = [NSString stringWithFormat:@"%@", launchOptions];
        [self.window.rootViewController.view addSubview:redView];
    }
    
    return YES;
}
遠端推送(Remote Notification)

1.從遠端伺服器推送給客戶端的通知(需要聯網)
2.遠端推送服務, 蘋果起名為:APNS (Apple Push Notification Services)
解決問題:只要聯網了, 就能夠接收到伺服器推送的遠端通知
使用須知:
所有的蘋果裝置,在聯網狀態下,都會與蘋果伺服器建立長連線.
1.長連線:一直連線,客戶端與伺服器
2.長連線作用:
1>事件校準
2>系統升級
3>查詢我的iPhone等....
3.長連線的好處
1>資料傳輸速度快
2>資料保持最新狀態

官方結實長連線的使用

1.獲得deviceToken的過程

Snip20151005_1.png

Snip20151005_2.png

1>客戶端向蘋果服務APNS,傳送裝置的UDID和英語的Bundle Identifier.
2>經蘋果伺服器加密生成一個deviceToken
3>將當前使用者的deviceToken(使用者標識),傳送給自己應用的伺服器
4>自己的伺服器,將得到的deviceToken,進行儲存

2.利用deviceToken進行資料傳輸,推送通知

Snip20151005_3.png

5>需要推送的時候,將訊息和deviceToken一起傳送給APNS,蘋果伺服器,再通過deviceToken找到使用者,並將訊息發給使用者

這裡不再演示關於證書的配置, 簡單的只進行說明步驟:
1> 建立明確的AppID,只有明確的AppID才能進行一些特殊的操作
2>真機除錯的APNS SSL證書
3>釋出程式的APNS SSL證書
4>生成描述檔案
[依次安裝證書, 再裝描述]

註冊遠端推送通知:

1.客戶端如果想要接收APNs的遠端推送通知,必須先進行註冊(得到使用者授權)
一般在APP啟動完畢後就馬上進行註冊

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    if ([[UIDevice currentDevice].systemVersion doubleValue] >= 8.0) {
        // 1.註冊UserNotification,以獲取推送通知的許可權
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge categories:nil];
        [application registerUserNotificationSettings:settings];
        
        // 2.註冊遠端推送
        [application registerForRemoteNotifications];
    } else {
        [application registerForRemoteNotificationTypes:UIRemoteNotificationTypeNewsstandContentAvailability | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound];
    }
    
    return YES;
}

2.註冊成功後, 呼叫AppDelegate的方法,獲取到使用者的deviceToken

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    // <32e7cf5f 8af9a8d4 2a3aaa76 7f3e9f8e 1f7ea8ff 39f50a2a e383528d 7ee9a4ea>
    // <32e7cf5f 8af9a8d4 2a3aaa76 7f3e9f8e 1f7ea8ff 39f50a2a e383528d 7ee9a4ea>
    NSLog(@"%@", deviceToken.description);
}

3.點選推送通知,和本地一樣有兩種狀況.
1> app沒有關閉,只是一直隱藏在後臺
讓app進入前臺, 並呼叫下面的方法(app沒有重新啟動)
過期的方法:

// 當接受到遠端退職時會執行該方法(當進入前臺或者應用程式在前臺)
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    NSLog(@"%@", userInfo);
    
    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = [UIColor redColor];
    redView.frame = CGRectMake(100, 100, 100, 100);
    [self.window.rootViewController.view addSubview:redView];
}

蘋果系統建議使用下面的方法:

/*
 1.開啟後臺模式
 2.呼叫completionHandler,告訴系統你現在是否有新的資料更新
 3.userInfo新增一個欄位:"content-available" : "1" : 只要添加了該欄位,接受到通知都會在後臺執行
 */
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
    NSLog(@"%@", userInfo);
    UIView *redView = [[UIView alloc] init];
    redView.backgroundColor = [UIColor redColor];
    redView.frame = CGRectMake(100, 100, 100, 100);
    [self.window.rootViewController.view addSubview:redView];
    
    completionHandler(UIBackgroundFetchResultNewData);
}

2>app已經關閉,需要重新開啟,---基本實現方法和本地通知