iOS 推送通知流程

本文根據(jù)此文稍作精簡: http://www.reibang.com/p/d18c51b3321d
作者:Poker_Facer

一、本文總結(jié)了項目iOS8-10的通知適配工作

iOS推送通知幾乎每年都在改铃在,直到iOS10的出現(xiàn),蘋果對這塊進行了重構(gòu)拇泣。本文總結(jié)了一下項目中iOS8-10的通知模塊適配工作。

二矮锈、實際開發(fā)中的適配工作

在實際開發(fā)中霉翔,iOS8-10的適配代碼如下:

- (void)setupWithOptions:(NSDictionary *)launchOptions {
    // iOS8-10.0 注冊通知
    if (!IS_IOS(10.0)) {
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
        [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
    }
    // iOS10.0+ 開啟通知權(quán)限
    else {
        UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter];
        center.delegate = self;
        UNAuthorizationOptions options = UNAuthorizationOptionBadge | UNAuthorizationOptionSound | UNAuthorizationOptionAlert;
        [center requestAuthorizationWithOptions:options completionHandler:^(BOOL granted, NSError * _Nullable error) {

        }];
    }
    
    // 啟動極光推送SDK
    [JPUSHService setupWithOption:launchOptions
                           appKey:kJPUSHAppKey
                          channel:channel
                 apsForProduction:VERSION_RELEASE
            advertisingIdentifier:nil];
    
    // 極光推送日志打印開關(guān)
    if (VERSION_RELEASE) {
        [JPUSHService setLogOFF];
    } else {
        [JPUSHService setDebugMode];
    }
    
    // 注冊極光推送(內(nèi)部會調(diào)用registerForRemoteNotifications注冊APNS)
    JPUSHRegisterEntity *entity = [[JPUSHRegisterEntity alloc] init];
    entity.types = JPAuthorizationOptionAlert | JPAuthorizationOptionBadge | JPAuthorizationOptionSound;
    [JPUSHService registerForRemoteNotificationConfig:entity delegate:self];
}

iOS10通過UNNotificationTrigger這個類的子類來區(qū)分遠程通知和本地通知。

  • iOS8 通知請求權(quán)限修改愕难。即UIRemoteNotificationType由UIUserNotificationType代替早龟,并加入了UIUserNotificationSettings。

  • iOS9 通知加入可輸入操作猫缭。

  • iOS10 通知重構(gòu)葱弟,全新框架UNUserNotifications。

三猜丹、遠程通知與本地通知的觸發(fā)和調(diào)用

各版本通知中使用的類圖表:


各版本通知類圖.png

1芝加、普通本地通知

  • 程序殺死狀態(tài)。
    所有版本射窒,本地通知在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法中獲取藏杖。[launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey]即為我們需要的本地通知對象。沒有通知時launchOptions為空脉顿。
  • 程序后臺狀態(tài)蝌麸。
    iOS10以下,在點擊通知會調(diào)用- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification方法艾疟。
    iOS10會調(diào)用- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler方法来吩。
  • 程序前臺狀態(tài)。
    iOS10以下不會觸發(fā)通知欄蔽莱,并且還是調(diào)用- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification方法弟疆。
    iOS10會立馬觸發(fā)- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions))completionHandler方法,并且能根據(jù)completionHandler回調(diào)配置通知的顯示樣式盗冷。點擊通知后同樣會觸發(fā)- (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)())completionHandler方法怠苔。

值得注意的是,程序后臺狀態(tài)下仪糖,代理方法都是在用戶點擊通知后才會執(zhí)行柑司,收到通知點擊應(yīng)用圖標(biāo)啟動是不會走代理方法的。

程序殺死狀態(tài)下啟動應(yīng)用只會觸發(fā)- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法锅劝。

iOS10所有的通知帜羊,都只會觸發(fā)下面兩個方法。而區(qū)分遠程還是本地通知鸠天,就是前面提到的UNNotificationTrigger的子類讼育,當(dāng)UNNotificationRequest的trigger為UNPushNotificationTrigger時,說明此通知為遠程通知,否則為本地通知奶段。下面為代理方法:

// iOS10通知代理方法饥瓷,應(yīng)用程序在前臺的時候調(diào)用
- (void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler {
    UNNotificationRequest *request = notification.request;
    NSDictionary *userInfo = request.content.userInfo;
    
    if ([request.trigger isKindOfClass:[UNPushNotificationTrigger class]]) {
        NSLog(@"收到了一個遠程推送:%@", userInfo);
    } else {
        NSLog(@"收到了一個本地推送:%@", userInfo);
    }
    
    //此方法回調(diào),設(shè)置程序前臺時banner提示框的顯示選項
completionHandler(UNNotificationPresentationOptionAlert | UNNotificationPresentationOptionSound);
}

// iOS10通知代理方法,通知前后臺點擊時會觸發(fā)痹籍。
-  (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(nonnull void (^)(void))completionHandler {
    NSDictionary *userInfo = response.notification.request.content.userInfo;
    // 只有本地通知才能獲取到這個key對應(yīng)的value
    NSData *modelData = userInfo[CYLocalNotificationModelKey];
    if (modelData) {
        [[CYLocalNotificationMgr sharedManager] handleLocalNotificationResponse:response];
    }

    completionHandler();
}

遠程通知和本地通知之所以能統(tǒng)一規(guī)范呢铆,就是因為其原理類似,唯一的區(qū)別在于遠程通知需要獲取用戶的token蹲缠,通過蘋果的APNS將通知發(fā)送給對應(yīng)用戶棺克,而具體通知的內(nèi)容則由后臺配置的那個aps字典決定了。

2线定、普通遠程通知

下面是iOS8-9遠程通知相關(guān)的代理方法

/**
 已經(jīng)收到遠程推送消息
 @param userInfo 收到的userInfo信息
 */
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    if (application.applicationState == UIApplicationStateActive) {
        NSLog(@"程序運行中收到通知");
    } else {
        NSLog(@"程序不活躍中收到通知");
    }
}

/**
 后臺模式收到的遠程推送信息娜谊,需要開啟后臺模式的遠程推送,實現(xiàn)了此方法斤讥,上面的方法就失效纱皆。
 */
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    if (application.applicationState == UIApplicationStateActive) {
        NSLog(@"程序運行中收到通知");
    } else {
        NSLog(@"程序不活躍中收到通知");
    }      
    completionHandler(UIBackgroundFetchResultNewData);
}

遠程推送需要后臺配置title等參數(shù),也就是在本地通知中設(shè)置的那些什么alertTitle芭商,alertBody啥子的派草。基本格式如下:

{
  "aps" : {
    "alert" : {
      "title" : "主標(biāo)題",
      "subtitle" : "子標(biāo)題",
      "body" : "通知內(nèi)容"
    },
    "badge" : 2,
    "sound" : "alert.wav"
  },
  "custom" : "something"
}

其中aps為固定對象铛楣,后臺需要傳輸自己的參數(shù)可以自行添加與aps并列的鍵值對近迁。

  • subtitle是iOS10才有的,iOS10之前加不加無所謂簸州。
  • sound為提示音钳踊,默認(rèn)為default,自定義時別忘了后綴勿侯。
  • custom為自擴展字段,比如iOS10中圖片和視頻的連接地址就可以放這里缴罗。

3助琐、高級遠程通知

所謂高級,無非就是iOS10以下的可操作通知面氓、iOS10中通知的增刪改兵钮,以及UNNotificationServiceExtension和UNNotificationContentExtension這兩個通知擴展了。由于是遠程通知舌界,這里僅附上測試aps格式掘譬,方便測試。

{
  "aps" : {
    "alert" : {
      "title" : "這是title",
      "subtitle" : "這是subtitle",
      "body" : "這是body"     
    },
    "mutable-content" : "1",            
    "category" : "myNotificationCategory"               
  }
}
  • 此aps可以用來測試上述所有高級遠程通知呻拌。
  • category中的值必須與測試可操作通知時的category值一樣葱轩。
  • 測試UNNotificationContentExtension時,必須和plist文件中的UNNotificationExtensionCategory所對應(yīng)的值保持一致,編譯對應(yīng)的Scheme即可靴拱。
  • 凡是需要對通知內(nèi)容做修改的都要加上mutable-content字段垃喊,UNNotificationServiceExtension中需要使用。例如下載通知中傳來的圖片或視頻袜炕,先下載后再通知本谜。
  • 通知的增刪改都是根據(jù)request中的identifier進行查找和區(qū)分的。

通知其實也就這些偎窘,只是改的多乌助,顯得亂而已。理解了通知的流程與原理陌知,處理這一模塊的問題也就能得心應(yīng)手他托。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市纵诞,隨后出現(xiàn)的幾起案子上祈,更是在濱河造成了極大的恐慌,老刑警劉巖浙芙,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件登刺,死亡現(xiàn)場離奇詭異,居然都是意外死亡嗡呼,警方通過查閱死者的電腦和手機纸俭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來南窗,“玉大人揍很,你說我怎么就攤上這事⊥蛏耍” “怎么了窒悔?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長敌买。 經(jīng)常有香客問我简珠,道長,這世上最難降的妖魔是什么虹钮? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任聋庵,我火速辦了婚禮,結(jié)果婚禮上芙粱,老公的妹妹穿的比我還像新娘祭玉。我一直安慰自己,他們只是感情好春畔,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布脱货。 她就那樣靜靜地躺著岛都,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蹭劈。 梳的紋絲不亂的頭發(fā)上疗绣,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天,我揣著相機與錄音铺韧,去河邊找鬼多矮。 笑死,一個胖子當(dāng)著我的面吹牛哈打,可吹牛的內(nèi)容都是我干的塔逃。 我是一名探鬼主播,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼料仗,長吁一口氣:“原來是場噩夢啊……” “哼湾盗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起立轧,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤格粪,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后氛改,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體帐萎,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年胜卤,在試婚紗的時候發(fā)現(xiàn)自己被綠了疆导。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡葛躏,死狀恐怖澈段,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情舰攒,我是刑警寧澤败富,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站摩窃,受9級特大地震影響兽叮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜偶芍,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望德玫。 院中可真熱鬧匪蟀,春花似錦、人聲如沸宰僧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至段化,卻和暖如春嘁捷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背显熏。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工雄嚣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人喘蟆。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓缓升,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蕴轨。 傳聞我的和親對象是個殘疾皇子港谊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一、為什么會有這篇文章橙弱? 推送通知蘋果幾乎每年都改歧寺,但都是縫縫補補的功效,直到iOS10的出現(xiàn)棘脐,可能蘋果覺得之前的...
    糖加一勺丶閱讀 1,363評論 0 14
  • 極光推送: 1.JPush當(dāng)前版本是1.8.2斜筐,其SDK的開發(fā)除了正常的功能完善和擴展外也緊隨蘋果官方的步伐,SD...
    Isspace閱讀 6,719評論 10 16
  • 推送通知 注意:這里說的推送通知跟NSNotification有所區(qū)別 NSNotification是抽象的荆残,不可...
    iOS開發(fā)攻城獅閱讀 4,229評論 1 13
  • 推送通知注意:這里說的推送通知跟NSNotification有所區(qū)別NSNotification是抽象的奴艾,不可見的...
    醉葉惜秋閱讀 1,515評論 0 3
  • 馬云說:“西湖邊上有個乞丐,面前放的不是缽不是碗内斯,而是二維碼蕴潦。”
    一米陽光HUIWEI閱讀 398評論 0 51