編者按:這是極光內(nèi)部員工整理的一篇對 iOS 推送的全面理解的文章,站在初學者的視角來介紹知識點,推薦給大家。
本文旨在對 iOS 推送進行一個完整的剖析,如果你之前對推送一無所知,那么在你認真地閱讀了全文后必將變成一個推送老手,你將會對其中的各種細節(jié)和原理有充分的理解。以下是 pikacode 使用 iOS 推送的一些經(jīng)驗,歡迎互相交流,指出錯漏之處。
推送服務(wù)可以說是所有 App 的標配,不論是哪種類型的 App,推送都從很大程度上決定了 App 的 打開率、使用率、存活率 。因此,熟知并掌握推送原理及方法,對每一個開發(fā)者來說都是必備技能,對每一個依賴 App 的公司來說都至關(guān)重要。
從 iOS 10 新增的 UserNotifications Framework 可以發(fā)現(xiàn),Apple 整合了原有散亂的 API,并且增加了許多強大的功能。以 Apple 官方的角度來看,也必然是相當重視推送服務(wù)對 App 的影響、以及對 Apple iOS 生態(tài)圈長遠發(fā)展的影響。
準備篇
Tip 1:推送通知(Push Notification)必須購買 Apple 開發(fā)者賬號,并使用特定的推送證書
使用免費賬號不能推送。
那如果我們使用的是第三方推送服務(wù)(以下簡稱第三方)呢?比如「極光推送」。也必須購買開發(fā)者賬號。因為所有的第三方都會將推送請求發(fā)至 APNs(Apple Push Notification service 蘋果推送通知服務(wù)),所有推送均是由 APNs 下發(fā)。
如何注冊及正確的配置證書,參考這里 iOS 證書設(shè)置指南。
原理篇
Tip 2:推送通知本身是 iOS 系統(tǒng)的行為,所以在 App 沒有運行(沒有在前臺也沒有在后臺)的時候:
仍然能夠推送及接收(通知中心通知、頂部橫幅、刷新 App 右上角的小圓點即 badge [以下簡稱角標] 等都會由系統(tǒng)來控制和展示)。
收到推送時,是無法在 App 的代碼中獲取到通知內(nèi)容的。因為沙盒機制,此時 App 的任何代碼都不可能被執(zhí)行。
Tip 3:手機向 APNs 注冊推送服務(wù)
1.在代碼中注冊推送服務(wù):
2.在第一次觸發(fā)這段代碼的時候,會有一個系統(tǒng)彈窗,詢問你是否允許該 App 要給你推送信息。當你選擇允許時,系統(tǒng)會打包 App 手機唯一標識 證書 信息發(fā)送至 APNs 服務(wù)器注冊推送服務(wù),APNs 系統(tǒng)會對該手機安裝的該 App 是否有推送權(quán)限進行驗證,所以必須要加入了 Apple Deveice 的手機,使用對應(yīng) App 的推送證書才能夠成功的注冊。
3.如果注冊成功,則可以在 AppDelegate.m 的如下方法中獲取到 deviceToken,它是對 該手機 該 App 組合的一個唯一標識,當使用遠程推送時,只需將推送消息發(fā)給指定的 deviceToken 即可使推送信息傳達給指定手機的指定 App 上。因此如果你使用第三方,就需要在這個方法里將deviceToken 傳給第三方。(在 iOS 9 為了更好的保護用戶隱私,會出現(xiàn)多次重復刪除 / 安裝 App 導致 deviceToken 不斷變化的情況。有時會出現(xiàn)一條推送手機會收到 2 次的問題,屬于 iOS 9 系統(tǒng)問題)。
4.如果以上步驟均成功,此時你能夠取到第三方提供的設(shè)備注冊 id。能否取到該 id 值,可以作為判斷設(shè)備是否能夠成功推送的標準(見 Tip 6 – Registration ID)。因為當你取到該值時必然:
推送證書配置正確(你擁有了推送權(quán)限)。
設(shè)備成功在 APNs 注冊并返回了 deviceToken(APNs 能識別你的設(shè)備了)。
返回 的 deviceToken 傳給第三方,成功在第三方生成了唯一標識注冊 id(第三方能將你的設(shè)備信息傳給 APNs 了)。
5.綜上,注冊及接收推送必須使用真機,必須連網(wǎng)。
Tip 4:推送通知從 服務(wù)端 –> App 代碼 的過程
1.使用你們公司或第三方的服務(wù)端向 APNs 發(fā)送推送請求(請參考蘋果 APNs 相關(guān)資料,或者第三方推送提供了更簡單的 REST API)。
2.APNs 接收并驗證推送請求。
3.APNs 找到設(shè)備下發(fā)推送。
4.手機收到推送通知,系統(tǒng)根據(jù) App 狀態(tài)進行處理:
前臺收到:
系統(tǒng)會將通知內(nèi)容傳到 didReceiveRemoteNotification
后臺收到:
如果開啟了 Remote Notification ,系統(tǒng)將推送傳到didReceiveRemoteNotification:fetchCompletionHandler:(見 Tip 5 – 后臺推送),否則此時代碼中收不到推送。
展示橫幅、通知中心、聲音、角標。
退出收到:
如果點擊推送橫幅 / 通知中心而啟動 App,系統(tǒng)將通知傳到didFinishLaunchingWithOptions。
展示橫幅、通知中心、聲音、角標。
推送通知內(nèi)容篇
Tip 5:推送通知分為 本地 / 遠程 2 種類型:
本地通知,可指定推送時間,在該時間準時彈出推送通知。
遠程推送通知,分為 普通推送 / 后臺推送 / 靜默推送 3 種類型。存在延遲問題(由于 Tip 1 第 2 點,APNs 的不穩(wěn)定及高峰時段的巨量請求所致)。
普通推送
就是我們在手機上平時見到的推送通知。
包含聲音、橫幅、角標、自定義字段。
App :
處于前臺,不會展示橫幅,可通過 didReceiveRemoteNotification(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after)獲取通知內(nèi)容(前臺展示橫幅的方法看這里)。
處于后臺,會展示橫幅,無法獲取通知內(nèi)容。
處于退出,會展示橫幅,無法獲取通知內(nèi)容。
點擊圖標啟動,無法獲取通知內(nèi)容。
點擊通知橫幅啟動,在 didFinishLaunchingWithOptions 獲取通知內(nèi)容。
通知內(nèi)容類似如下:
后臺推送
各種顯示效果跟普通推送完全一樣。
必須攜帶 'content-available' = 1;
必須攜帶 alert、badge、sound 中 至少 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) 獲取通知內(nèi)容。
處于后臺,可通過 didReceiveRemoteNotification:fetchCompletion Handler: 獲取通知內(nèi)容 // 獲取情況中與普通推送的唯一不同點,此時 iOS 系統(tǒng)允許開發(fā)者在 App 處于后臺的情況下,執(zhí)行一些代碼,大概提供幾分鐘的時間,可以用來偷偷的刷新 UI、切換頁面、下載更新包等等操作。
處于退出,無法獲取通知內(nèi)容。
點擊圖標啟動,無法獲取通知內(nèi)容。
點擊推送橫幅啟動,在 didFinishLaunchingWithOptions 獲取通知內(nèi)容。
通知內(nèi)容類似如下:
靜默推送
沒有任何展示效果。
必須攜帶 'content-available' = 1;,因此靜默必然是后臺的。
必須不攜帶 alert、badge、sound。
可攜帶自定義字段。
App :
處于前臺,可通過didReceiveRemoteNotification(iOS 7 before)didReceiveRemoteNotification:fetchCompletionHandler:(iOS 7 after) 獲取通知內(nèi)容。
處于后臺,可通過 didReceiveRemoteNotification:fetchCompletion Handler: 獲取通知內(nèi)容 // 獲取情況中與普通推送的唯一不同點,此時 iOS 系統(tǒng)允許開發(fā)者在 App 處于后臺的情況下,執(zhí)行一些代碼,大概提供幾分鐘的時間,可以用來偷偷的刷新 UI、切換頁面、下載更新包等等操作。
處于退出,無法獲取通知內(nèi)容。
通知內(nèi)容類似如下:
推送目標篇
別名、標簽、Registration ID 均是第三方提供的用于更方便地指定推送目標的功能。
Tip 6:推送根據(jù)目標的不同可分為:
廣播
無差別發(fā)送給所有用戶。
別名 alias 推送
第三方提供的功能
一個手機的一款 App 只能設(shè)置一個 alias(可修改)。
建議對每一個用戶都取不同的別名,以此來確定唯一的用戶(也可多個用戶取 1 個別名)。
推送時可指定多個 alias 來下發(fā)同一內(nèi)容。
僅指定 alias 的用戶能夠收到推送。
標簽 tag 推送
第三方提供的功能。
可設(shè)置多個、可增加、清空。
用于指定多樣的屬性,如 『1000』 『daily』 『discount』 可用于表示月消費超過 1k、喜歡購買日用品、偏好折扣商品的用戶。
如果要刪除,需要在上次設(shè)置時,將設(shè)置的 tags 保存至 NSUserDefaults,本次剔除不需要的 tag 后,再重新設(shè)置。
推送時可指定多個 tag 來下發(fā)同一內(nèi)容。
手機如果設(shè)置了推送指定的多個 tag 中任一個 tag,都能夠收到推送消息。如指定 『1000』 『globe』 『original』 (千元級消費者、全球購、原價),那么設(shè)置了 『100』 『globe』 『discount』(百元級消費者、全球購、折扣價)的用戶可以收到該推送消息。
Registration ID 推送
第三方提供的功能。
在 Tip 3 的第 3 步時將 deviceToken 提供給第三方之后,其服務(wù)器會自動生成的指向該手機的唯一 id。
可在推送時指定多個 id 來下發(fā)消息。
可用于對核心用戶、旗艦用戶的精準推送。
應(yīng)用內(nèi)消息篇
Tip 7:應(yīng)用內(nèi)消息(以下簡稱消息 )和推送通知的區(qū)別,消息:
不需要 Apple 推送證書。
由第三方的服務(wù)器下發(fā),而不是 APNs。
相比通知,更快速,幾乎沒有延遲,可用于 IM 消息的即時送達。
能夠長時間保留離線消息,可獲取所有歷史消息內(nèi)容。
通過長連接技術(shù)下發(fā)消息,因此:
手機必須啟動并與第三方服務(wù)器建立連接。
如果手機啟動立刻切至后臺,很可能連接沒有建立。
手機必須處于前臺才能收到消息。
手機從后臺切回前臺,會自動重新建立連接,并收到離線消息。
沒有任何展示(橫幅、通知中心、角標、聲音),因此可以:
自定義字段實現(xiàn) UI 效果。
完全在靜默情況下處理 App 內(nèi)部邏輯。
使用一些 App Store 審核不會通過的功能,在審核時關(guān)閉功能,上架后通過接收消息,開啟相關(guān)功能。
組合大招篇
Tip 8:tags 的組合技巧
見 Tip 5 – 標簽 tag 推送。
可以在服務(wù)端來統(tǒng)計分析用戶行為,然后將指定的 tags 發(fā)送至手機,手機接收后再為用戶打上對應(yīng)的 tags。
Tip 9:通知 消息的組合技巧
由于各自的特性都存在差異,因此二者結(jié)合使用是使得 App 推送性能最大化的必然選擇:
情景一:
QQ / 微信 聊天。會同時下發(fā)一組通知 消息 ,如果用戶沒有啟動 QQ,雖有延遲但必然能夠先收到通知,在收到通知的提醒之后,用戶打開 App,此時收到了離線消息,即時更新 UI,與好友即時地發(fā)送 / 接收消息。(在收到通知后,斷網(wǎng),然后啟動 App,你會發(fā)現(xiàn)此時手機里并不會顯示剛剛通知的內(nèi)容,因為它是依靠拉取消息來刷新頁面的,而不是不夠穩(wěn)定的通知)。
情景二:(期待您的補充…)