iOS遠程推送和本地推送(一)


推送和通知的區(qū)別:
  • NSNotification:是看不到的
  • 推送通知:是可以看到的
推送通知分類
  • 本地推送通知
  • 遠程推送通知
推送通知作用

可以讓不在前臺運行的App告知用戶App內部發(fā)生了什么事情

推送通知效果
  • 屏幕頂部顯示一個橫幅
  • 屏幕中間彈出一個UIAertView
  • 鎖屏時候也照樣顯示
  • 呈現(xiàn)的通知同時修改應用圖標
  • 用戶接受的推送通知都會展示在通知中心
  • 播放音效
Snip20160425_9.png
手機設置推送通知
Snip20160425_10.png
推送通知的使用細節(jié)
  • 發(fā)送通知時,如果應用程序正在前臺運行,那么推送通知就不回顯示出來
  • 點擊推送通知默認會打開發(fā)送推送通知的應用
  • 不管應用是打開還是關閉,推送通知都可以如期發(fā)送

本地通知

什么是本地通知

  • 顧名思義,不需要聯(lián)網(wǎng)就能發(fā)送的通知,無需服務器.

本地通知使用場景

  • 常用來提醒用戶完成一些定時任務,比如
  • 鬧鐘,清理垃圾,買衣服,看電影,睡覺,運動等

如何發(fā)送本地推送通知

推送通知也屬于UI的一部分,所以推送通知對象是以UI開頭

  • 創(chuàng)建本地通知
//  創(chuàng)建本地通知對象
  UILocalNotification *ln = [[UILocalNotification alloc] init];
  • 設置本地通知屬性(推薦一個一個屬性測試運行)
//  1.設置通知的內容(如果此屬性不設置是不會發(fā)送通知的)
    ln.alertBody = @"小明,你媽叫你回家吃飯了!";
//  2.設置通知觸發(fā)的開始時間
    ln.fireDate = [NSDate dateWithTimeIntervalSinceNow:3];
//  3.設置重復通知的時間,間隔
    ln.repeatInterval = NSCalendarUnitSecond;
//  4.設置重復執(zhí)行使用日歷(用戶設置的日歷)
    ln.repeatCalendar = [NSCalendar  currentCalendar];
//    NSString * const NSGregorianCalendar; 公歷
//    NSString * const NSChineseCalendar; 農歷
//    ln.repeatCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSChineseCalendar];
//  5.設置應用圖標右上角的數(shù)字
    ln.applicationIconBadgeNumber = 3;
//  6.設置點擊推送通知進入界面的時候顯示,加載圖片
    ln.alertLaunchImage = @"";
//  7 設置通知的音效(只有真機有效)
    local.soundName = UILocalNotificationDefaultSoundName;
//  8 設置一些額外信息
    local.userInfo = @{@"QQ":@"55555",@"info":@"約了沒"};

//  iOS8.0 以后新增屬性
//  ************************************
//  1.設置區(qū)域,進入或離開某個區(qū)域的時候觸發(fā)
//    CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(40.1,106.1);
//    ln.region = [[CLCircularRegion alloc] initWithCenter:coordinate radius:10.0 identifier:@"ab"];
//  2.設置進入或離開某個區(qū)域只執(zhí)行一次
//    ln.regionTriggersOnce = YES;
//  ***************************************

//  iOS8.2 新增屬性
//    ln.alertTitle = @"通知標題";
  • 使用應用[UIApplication]調度本地通知
//  讓應用調度通知
    [[UIApplication sharedApplication] scheduleLocalNotification:ln];

本地推送通知頁面跳轉

無論應用是在前臺,后臺還是已經關閉都能如期接收到本地通知,但是當用戶點擊通知進入應用的時候,我們需要根據(jù)不同情況,進行處理

AppDelegate本地通知代理方法
/**
 *  一旦接收到本地通知就會調用該方法
 *  注意這個方法:應用在前臺也會調用
 *  @param application  應用
 *  @param notification 本地通知對象
 */
- (void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{

//  當應用在前臺時候什么都不做
    if (application.applicationState == UIApplicationStateActive) {
        return;
    }

//  當應用不再前臺的時候才去跳轉,這樣用戶體檢更好
    UITabBarController *tbVc = (UITabBarController *)application.keyWindow.rootViewController;
    tbVc.selectedIndex = 1;

}

但是當應用已經退出的時候,點擊通知進入本應用時候,不在調用application:didReceiveLocalNotification:的代理方法,難道當應用退出后,用戶再進入應用我們就不再跳轉指定界面了嗎?為了更好用戶體驗,我此時也應該讓應用跳轉到指定的界面,怎么才能實現(xiàn)這個功能呢? 我們知道當應用程序啟動的時候一定會調用application: didFinishLaunchingWithOptions:的代理方法,在這里我們能拿到本地通知信息,也可以跳轉相應的界面

//  如果是點擊本地通知進來的那么launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]就會有內容
    if(launchOptions[UIApplicationLaunchOptionsLocalNotificationKey])
    {
        //頁面跳轉
        UITabBarController *tbVc = (UITabBarController *)self.window.rootViewController;
        tbVc.selectedIndex = 1;
    }
一個應用可能要各種不同的通but知,點擊不同的通知可以跳轉不同界面,這個有該怎么做呢?

1.在發(fā)送通知時候,設置userInfo屬性

 //  7.設置應用信息
 ln.userInfo = @{@"pageKey":@"friend"};

2.在AppDelegate本地通知代理方法中進行判斷

/**
 *  一旦接收到本地通知就會調用該方法
 *  注意這個方法:應用在前臺也會調用
 *  @param application  應用
 *  @param notification 本地通知對象
 */
- (void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{

//  當應用在前臺時候什么都不做
    if (application.applicationState == UIApplicationStateActive) {
        return;
    }
//  當應用不再前臺的時候才去跳轉,這樣用戶體檢更好
//  獲取tabBarController
    UITabBarController *tbVc = (UITabBarController *)self.window.rootViewController;


//  獲取用戶設置的跳轉頁
    NSString *page = notification.userInfo[@"pageKey"];
//  如果是朋友圈
    if ([page isEqualToString:@"session"]) {
        tbVc.selectedIndex = 1;
    }else{
//       否則跳轉到好友
        tbVc.selectedIndex = 0;
    }
}
  • 測試launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]中的內容
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
//  獲取UIApplicationLaunchOptionsLocalNotificationKey對應內容
    id obj = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
//  獲取控制器(注意此時需要通過self.window,通過application.keyWindow無法獲取到,因為此時的window還沒有成為keyWindow)
    UITabBarController *tbVc = (UITabBarController *)self.window.rootViewController;
//  獲取索引為0的控制(注意此時tbVc.selectedViewController為nil)
    UIViewController *vc = tbVc.viewControllers[0];

//  創(chuàng)建一個文本
    UILabel *label = [[UILabel alloc] init];
    label.backgroundColor = [UIColor brownColor];
//  設置text為UIApplicationLaunchOptionsLocalNotificationKey對應的內容
    label.text =  [obj description] ;
    label.frame = CGRectMake(10, 100, 300, 400);
    label.numberOfLines = 0;
//  添加到控制器的View上
    [vc.view addSubview:label];


    return YES;
}
Snip20160425_11.png
  • 我們從中可以出他是一個UILocalNotification對象
  • 所以我們取出UILocalNotification對象,剩下的做法與接收到本地通知代理方法中處理相同,所以我們把它提取為一個公用的方法
/**
 *  根據(jù)通知跳轉到不同頁面
 */
- (void) jumpToPageWithLocalNotification:(UILocalNotification *) notification
{
    //  獲取tabBarController
    UITabBarController *tbVc = (UITabBarController *)self.window.rootViewController;

    //  獲取用戶設置的跳轉頁
    NSString *page = notification.userInfo[@"pageKey"];
    //  如果是朋友圈
    if ([page isEqualToString:@"session"]) {
        tbVc.selectedIndex = 0;
    }else{
        //       否則跳轉到好友
        tbVc.selectedIndex = 1;
    }
}
  • 在didReceiveLocalNotification方法中
/**
 *  一旦接收到本地通知就會調用該方法
 *  注意這個方法:應用在前臺也會調用
 *  @param application  應用
 *  @param notification 本地通知對象
 */
- (void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{

//  當應用在前臺時候什么都不做
    if (application.applicationState == UIApplicationStateActive) {
        return;
    }
//  當應用不再前臺的時候才去跳轉,這樣用戶體檢更好
    [self jumpToPageWithLocalNotification:notification];
}
  • 在didFinishLaunchingWithOptions方法中
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
//  如果是點擊本地通知進來的那么launchOptions[UIApplicationLaunchOptionsLocalNotificationKey]就會有內容
    UILocalNotification *notifcation = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
//  如果存在通知
    if(notifcation){
        [self jumpToPageWithLocalNotification:notifcation];
    }

    return YES;
}

iOS8的不同點

你如果把上面的程序運行在iOS8上,會爆出如下錯誤

][615:7847] Attempting to schedule a local notification {fire date = Monday, July 13, 2015 at 9:02:25 AM China Standard Time, time zone = (null), repeat interval = 0, repeat count = UILocalNotificationInfiniteRepeatCount, next fire date = Monday, July 13, 2015 at 9:02:25 AM China Standard Time, user info = { pageKey = friend; }} with an alert but haven't received permission from the user to display alerts

也就是在iOS8上要發(fā)送本地通知需要 請求用戶權限 如何請求用戶權限呢?一般在新版有變化的地方,在頭文件中都會有相應的說明,所以點擊到scheduleLocalNotification:方法中,看看有沒有我們需要信息

Snip20160425_12.png

意思就是說:在iOS8.0以后,在調度通知之前你需要使用UIApplication的對象方法registerUseNotificationSetting:來請求用戶授權.

這種請求權限的代碼一般放在didFinishLaunchingWithOptions:方法中,在用戶不卸載的情況下,只需要請求一次,下次在運行就不用請求了!

//  1.如果是iOS8請求用戶權限
    if ([UIDevice currentDevice].systemVersion.doubleValue >= 8.0) {

        /*
         UIUserNotificationType:

         UIUserNotificationTypeBadge   = 1 << 0, // 接收到通知可更改程序的應用圖標
         UIUserNotificationTypeSound   = 1 << 1, // 接收到通知可播放聲音
         UIUserNotificationTypeAlert   = 1 << 2, // 接收到通知課提示內容
         如果你需要使用多個類型,可以使用 "|" 來連接
         */

//      向用戶請求通知權限
//      categories暫時傳入nil
        UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil];

        [application registerUserNotificationSettings:setting];
    }

運行程序

Snip20160425_13.png

測試點擊通知,進入應用,也沒問題

接下來,我們說說-[UIUserNotificationSettings settingsForTypes:categories:] 中的 categories

  • categories可以讓我們發(fā)送通知之前預定義一些通知也就是通知上可以顯示按鈕,他需要是一個裝有UIUserNotificationCategory類的對象的NSSet的對象. 但是官方推薦我們使用它的子類UIMutableUserNotificationCategory,來動態(tài)的添加通知的行為按鈕,iOS8支持前臺和后臺的兩種行為.
4月 25, 2016 16:41.gif
  • 通知Action按鈕以長條展示如圖
4月 25, 2016 16:43.gif
  • 注冊分類,并在分類中添加不同的行為 由于注冊用戶通知設置代碼量比較大我們實現(xiàn)一個新的方法registerUserNotification
(void) registerUserNotification
{
    //      向用戶請求通知權限
    /*
     UIUserNotificationType:用戶通知的類型

     UIUserNotificationTypeBadge   = 1 << 0, // 接收到通知可更改程序的應用圖標
     UIUserNotificationTypeSound   = 1 << 1, // 接收到通知可播放聲音
     UIUserNotificationTypeAlert   = 1 << 2, // 接收到通知課提示內容
     如果你需要使用多個類型,可以使用 "|" 來連接
     */
//  1.設置用戶通知權限類型
    UIUserNotificationType types = UIUserNotificationTypeBadge|UIUserNotificationTypeSound|UIUserNotificationTypeAlert;


//  2.創(chuàng)建通知的行為按鈕

//  2.1創(chuàng)建第一個行為
    UIMutableUserNotificationAction *action1 = [[UIMutableUserNotificationAction alloc] init];
//  2.1.1 設置行為的唯一標示
    action1.identifier = UIMutableUserNotificationActionBackground;
//  2.1.2 設置通知按鈕的的標題
    action1.title = @"后臺";
//      以什么樣模式運行應用
//        UIUserNotificationActivationModeForeground, // 當應用在前臺的時候觸發(fā)
//        UIUserNotificationActivationModeBackground  // 即使應用不在前臺也觸發(fā)
    action1.activationMode = UIUserNotificationActivationModeBackground;
//  2.1.3 是否只有鎖屏的鎖屏狀態(tài)下才能顯示
    action1.authenticationRequired = NO;
//  2.1.4 按鈕的性質
    action1.destructive = NO;

//  2.1創(chuàng)建第一個行為
    UIMutableUserNotificationAction *action2 = [[UIMutableUserNotificationAction alloc] init];
//  2.1.1 設置行為的唯一標示
    action2.identifier =UIMutableUserNotificationActionForeground;
//  2.1.2 設置通知按鈕的的標題
    action2.title = @"前臺";
//      以什么樣模式運行應用
    //        UIUserNotificationActivationModeForeground, // 當應用在前臺的時候觸發(fā)
    //        UIUserNotificationActivationModeBackground  // 即使應用不在前臺也觸發(fā)
    action2.activationMode = UIUserNotificationActivationModeForeground;
    //  2.1.3 用戶必須輸入密碼才能執(zhí)行
    action2.authenticationRequired = YES;
    //  2.1.4 按鈕的性質(沒有效果)
    action2.destructive = YES;


//  3.創(chuàng)建用戶通知分類
    UIMutableUserNotificationCategory *category = [[UIMutableUserNotificationCategory  alloc]  init];
//  3.1 設置類別的唯一標識
    category.identifier = @"myCategory";
//  3.2 設置通知的按鈕
    //    Context:
    //        UIUserNotificationActionContextDefault,  //默認上下文(情景)下的英文(通常都是)
    //        UIUserNotificationActionContextMinimal   //通知內容區(qū)域受限情況下內容
    [category   setActions:@[action1,action2] forContext:UIUserNotificationActionContextDefault];


//  4.創(chuàng)建用戶通知的設置信息
    UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:types categories:[NSSet setWithObject:category]];

//  注冊設置
    [[UIApplication sharedApplication] registerUserNotificationSettings:setting];
}

  • 在發(fā)送本地推送通知時候指定通知的分類標示
   //  9.設置通知的類別
    ln.category = @"myCategory";
  • 監(jiān)聽點擊通知按鈕的行為,在AppDelegate中實現(xiàn)監(jiān)聽通知按鈕點擊方法
/**
 *  當用戶點擊通知上定制的按鈕執(zhí)行的行為(注意:不點擊行為按鈕,不會進入該方法)
 *
 *  @param application       應用
 *  @param identifier        行為標識符
 *  @param notification      本地通知
 *  @param completionHandler 完成回調
 */
- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)notification completionHandler:(void (^)())completionHandler
{
//  處理不同行為
    if ([identifier isEqualToString:UIMutableUserNotificationActionBackground]) {
        NSLog(@"后臺運行程序");
    }else if ([identifier isEqualToString:UIMutableUserNotificationActionForeground]){
        NSLog(@"前臺運行程序");
    }else{
        NSLog(@"其他");
    }
    /**
       You should call the completion handler as soon as you've finished handling the action.
       當任務處理完畢時候,你應該盡快的調用completion的block.
     */

// 在當任務完成的時候,調用任務完成的block
    completionHandler();
}

iOS8 基于位置的本地通知
什么是基于位置的本地通知
  • 基于位置的本地通知就是當用戶進入或離開某個區(qū)域,就會給該用戶發(fā)送一條本地通知
  • 基于位置的本地通知只有在iOS8.0以后才能使用
實現(xiàn)步驟:

在 didFinishLaunchingWithOptions方法中注冊通知權限

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    if ([application respondsToSelector:@selector(registerUserNotificationSettings:)]) {

        UIUserNotificationType types = UIUserNotificationTypeBadge|UIUserNotificationTypeAlert|UIUserNotificationTypeSound;

        UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:types categories:nil];

        [application registerUserNotificationSettings:setting];
    }


    return YES;
}
  • 在發(fā)送通知之前要請求使用用戶的位置權限

  • 在info.plist增加 NSLocationWhenInUseUsageDescription 的Key,類型為String,值填寫需要提示內容

  • 定一個 CLLocationManager 類型的屬性

@property (nonatomic, strong) CLLocationManager *locManager;
  • 通過懶加載的方式其進行初始化并設置其代理
 懶加載位置管理器對象
 - (CLLocationManager *)locManager
 {
     if (_locManager == nil) {
         _locManager = [[CLLocationManager alloc] init];
         _locManager.delegate = self;
     }
     return _locManager;
 }
  • 發(fā)送基于位置的推送通知之前首先判斷用戶是否已經擁有了,訪問位置的權限,如果如果沒有請求權限,如果已經有就直接發(fā)送推送通知
(IBAction)baseLocationNotification { 
// 請求注冊權限 if([CLLocationManager authorizationStatus] != kCLAuthorizationStatusAuthorizedWhenInUse){ //請求使用用戶位置權限

  [self.locManager requestWhenInUseAuthorization];
}else{ // 發(fā)送基于位置本地通知

  [self scheduleBaseLocationNotification];
}

} 

  • 監(jiān)聽用戶授權的改變
  - (void) locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
  {
      if (status == kCLAuthorizationStatusAuthorizedWhenInUse) {
  //       發(fā)送基于位置通知
          [self scheduleBaseLocationNotification];
      }
  }
  • 實現(xiàn)發(fā)送基于位置的通知方法
  - (void) scheduleBaseLocationNotification
  {
  //  創(chuàng)建本地通知對象  
      UILocalNotification *loc = [[UILocalNotification alloc] init];  
  //  設置通知提示內容
      loc.alertBody = @"歡迎來到傳智博客";
  //  創(chuàng)建經緯度坐標
      CLLocationCoordinate2D coordinate = CLLocationCoordinate2DMake(23.139009,113.363798);
  //  設置觸發(fā)的區(qū)域,當用戶進入或離開這個區(qū)域的時候就會觸發(fā)
          loc.region = [[CLCircularRegion alloc] initWithCenter:coordinate radius:100 identifier:@"loc"];
      //  設置是否只觸發(fā)一次
      //  YES 表示只觸發(fā)一次(用戶進入或離開這個區(qū)域的時候觸發(fā)一次)  NO 表示可以(用戶每次進入或離開這個區(qū)域的時候都會觸發(fā))
          loc.regionTriggersOnce = NO;
      //  調度通知
          [[UIApplication sharedApplication] scheduleLocalNotification:loc];

  }
說明
  • 基于位置本地通知,提醒做不到非常精確他依賴與GPS和周圍的信號基站
  • 基于位置的本地通知,只有真機才能測試
  • 基于位置的本地通知,無需編程人員主動獲取用戶位置,我們添加應用調度中,如果用戶手機打開了定位,系統(tǒng)會根據(jù)用戶當前的位置來決定是否要給該用戶發(fā)送通知.

有關遠程推送的請見下篇

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容