推送-推送原理性說明

前言

我們?cè)趯?shí)現(xiàn)推送功能的時(shí)候,更需要了解下推送的原理機(jī)制,這樣我們?cè)诎l(fā)現(xiàn)問題時(shí)候才好定位到問題的解決辦法。

推送流程和原理

推送
推送

Provider就是我們自己程序的后臺(tái)服務(wù)器(或者是第三方的推送服務(wù)器),APNS是Apple Push Notification Service的縮寫,也就是蘋果的推送服務(wù)器。
上圖可以分為三個(gè)階段:

  • 第一階段:應(yīng)用程序的服務(wù)器端把要發(fā)送的消息、目的iPhone的標(biāo)識(shí)打包,發(fā)給APNS。
  • 第二階段:APNS在自身的已注冊(cè)Push服務(wù)的iPhone列表中,查找有相應(yīng)標(biāo)識(shí)的iPhone,并把消息發(fā)送到iPhone。
  • 第三階段:iPhone把發(fā)來的消息傳遞給相應(yīng)的應(yīng)用程序,并且按照設(shè)定彈出Push通知。

APNS推送通知的詳細(xì)工作流程下面這張圖是說明APNS推送通知的詳細(xì)工作流程:

根據(jù)圖片我們可以概括一下:

  • 應(yīng)用程序注冊(cè)APNS消息推送。
  • iOS從APNS Server獲取devicetoken,應(yīng)用程序接收device token。
  • 應(yīng)用程序?qū)evice token發(fā)送給程序的PUSH服務(wù)端程序。
  • 服務(wù)端程序向APNS服務(wù)發(fā)送消息。
  • APNS服務(wù)將消息發(fā)送給iPhone應(yīng)用程序。

有幾點(diǎn)值得注意

  • 首先要有一臺(tái)蘋果的設(shè)備,模擬器是不支持推送的,

  • APNS
    如果需要給應(yīng)用集成推送功能,就一定要用到蘋果的推送服務(wù)。Apple推送通知服務(wù)(Apple Push Notification service =APNs),例如友盟,極光之類的推送服務(wù)都是向APNs推送消息,APNs再將消息推送給設(shè)備的。

  • 推送消息傳輸路徑:
    Provider-APNs-Client App 我們的設(shè)備聯(lián)網(wǎng)時(shí)(無論是蜂窩聯(lián)網(wǎng)還是Wi-Fi聯(lián)網(wǎng))都會(huì)與蘋果的APNs服務(wù)器建立一個(gè)長連接(persistent IP connection),當(dāng)Provider推送一條通知的時(shí)候,這條通知并不是直接推送給了我們的設(shè)備,而是先推送到蘋果的APNs服務(wù)器上面,而蘋果的APNs服務(wù)器再通過與設(shè)備建立的長連接進(jìn)而把通知推送到我們的設(shè)備上(參考圖1-1,圖1-2)。而當(dāng)設(shè)備處于非聯(lián)網(wǎng)狀態(tài)的時(shí)候,APNs服務(wù)器會(huì)保留Provider所推送的最后一條通知,當(dāng)設(shè)備轉(zhuǎn)換為連網(wǎng)狀態(tài)時(shí),APNs則把其保留的最后一條通知推送給我們的設(shè)備;如果設(shè)備長時(shí)間處于非聯(lián)網(wǎng)狀態(tài)下,那么APNs服務(wù)器為其保存的最后一條通知也會(huì)丟失。Remote Notification必須要求設(shè)備連網(wǎng)狀態(tài)下才能收到,并且太頻繁的接收遠(yuǎn)程推送通知對(duì)設(shè)備的電池壽命是有一定的影響的。

  • deviceToken的生成
    當(dāng)一個(gè)App注冊(cè)接收遠(yuǎn)程通知時(shí),系統(tǒng)會(huì)發(fā)送請(qǐng)求到APNs服務(wù)器,APNs服務(wù)器收到此請(qǐng)求會(huì)根據(jù)請(qǐng)求所帶的key值生成一個(gè)獨(dú)一無二的value值也就是所謂的deviceToken,而后APNs服務(wù)器會(huì)把此deviceToken包裝成一個(gè)NSData對(duì)象發(fā)送到對(duì)應(yīng)請(qǐng)求的App上。然后App把此deviceToken發(fā)送給我們自己的服務(wù)器,就是所謂的Provider。Provider收到deviceToken以后進(jìn)行儲(chǔ)存等相關(guān)處理,以后Provider給我們的設(shè)備推送通知的時(shí)候,必須包含此deviceToken。

  • deviceToken到底是什么?有什么用?為什么是獨(dú)一無二的?

    是什么:deviceToken其實(shí)就是根據(jù)注冊(cè)遠(yuǎn)程通知的時(shí)候向APNs服務(wù)器發(fā)送的Token key,Token key中包含了設(shè)備的UDID和App的Bundle Identifier,然后蘋果APNs服務(wù)器根據(jù)此Token key編碼生成一個(gè)deviceToken。deviceToken可以簡單理解為就是包含了設(shè)備信息和應(yīng)用信息的一串編碼。

    有什么用:上面提到Provider推送消息的時(shí)候必須帶有此deviceToken,然后此消息就根據(jù)deviceToken(UDID + App's Bundle Identifier)找到對(duì)應(yīng)的設(shè)備以及該設(shè)備上對(duì)應(yīng)的應(yīng)用,從而把此推送消息推送給此應(yīng)用。

    唯一性:蘋果APNs的編碼技術(shù)和deviceToken的獨(dú)特作用保證了他的唯一性。唯一性并不是說一臺(tái)設(shè)備上的一個(gè)應(yīng)用程序永遠(yuǎn)只有一個(gè)deviceToken,當(dāng)用戶升級(jí)系統(tǒng)的時(shí)候deviceToken是會(huì)變化的。

  • 后臺(tái)推送也是很必須的,不是所謂的多做活動(dòng),因?yàn)橛行┩扑褪菞l件觸發(fā)的,無法做到人為推送(比如大量用戶中,接單后通知發(fā)單的人)。

  • 推送通知本身是 iOS 系統(tǒng)的行為,所以在 App 沒有運(yùn)行(沒有在前臺(tái)也沒有在后臺(tái))的時(shí)候:仍然能夠推送及接收(通知中心通知、頂部橫幅、刷新 App 右上角的小圓點(diǎn)即 badge [以下簡稱角標(biāo)] 等都會(huì)由系統(tǒng)來控制和展示)。但是收到推送時(shí),是無法在 App 的代碼中獲取到通知內(nèi)容的。因?yàn)樯澈袡C(jī)制,此時(shí) App 的任何代碼都不可能被執(zhí)行。

開發(fā)中實(shí)現(xiàn)推送的步驟

  • 在代碼中注冊(cè)推送服務(wù);

  • 在第一次觸發(fā)這段代碼的時(shí)候,會(huì)有一個(gè)系統(tǒng)彈窗,詢問你是否允許該 App 要給你推送信息。當(dāng)你選擇允許時(shí),系統(tǒng)會(huì)打包 App+手機(jī)唯一標(biāo)識(shí)+證書 信息發(fā)送至 APNs 服務(wù)器注冊(cè)推送服務(wù),APNs 系統(tǒng)會(huì)對(duì)該手機(jī)安裝的該 App 是否有推送權(quán)限進(jìn)行驗(yàn)證,所以必須要加入了 Apple Deveice 的手機(jī),使用對(duì)應(yīng) App 的推送證書才能夠成功的注冊(cè)。

  • 如果注冊(cè)成功,則可以在 AppDelegate.m 的如下方法中獲取到 deviceToken,它是對(duì) 該手機(jī)+該App 組合的一個(gè)唯一標(biāo)識(shí),當(dāng)使用遠(yuǎn)程推送時(shí),只需將推送消息發(fā)給指定的 deviceToken 即可使推送信息傳達(dá)給指定手機(jī)的指定 App 上。因此如果你使用第三方,就需要在這個(gè)方法里將 deviceToken 傳給第三方。(在 iOS 9 為了更好的保護(hù)用戶隱私,會(huì)出現(xiàn)多次重復(fù)刪除/安裝 App 導(dǎo)致 deviceToken 不斷變化的情況。有時(shí)會(huì)出現(xiàn)一條推送手機(jī)會(huì)收到 2 次的問題,屬于 iOS 9 系統(tǒng)問題)。

     -(void)application:(UIApplication *)application   didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {  
       [JPUSHService registerDeviceToken:deviceToken];//將 deviceToken 傳給極光推送
     }
    
  • 綜上,注冊(cè)及接收推送 必須 使用真機(jī),必須連網(wǎng)。

推送從 服務(wù)端 --> App 代碼 的過程

  • 使用你們公司或第三方的服務(wù)端向 APNs 發(fā)送推送請(qǐng)求(包含 推送內(nèi)容+App描述+手機(jī)描述 )
  • APNs 接收并驗(yàn)證推送請(qǐng)求
  • APNs 利用網(wǎng)絡(luò)搜索并定位指定設(shè)備,下發(fā)推送
  • 手機(jī)收到推送,系統(tǒng)根據(jù) App 狀態(tài)進(jìn)行處理
    前臺(tái)收到:
    后臺(tái)收到:
    退出收到:

推送分幾種分類

  • 普通式推送

    就是我們?cè)谑謾C(jī)上平時(shí)見到的推送
    包含聲音、彈窗、角標(biāo)、自定義字段

      App      
          處于前臺(tái):不會(huì)彈窗,可通過 didReceiveRemoteNotification 獲取推送內(nèi)容([前臺(tái)彈窗的方法看這里](https://github.com/pikacode/EBForeNotification))
          處于后臺(tái):會(huì)彈窗 ,無法獲取推送內(nèi)容
          處于退出: 會(huì)彈窗,無法獲取推送內(nèi)容,點(diǎn)擊圖標(biāo)啟動(dòng),無法獲取推送內(nèi)容
          點(diǎn)擊推送彈窗啟動(dòng),在 didFinishLaunchingWithOptions獲取推送內(nèi)容
    
      推送內(nèi)容類似如下:
    
      {
          "_j_msgid" = 200806057;//第三方附帶的 id,用于在后臺(tái)查詢送達(dá)情況  
          aps =     {
              alert = "顯示內(nèi)容";
            badge = 1;//App 角標(biāo),可推送 n、+n、-n 來實(shí)現(xiàn)角標(biāo)的固定、增加、減少
            sound = default;//推送聲音,默認(rèn)系統(tǒng)三全音,如需使用自己的聲音,需要將聲音文件拖拽&拷貝至 Xcode 工程目錄任意位置,并在推送時(shí)指定其文件名
          };
          key1 = value1;//自定義字段,可設(shè)置多組,用于處理內(nèi)部邏輯 
          key2 = value2;
      }
    
  • 后臺(tái)式推送

    各種顯示效果跟普通推送完全一樣。
    必須攜帶alert、badge、sound中至少 1 個(gè)字段。
    僅 iOS 7 以后支持。
    必須在 Xcode 工程中 TARGETS - Capabilities - Background Modes - Remote notifications 開啟該功能.

     App:
          處于前臺(tái):可通過didReceiveRemoteNotification(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after) 獲取通知內(nèi)容。
          處于后臺(tái):可通過didReceiveRemoteNotification:fetchCompletionHandler:獲取通知內(nèi)容 // 獲取情況中與普通推送的唯一不同點(diǎn),此時(shí) iOS 系統(tǒng)允許開發(fā)者在 App 處于后臺(tái)的情況下,執(zhí)行一些代碼,大概提供幾分鐘的時(shí)間,可以用來偷偷的刷新 UI、切換頁面、下載更新包等等操作。
          處于退出:無法獲取通知內(nèi)容。
        點(diǎn)擊圖標(biāo)啟動(dòng),無法獲取通知內(nèi)容。
        點(diǎn)擊推送橫幅啟動(dòng),在didFinishLaunchingWithOptions獲取通知內(nèi)容。
    
      通知內(nèi)容類似如下:
      { 
            "_j_msgid" = 2090737306;
           aps = {
                alert = "顯示內(nèi)容"; 
               badge = 1; 
            }; 
         key1 = value1;
      }
    
  • 靜默式推送

    沒有任何展示效果。
    必須攜帶 "content-available" = 1;,因此靜默必然是后臺(tái)的。
    必須不攜帶 alert、badge、sound。
    可攜帶自定義字段。

    App :
      處于前臺(tái):可通過didReceiveRemoteNotification(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after) 獲取通知內(nèi)容。
      處于后臺(tái):可通過 didReceiveRemoteNotification:fetchCompletionHandler: 獲取通知內(nèi)容 //獲取情況中與普通推送的唯一不同點(diǎn),此時(shí) iOS 系統(tǒng)允許開發(fā)者在 App 處于后臺(tái)的情況下,執(zhí)行一些代碼,大概提供幾分鐘的時(shí)間,可以用來偷偷的刷新 UI、切換頁面、下載更新包等等操作。
      處于退出,無法獲取通知內(nèi)容。
      通知內(nèi)容類似如下:
    {
         "_j_msgid" = 3938587719;
         aps =     {
             alert = "";
            "content-available" = 1;  // 必帶字段
         };
         key1 = value1;
      }
    

小結(jié)

推送的大致原理我們說了一下,其他相關(guān)知識(shí)可以查看我的其他相關(guān)知識(shí)。

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

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容