“靜默”
靜默推送(Silent Push)并不是必須要“靜默”精肃,只要推送payload中aps
字典里包含了"content-available": 1
的鍵值對,都具有靜默推送的特性(比如喚醒應用),而無論你是否推了alert
, badge
或sound
蠢甲。
例如你推了一條形如以下的推送
{
"aps": {
"content-available": 1,
"alert": "Test",
"badge": 1,
"sound": "default",
}
// 以下是自定義鍵值對
}
用戶可以看到這條推送通知的到來呻澜,而且這條推送依然具有靜默推送的特性。
但我不建議這樣做涂臣,畢竟和蘋果設計這個功能的初衷不符盾计。
registerForRemoteNotifications方法調用時機
對于任何遠程推送(已經不單指靜默推送了),registerForRemoteNotifications
可以直接調用來注冊遠程推送赁遗,而不需要用戶允許署辉。也就是說只要調用-[UIApplication registerForRemoteNotifications]
,就可以在AppDelegate
的application:didRegisterForRemoteNotificationsWithDeviceToken:
中獲取到設備的push token岩四。
那么通常的彈窗詢問權限有什么用呢哭尝?其實只是請求用戶允許在推送通知到來時能夠有alert
, badge
和sound
,而并不是在請求注冊推送本身的權限剖煌。
靜默推送就更厲害了材鹦,即使用戶不允許應用的推送逝淹,靜默推送依然會送達用戶設備,只是不會有alert
, badge
和sound
桶唐。這也符合靜默推送的正常使用場景创橄。
啟動應用到后臺(推送喚醒)
在大多數情況下,啟動一個app后都是進入前臺莽红,比如我們點擊應用圖標或點推送通知來啟動應用妥畏。其實app在某些后臺事件和特定條件下是可以直接啟動到后臺(launch into the background)的。
首先我們需要明確兩點關于應用狀態(tài)和生命周期的知識:
1. 應用狀態(tài)之一Suspended
這種狀態(tài)其實和Background
類似安吁,而且從用戶角度講應用現在看起來確實是在“后臺”醉蚁,但它和Background
狀態(tài)不同的是Suspended
下已經不能執(zhí)行代碼了。
應用何時會進Suspended就是玄學了鬼店,這是由iOS系統(tǒng)自動控制的网棍,而且不會有任何回調,可以看到UIApplicationDelegate
里并沒有像applicationWillBecomeSuspended:這種東西妇智。
這種狀態(tài)下的應用雖然還在內存中滥玷,但是一旦設備內存吃盡,比如開了爐石傳說的游戲巍棱,那么系統(tǒng)就會優(yōu)先干掉(文檔上用的是purge這個詞)處于Suspended
狀態(tài)的應用惑畴,而且也不會有回調。
2. 應用啟動到前臺的生命周期(以點擊應用圖標開始)
重點記住右側在
AppDelegate
中走的回調方法航徙,依次是
application:willFinishLaunchingWithOptions:
application:didFinishLaunchingWithOptions:
applicationDidBecomeActive:
靜默推送可以使應用啟動到后臺
前提是應用先被退到后臺如贷,過一段時間被系統(tǒng)移入Suspended
狀態(tài),然后又被系統(tǒng)在內存吃緊時回收了內存(相當于應用已經被系統(tǒng)正當殺掉到踏,而非用戶雙擊Home鍵殺掉)杠袱,在這以后,該應用收到靜默推送即會啟動應用到后臺窝稿。
這種情況下啟動應用的生命周期如圖
可以看到此時在
AppDelegate
中走的回調方法已經變?yōu)?p>
application:willFinishLaunchingWithOptions:
application:didFinishLaunchingWithOptions:
applicationDidEnterBackground:
值得一提的是這個過程中楣富,系統(tǒng)不會顯示應用的window,就是說我們不會看到手機屏幕上突然鬼畜一下應用啟動伴榔,但是應用的第一屏會被加載和渲染纹蝴,比如你的window.rootViewController
是一個TabBarController,那么它及其默認選中的selectedViewController
都會被加載和渲染潮梯。這是因為系統(tǒng)認為在后臺執(zhí)行完任務后可能會有UI上的更新骗灶,所以在applicationDidEnterBackground:
方法執(zhí)行結束后便會有個快速的截圖,來更新用戶雙擊Home時看到的那個應用截圖秉馏。
application:didReceiveRemoteNotification:fetchCompletionHandler:方法內應該何時調completionHandler(...)
這是應用收到靜默推送的回調方法,我們最多有30s的時間來處理數據脱羡,比如靜默推送表示某個列表或資源有更新萝究,你可以在此處下載數據免都,在下載處理完數據后需要盡快調用completionHandler(...)
告訴系統(tǒng)處理完畢。
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
[Downloader fetchData:^(id x){
// 處理數據帆竹,更新UI 等
completionHandler(UIBackgroundFetchResultNewData);
}];
}
如果這次是啟動到后臺的情況绕娘,調用completionHandler(...)
后會使應用馬上進入之前的狀態(tài)。那就有可能遇到這樣的問題:很多時候我們需要在啟動時發(fā)送一堆業(yè)務上的API請求栽连,如果這次靜默推送沒有數據需要下載和處理险领,就會剛把啟動處的API請求發(fā)出,就調用了completionHandler(...)
秒紧,導致發(fā)出的這些請求在下次打開應用時顯示超時绢陌。這種情況下我們可以強行延時下completionHandler(...)
的調用,來保證能在這次收到那些API的返回熔恢。
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
completionHandler(UIBackgroundFetchResultNoData);
});
注:本文僅陳述靜默推送相關的一些事實和特殊情況的處理辦法脐湾,請在開發(fā)中遵照蘋果對于該功能的設計思想和最佳實踐。