iOS 推送全解析,你不可不知的全部 Tips!

本文旨在對 iOS 推送進行一個完整的剖析,若是你以前對推送一無所知,那麼在你認真地閱讀了全文後必將變成一個推送老手,你將會對其中的各類細節和原理有充分的理解。如下是 pikacode 使用 iOS 推送的一些經驗,歡迎互相交流,指出錯漏之處。ios

推送服務能夠說是全部 App 的標配,不管是哪一種類型的 App,推送都從很大程度上決定了 App 的 打開率、使用率、存活率 。所以,熟知並掌握推送原理及方法,對每個開發者來講都是必備技能,對每個依賴 App 的公司來講都相當重要。git

從 iOS 10 新增的 UserNotifications Framework 能夠發現,Apple 整合了原有散亂的 API,而且增長了許多強大的功能。以 Apple 官方的角度來看,也必然是至關重視推送服務對 App 的影響、以及對 Apple iOS 生態圈長遠發展的影響。github

準備篇


Tip 1:推送通知(Push Notification)必須購買 Apple 開發者帳號,並使用特定的推送證書

  • 使用免費賬號不能推送。
  • 那若是咱們使用的是第三方推送服務(如下簡稱第三方)呢?好比「極光推送」。也必須購買開發者賬號。由於全部的第三方都會將推送請求發至 APNs(Apple Push Notification service 蘋果推送通知服務),全部推送均是由 APNs 下發。
  • 如何註冊及正確的配置證書,參考這裏 iOS 證書設置指南

原理篇


Tip 2:推送通知自己是 iOS 系統的行爲,因此在 App 沒有運行(沒有在前臺也沒有在後臺)的時候:

  • 仍然可以推送及接收(通知中心通知、頂部橫幅、刷新 App 右上角的小圓點即 badge [如下簡稱角標] 等都會由系統來控制和展現)。
  • 收到推送時,是沒法在 App 的代碼中獲取到通知內容的。由於沙盒機制,此時 App 的任何代碼都不可能被執行。

Tip 3:手機向 APNs 註冊推送服務

  1. 在代碼中註冊推送服務:json

    #ifdef __IPHONE_8_0
     if ([[UIApplication sharedApplication] respondsToSelector:@selector(registerUserNotificationSettings:)]) {
         UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge| UIUserNotificationTypeSound|UIUserNotificationTypeAlert categories:nil];
         [[UIApplication sharedApplication] registerUserNotificationSettings:settings];
     } else {
         UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
         [[UIApplication sharedApplication] registerForRemoteNotificationTypes:myTypes];
    }
     #else
         UIRemoteNotificationType myTypes = UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeSound;
         [[UIApplication sharedApplication] registerForRemoteNotificationTypes:myTypes];
     #endif複製代碼
  2. 在第一次觸發這段代碼的時候,會有一個系統彈窗,詢問你是否容許該 App 要給你推送信息。當你選擇容許時,系統會打包 App+手機惟一標識+證書 信息發送至 APNs 服務器註冊推送服務,APNs 系統會對該手機安裝的該 App 是否有推送權限進行驗證,因此必需要加入了 Apple Deveice 的手機,使用對應 App 的推送證書纔可以成功的註冊。
  3. 若是註冊成功,則能夠在 AppDelegate.m 的以下方法中獲取到 deviceToken,它是對 該手機+該App 組合的一個惟一標識,當使用遠程推送時,只需將推送消息發給指定的 deviceToken 便可使推送信息傳達給指定手機的指定 App 上。所以若是你使用第三方,就須要在這個方法裏將 deviceToken 傳給第三方。(在 iOS 9 爲了更好的保護用戶隱私,會出現屢次重複刪除/安裝 App 致使 deviceToken 不斷變化的狀況。有時會出現一條推送手機會收到 2 次的問題,屬於 iOS 9 系統問題)。服務器

    -(void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {  
         [JPUSHService registerDeviceToken:deviceToken];//將 deviceToken 傳給極光推送
     }複製代碼
  4. 若是以上步驟均成功,此時你可以取到第三方提供的設備註冊 id。可否取到該 id 值,能夠做爲判斷設備是否可以成功推送的標準(見 Tip 6 - Registration ID)。由於當你取到該值時必然:微信

    • 推送證書配置正確(你擁有了推送權限)。
    • 設備成功在 APNs 註冊並返回了 deviceToken(APNs 能識別你的設備了)。
    • 返回 的 deviceToken 傳給第三方,成功在第三方生成了惟一標識註冊 id(第三方能將你的設備信息傳給 APNs 了)。
  5. 綜上,註冊及接收推送必須使用真機,必須連網。

Tip 4:推送通知從 服務端 --> App 代碼 的過程

  1. 使用大家公司或第三方的服務端向 APNs 發送推送請求(請參考蘋果 APNs 相關資料,或者第三方推送提供了更簡單的 REST API)。
  2. APNs 接收並驗證推送請求。
  3. APNs 找到設備下發推送。
  4. 手機收到推送通知,系統根據 App 狀態進行處理:
    • 前臺收到:
      • 系統會將通知內容傳到 didReceiveRemoteNotification
    • 後臺收到:
      • 若是開啓了 Remote Notification ,系統將推送傳到 didReceiveRemoteNotification:fetchCompletionHandler:(見 Tip 5 - 後臺推送),不然此時代碼中收不到推送。
      • 展現橫幅、通知中心、聲音、角標。
    • 退出收到:
      • 若是點擊推送橫幅/通知中心而啓動 App,系統將通知傳到 didFinishLaunchingWithOptions
      • 展現橫幅、通知中心、聲音、角標。

推送通知內容篇


Tip 5:推送通知分爲 本地/遠程 2 種類型:

  • 本地通知,可指定推送時間,在該時間準時彈出推送通知。
  • 遠程推送通知,分爲 普通推送/後臺推送/靜默推送 3 種類型。存在延遲問題(因爲 Tip 1 第 2 點,APNs 的不穩定及高峯時段的巨量請求所致)。app

    • 普通推送性能

      • 就是咱們在手機上平時見到的推送通知。
      • 包含聲音、橫幅、角標、自定義字段。
      • App :
        • 處於前臺,不會展現橫幅,可經過 didReceiveRemoteNotification(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after)獲取通知內容(前臺展現橫幅的方法看這裏)。
        • 處於後臺,會展現橫幅,沒法獲取通知內容。
        • 處於退出,會展現橫幅,沒法獲取通知內容。
        • 點擊圖標啓動,沒法獲取通知內容。
        • 點擊通知橫幅啓動,在 didFinishLaunchingWithOptions 獲取通知內容。
      • 通知內容相似以下:fetch

        {
          "_j_msgid" = 200806057;  // 第三方附帶的 id,用於統計點擊
          aps =     {
            alert = "顯示內容";
            badge = 1;  // App 角標,可推送 n、+n、-n 來實現角標的固定、增長、減小
            sound = default;  // 推送聲音,默認系統三全音,如需使用本身的聲音,須要將聲音文件拖拽&拷貝至 Xcode 工程目錄任意位置,並在推送時指定其文件名
          };
          key1 = value1;  // 自定義字段,可設置多組,用於處理內部邏輯
          key2 = value2;
        }複製代碼
    • 後臺推送ui

      • 各類顯示效果跟普通推送徹底同樣。
      • 必須攜帶 "content-available" = 1;
      • 必須攜帶 alertbadgesound至少 1 個字段
      • 僅 iOS 7 之後支持。
      • 必須在 Xcode 工程中 TARGETS - Capabilities - Background Modes - Remote notifications 開啓該功能,具體可參照 iOS 7 Background Remote Notification
      • App:
        • 處於前臺,可經過didReceiveRemoteNotification(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after) 獲取通知內容。
        • 處於後臺,可經過 didReceiveRemoteNotification:fetchCompletion Handler: 獲取通知內容 // 獲取狀況中與普通推送的惟一不一樣點,此時 iOS 系統容許開發者在 App 處於後臺的狀況下,執行一些代碼,大概提供幾分鐘的時間,能夠用來偷偷的刷新 UI、切換頁面、下載更新包等等操做。
        • 處於退出,沒法獲取通知內容。
        • 點擊圖標啓動,沒法獲取通知內容。
        • 點擊推送橫幅啓動,在 didFinishLaunchingWithOptions 獲取通知內容。
      • 通知內容相似以下:

        {
          "_j_msgid" = 2090737306;
          aps =     {
            alert = "顯示內容";
            badge = 1;
            "content-available" = 1;  // 必帶字段
            sound = default;
          };
          key1 = value1;
        }複製代碼

    • 靜默推送

      • 沒有任何展現效果。
      • 必須攜帶 "content-available" = 1;,所以靜默必然是後臺的。
      • 必須不攜帶 alertbadgesound
      • 可攜帶自定義字段。
      • App :
        • 處於前臺,可經過didReceiveRemoteNotification(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after) 獲取通知內容。
        • 處於後臺,可經過 didReceiveRemoteNotification:fetchCompletion Handler: 獲取通知內容 //獲取狀況中與普通推送的惟一不一樣點,此時 iOS 系統容許開發者在 App 處於後臺的狀況下,執行一些代碼,大概提供幾分鐘的時間,能夠用來偷偷的刷新 UI、切換頁面、下載更新包等等操做。
        • 處於退出,沒法獲取通知內容。
      • 通知內容相似以下:
      {
          "_j_msgid" = 3938587719;
          aps =     {
          alert = "";
          "content-available" = 1;  // 必帶字段
          };
          key1 = value1;
      }複製代碼

推送目標篇


別名、標籤、Registration ID 均是第三方提供的用於更方便地指定推送目標的功能。

Tip 6:推送根據目標的不一樣可分爲:

  • 廣播
    • 無差異發送給全部用戶。
  • 別名 alias 推送
    • 第三方提供的功能
    • 一個手機的一款 App 只能設置一個 alias(可修改)。
    • 建議對每個用戶都取不一樣的別名,以此來肯定惟一的用戶(也可多個用戶取 1 個別名)。
    • 推送時可指定多個 alias 來下發同一內容。
    • 僅指定 alias 的用戶可以收到推送。
  • 標籤 tag 推送
    • 第三方提供的功能。
    • 可設置多個、可增長、清空。
    • 用於指定多樣的屬性,如 『1000』+『daily』+『discount』 可用於表示月消費超過 1k、喜歡購買日用品、偏好折扣商品的用戶。
    • 若是要刪除,須要在上次設置時,將設置的 tags 保存至 NSUserDefaults,本次剔除不須要的 tag 後,再從新設置。
    • 推送時可指定多個 tag 來下發同一內容。
    • 手機若是設置了推送指定的多個 tag 中任一個tag,都可以收到推送消息。如指定 『1000』+『globe』+『original』 (千元級消費者、全球購、原價),那麼設置了 『100』+『globe』+『discount』(百元級消費者、全球購、折扣價)的用戶能夠收到該推送消息。
  • Registration ID 推送
    • 第三方提供的功能。
    • 在 Tip 3 的第 3 步時將 deviceToken 提供給第三方以後,其服務器會自動生成的指向該手機的惟一 id。
    • 可在推送時指定多個 id 來下發消息。
    • 可用於對核心用戶、旗艦用戶的精準推送。

應用內消息篇


Tip 7:應用內消息(如下簡稱消息 )和推送通知的區別,消息:

  • 不須要 Apple 推送證書。
  • 由第三方的服務器下發,而不是 APNs。
  • 相比通知,更快速,幾乎沒有延遲,可用於 IM 消息的即時送達。
  • 可以長時間保留離線消息,可獲取全部歷史消息內容。
  • 經過長鏈接技術下發消息,所以:
    • 手機必須啓動並與第三方服務器創建鏈接。
    • 若是手機啓動馬上切至後臺,極可能鏈接沒有創建。
    • 手機必須處於前臺才能收到消息。
    • 手機從後臺切回前臺,會自動從新創建鏈接,並收到離線消息。
  • 沒有任何展現(橫幅、通知中心、角標、聲音),所以能夠:
    • 自定義字段實現 UI 效果。
    • 徹底在靜默狀況下處理 App 內部邏輯。
    • 使用一些 App Store 審覈不會經過的功能,在審覈時關閉功能,上架後經過接收消息,開啓相關功能。

組合大招篇


Tip 8:tags 的組合技巧

  • 見 Tip 5 - 標籤 tag 推送。
  • 能夠在服務端來統計分析用戶行爲,而後將指定的 tags 發送至手機,手機接收後再爲用戶打上對應的 tags。

Tip 9:通知+消息的組合技巧

  • 首先來看通知和消息特性的對比:
通知 消息
送達時間 可能存在幾秒延遲 幾乎無延遲
獲取時機 處於前臺或後臺能獲取內容 僅處於前臺能獲取內容
離線內容 保留『一段時間』,過時會拋棄,沒法查詢歷史內容 始終保留,可查詢所有歷史內容
系統展現 會展現(靜默推送或App處於前臺不展現) 不展現
  • 因爲各自的特性都存在差別,所以兩者結合使用是使得 App 推送性能最大化的必然選擇:
    • 情景一:
      QQ/微信 聊天。會同時下發一組通知+消息 ,若是用戶沒有啓動 QQ,雖有延遲但必然可以先收到通知,在收到通知的提醒以後,用戶打開 App,此時收到了離線消息,即時更新 UI,與好友即時地發送/接收消息。(在收到通知後,斷網,而後啓動 App,你會發現此時手機裏並不會顯示剛剛通知的內容,由於它是依靠拉取消息來刷新頁面的,而不是不夠穩定的通知)。
    • 情景二:(期待您的補充...)
相關文章
相關標籤/搜索