iOS-----推送機制(上)

  推 送 機 制ios

使用NSNotificationCenter通訊

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監聽自定義通知

使用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本地通知

   本地通知屬於應用界面編程的內容,本地通知和遠程推送通知均可以向不在前臺運行的應用發送消息,這種消息既多是即將發生的事件,也能夠是服務器的新數據,均可能顯示爲一段警告信息信息或應用程序圖標上的徽標。

     本地通知和遠程推送通知的基本目的都死讓應用程序可以通知用戶某些事情,並且不須要應用程序在前臺運行。兩者的區別在於:本地通知由本應用負責調用,只能從當前設備上的 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應用中發送本地通知的步驟很簡單,只要以下幾步便可。

  1. 建立UILocalNotification對象
  2. 設置UILocalNotification的屬性
  3. 調用UIApplication的方法發送或調用通知
  4. 若是但願應用程序在前臺運行時能夠對通知進行相應的處理,則須要重寫應用程序委託類的application:didReceiveLocalNotification:方法。
  5. 當應用須要取消本地通知時,可調用UIApplication的cancelLocalNotification:方法取消指定通知,或調用cancelLocalNotifications方法取消全部通知。

示例示範如何開發本地通知

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遠程推送通知

 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服務而言,完整的過程以下。

  1. 應用程序註冊遠程推送通知。
  2. 當應用程序註冊推送通知成功或註冊失敗時,系統都會觸發應用程序委託類的對應方法。能夠經過重寫應用程序委託類的這些方法來獲取該設備註冊成功後獲得的device token。
  3. 應用程序將device token發送給Push服務端程序
  4. 服務端程序向APNs發送通知。
  5. APNs將通知發送給iOS應用------實際的過程是先發送給指定的iOS設備,再由該設備彈出Push通知。[BL2] 

 

從上圖能夠看出,Push客戶端應用須要3個組件。

  • App ID(應用程序惟一標識,這個必須到Apple網站註冊來得到)
  • Provisioning Profile(這個也必須到Apple網站下載)
  • device token(當Push客戶端應用註冊Push推送通知成功時,APNs將會返回該設備的device  token)。[BL3] 

Push服務端程序則須要以下兩個組件

  • SSL Certificate(SSL鏈接證書,這個必須從Apple網站下載)。
  • Private Key(私鑰,這個可用過開發者電腦導出)。

開發Push客戶端應用

開發Push客戶端應用須要到Apple網站註冊一個App ID,並且該App ID不容許使用通配符。經過Apple網站註冊App ID的步驟以下。

  1. 打開OS X系統上的」鑰匙串訪問」應用,單擊該應用的主菜單」鑰匙串訪問」 →」證書助理」→」從證書頒發機構請求證書」,以下圖所示.

 

  1. 單擊」從證書頒發機構請求證書」後,將會顯示下圖所示的對話框
  2. 輸入電子郵件地址和經常使用名稱,並選中「存儲到磁盤」單選鈕,而後單擊「繼續」按鈕,該程序將會建立一個「Certificate Signing Request」(證書籤名請求)文件,系統彈出下圖所示的保存文件對話框

 

將證書籤名請求文件保存到磁盤上,此處將該文件保存爲「Push。cerSigningRequest」。

  1. 使用瀏覽器打開 https://developer.apple.com/ios/manage/overview/index.action站點, 頁面上將會提示用戶輸入開發者帳號\密碼. 登陸成功後會看到以下說是的頁面

 

在上圖所示頁面中,能夠看到在「iOS Apps」欄目下包含了Certificates、Identifiers、Device、ProvisioningProfiles-----這些只有登陸帳號已經加入iOS Developer Program(iDP)的緣由。

  1. 單擊「iOS Apps」 →「Identifiers」→欄目下的」App IDS」 連接,系統將會顯示以下圖

   

 


 [BL1]本地通知與遠程推送的區別

 [BL2]開發iOSPush服務的完整的過程

 [BL3]Push客戶端應用須要3個組件

相關文章
相關標籤/搜索