推 送 機 制ios
NSNotificationCenter實現了觀察者模式,容許應用的不一樣對象之間以鬆耦合的方式進行通訊。編程
NSNotification表明Poster與Observer之間的信息載體,該對象包含以下只讀屬性。數組
name:該屬性表明該通知的名字,程序將Poster註冊到指定通知中心時,就是根據該名稱進行註冊的瀏覽器 |
object:該屬性表明該通知的Poster。服務器 |
userInfo:該屬性是一個NSDictionary對象,用於攜帶通知的附加信息。併發 |
NSNotificationCenter是整個通知系統的中心,Observer向NSNotificationCenter註冊本身感興趣的通知,Poster向NSNotificationCenter發送通知。app
- addObserverForName:object:queue:usingBlock:該方法將指定代碼塊註冊爲監聽者,監聽object:參數表明的對象(Poster)發出的通知(由第1個參數指定通知名稱)。該方法直接使用指定代碼塊做爲監聽者,當Poster向NSNotificationCenter發送通知時,將會觸發、執行該代碼塊。若是object:參數爲nil,則用於監放任何對象發出的通知。異步 |
示例說明async |
1 ViewController.m 2 3 @implementation ViewController 4 5 - (void)viewDidLoad 6 7 { 8 9 [super viewDidLoad]; 10 11 // 監聽UIApplicatiob的 UIApplicationDidFinishLaunchingNotification通知 12 13 [[NSNotificationCenter defaultCenter] addObserver:self 14 15 selector:@selector(launch:) 16 17 name:UIApplicationDidFinishLaunchingNotification 18 19 object:[UIApplication sharedApplication]]; 20 21 // 監聽UIApplicatiob的 UIApplicationDidEnterBackgroundNotification通知 22 23 [[NSNotificationCenter defaultCenter] addObserver:self 24 25 selector:@selector(back:) 26 27 name:UIApplicationDidEnterBackgroundNotification 28 29 object:[UIApplication sharedApplication]]; 30 31 // 監聽UIApplicatiob的 UIApplicationWillEnterForegroundNotification通知 32 33 [[NSNotificationCenter defaultCenter] addObserver:self 34 35 selector:@selector(fore:) 36 37 name:UIApplicationWillEnterForegroundNotification 38 39 object:[UIApplication sharedApplication]]; 40 41 } 42 43 - (void)back: (NSNotification*)Notification 44 45 { 46 47 self.showLabel.text = [NSString stringWithFormat:@」應用程序加載完成!」]; 48 49 } 50 51 - (void)launch: (NSNotification*)Notification 52 53 { 54 55 self.showLabel.text = [NSString stringWithFormat:@」%@\n應用程序進入後臺!」, 56 57 self.showLabel.text]; 58 59 } 60 61 - (void) fore: (NSNotification*)Notification 62 63 { 64 65 self.showLabel.text = [NSString stringWithFormat:@」%@\n應用程序進入前臺!」, 66 67 self.showLabel.text]; 68 69 } 70 71 @end
|
使用NSNotificationCenter除了能夠監聽系統組件發出的通知以外,也能夠監聽程序本身發出的通知.下面示例將使用異步操做來模擬執行一個耗時任務,並在界面上使用UIProgressView顯示耗時任務的執行進度.ide
示例代碼 |
ViewController.m @import 「ViewController.h」 #define PROGRESS_CHANGED @」down_progress_changed」 @interface ViewController() { NSNotificationCenter* nc; NSOperationQueue* queue; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; nc = [NSNotificationCenter defaultCenter]; queue = [[NSOperationQueue alloc] init]; // 設置該隊列最多支持10個併發線程 queue.maxConcurrentOperationCount = 10; // 使用視圖控制器監放任何對象發出的 PROGRESS_CHANGED 通知 [nc addObserver:self selector:@selector(update:) name: PROGRESS_CHANGED object:nil]; // ① } - (IBAction)start: (id)sender { __block int progStatus = 0; [sender setEnabled:NO]; // 以傳入的代碼塊做爲執行體,建立NSOperation NSBlockOperation* operation = [NSBlockOperation blockOperationWithBlock:^{ for(int I = 0; i < 100; i++) { // 暫停0.5秒模擬耗時任務 [NSThread sleepForTimeInterval: 0.5] ; // 建立NSNotification,並指定userInfo信息 NSNotification* noti = [NSNotification notificationWithName: PROGRESS_CHANGED object:nil userInfo: [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt: ++ progStatus] ,@」prog」 , nil]]; // 發送通知 [nc postNotification : noti]; // ② } }]; // 將NSOperation添加給NSOperationQueue [queue addOperation: operation]; } - (void)update: (NSNotification*) noti { // 經過userInfo屬性獲取耗時任務的進度信息 NSNumber* progStatus = noti.userInfo[@」prog」]; NSLog(@」%d」, progStatus.intValue); dispatch_async(dispatch_get_main_queue(), ^{ self.prog.progress = progStatus.intValue / 100.0; // 當任務執行進度執行到100時,啓用按鈕 if(100 == progStatus.intValue) { [self.bn setEnabled: YES]; } }); } @end
|
上面程序中的第1行代碼將視圖控制器註冊爲通知監聽者,用於監放任何對象的PROGRESS_CHANGED通知;接下來的第②行代碼先建立了一個NSNotification,並使用NSNotificationCenter發送該通知。當該異步代碼塊向NSNotificationCenter發送通知以後,通知監聽者的方法(update:)將會被觸發執行,這個update:方法將會更新界面上UIProgressView的進度. |
本地通知屬於應用界面編程的內容,本地通知和遠程推送通知均可以向不在前臺運行的應用發送消息,這種消息既多是即將發生的事件,也能夠是服務器的新數據,均可能顯示爲一段警告信息信息或應用程序圖標上的徽標。
本地通知和遠程推送通知的基本目的都死讓應用程序可以通知用戶某些事情,並且不須要應用程序在前臺運行。兩者的區別在於:本地通知由本應用負責調用,只能從當前設備上的 iOS 發出;而遠程推送通知由遠程服務器上的程序(可由任意語言編寫)發送至 Apple Push Notification service(APNs), 再由 APNs 把消息推送至設備上對應的程序.[BL1]
本地通知是一個 UILocalNotification對象,它有以下經常使用屬性. |
fireData: 指定通知將在什麼時間觸發. |
repeatInterval:設置本地通知重複發送的時間間隔. |
alertBody: 設備本地通知的消息體. |
alertAction: 設置當設備處於鎖屏狀態時,顯示通知的警告框下方的 title. |
has Action: 設置是否顯示 Action. |
alertLaunchImage: 當用戶經過該通知啓動對應的應用時, 該屬性設置爲加載圖片. |
applicatonIconBadgeNumber: 設置顯示在應用程序上紅色徽標中的數字. |
soundName: 設置通知的聲音. |
userInfo: 設置該通知攜帶的附加信息. |
|
建立了 UILocalNotification對象以後,接下來就能夠經過 UIApplication 的以下兩個方法發送通知了 |
l - scheduleLocalNotification: 該方法指定調度通知。通知將會於 fireDate 指定的時間觸發,並且會按 repeatInterval 指定的時間間隔重複觸發。 l - presentLocalNotificationNow: 該方法指定當即發送通知。該方法會忽略UILocalNotification的fireDate屬性。 |
若是系統發出通知時,應用程序處於前臺運行,系統將會觸發應用程序委託類的application:didReceiveLocalNotification:方法。 |
|
在iOS應用中發送本地通知的步驟很簡單,只要以下幾步便可。
|
示例示範如何開發本地通知 |
ViewController.m @interface ViewController() { UIApplication* app; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; app = [UIApplication sharedApplication]; } - (IBAction)changed: (id)sender { UISwitch* sw = (UISwitch*)sender; if(sw.on) { // 建立一個本地通知 UILocalNotification* notification = [[UILocalNotification alloc] init]; // ① // 設置通知的觸發時間 notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:10]; // 設置通知的時區 notification.timeZone = [NSTimeZone defaultTimeZone]; // 設置通知重複發送的時間間隔 notification.repeatInterval = kCFCalendarUnitMinute; // 設置通知的聲音 notification.soundName = @」gu.mp3」; // 設置當設備處於鎖屏狀態時, 顯示通知的警告框下方的 title notification.alertAction = @」打開」; // 設置通知是否顯示 Action notification.hasAction = YES; // 設置經過通知加載應用時顯示的圖片 notification.alertLaunchingImage = @」logo.png」; // 設置通知內容 notification.alertBody = @」輪到你下棋了, 趕快走棋!」; // 設置顯示在應用程序上紅色徽標中的數字 notification.applicationIconBadgeNumber = 1; // 設置 userInfo, 用於攜帶額外的附加信息 NSDictionary* info = @{@」123456」: @」key」}; notification.userInfo = info; // 調度通知 [app scheduleLocalNotification:Notification]; // ① } else { // 獲取全部處於調度中的本地通知數組 NSArray* localArray = [app scheduledLocalNotifications]; if(localArray) { for(UILocalNotification * noti in localArray) { NSDictionary* dict = noti.userInfo; if(dict) { // 若是找到要取消的通知 NSString* inKey = [dict objectForKey:@」key」]; if([inKey isEqualToString:@」123456」]) { // 取消調度該通知 [app cancelLocalNotification: noti]; // ② } } } } } } @end
|
上面程序中的第①段代碼建立了一個UILocalNotification對象,併爲該對象設置了相關屬性,接下來在①號代碼處調用了UIApplication的scheduleLocalNotification:方法來調度通知,這樣該通知將會在指定事件觸發,並按相應的週期重複執行。當用戶把UISwitch控件切換到關閉狀態時,②號代碼將會取消調度該通知。 爲了讓程序處於前臺運行時也能看到本地通知,還重寫了應用程序委託類的application:didReceiveLocalNotification:方法。 |
AppDelegate.m @implementation AppDelegate // 只有當應用程序在前臺運行時,該方法纔會被調用 - (void)application: (UIApplication*)application didReceiveLocalNotification: (UILocalNotification*) notification { // 若是應用程序在前臺運行,則將應用程序圖標上的紅色徽標中的數字設爲0 application.applicationIconBadgeNumber = 0; // ① // 使用UIAlertView顯示本地通知的信息 [[[UIAlertView alloc] initWithTitle:@」 收到通知 」 message:notification.alertBody delegate:nil cancelButtonTitle:@」肯定」 otherButtonTitles: nil] show]; // ② } - (void)applicationWillEnterForeground: (UIApplication*) application { // 當應用程序再次進入前臺運行時,將應用程序徽標中數字設爲0 application.applicationIconBadgeNumber = 0; } … @end
|
上面程序中的第①②段代碼控制當應用程序處於前臺運行時,即便程序收到了本地通知,也依然會將應用程序圖標上的紅色徽標中數字設爲0。 |
iOS遠程推送通知由遠程服務器上的程序(可由任意語言編寫)發送至APNs,再由APNs把消息推送至設備上對應的程序。
iOS遠程推送通知的過程可用下圖進行描述
在上面中,Provider指遠程服務器上的Push服務端應用,這種Push服務端應用可使用任意語言編寫,如Java、PHP等。
APNs由Apple公司提供,APNs負責把通知發送到對應的iOS設備,該設備再把通知轉發給ClientApp-----即咱們的iOS應用。
上面所示的過程分爲3個階段 |
第一個階段:Provider程序把要發送的通知、目標iPhone的device token (至關於該設備的惟一標識)打包,發給APNs. |
第二階段:APNs經過已註冊Push服務的iPhone列表查找具備對應device token的iPhone,並把Push通知發送給對應的iPhone。 |
第三階段:iPhone將收到的Push通知傳遞給相應的應用程序,而且按照設定彈出Push通知。 |
實際上,Push服務端程序能夠經過APNs將一條通知發送給多個iPhone 上的客戶端應用;與此同時,iPhone上的客戶端應用也可接收多個Push服務端程序發送過來的推送通知。下圖顯示了這種示意圖
|
對於開發iOSPush服務而言,完整的過程以下。
|
從上圖能夠看出,Push客戶端應用須要3個組件。
Push服務端程序則須要以下兩個組件
|
開發Push客戶端應用須要到Apple網站註冊一個App ID,並且該App ID不容許使用通配符。經過Apple網站註冊App ID的步驟以下。
|
|
將證書籤名請求文件保存到磁盤上,此處將該文件保存爲「Push。cerSigningRequest」。
在上圖所示頁面中,能夠看到在「iOS Apps」欄目下包含了Certificates、Identifiers、Device、ProvisioningProfiles-----這些只有登陸帳號已經加入iOS Developer Program(iDP)的緣由。 |
|