[iOS] 關於 App States & Multitasking 與 Push Notification 機制心得

最近主管問起 iOS 的多工機制和 Push Notification 的機制,在回答之餘,趁機整理一份到自己的網誌,備份一下以備不時之需。

Q:關於 iOS 的 App States有哪些? 
A:

APP States 變化關係圖


iOS 在 iOS4 支援多工後,APP 的生命週期主要分為 Foreground(前景)、Background(背景)、Suspended(暫停) 三種狀態。 一般的APP在離開 Foreground 時會被推到 Background,會有一段 X時間(大約是數秒)是可以在背景執行一些 code,然後 OS 就會再把 APP 推到 Suspended。

那段X時間是非常短暫的,只能讓你做些必要事件處置(Finite-Length Task),例如儲存 user data 或 APP 的 state information 等等。

APP 從 foreground 移動到 background 的流程圖


Q:關於可長時間 Background 下可執行的 Task 有哪些? 
A:

承上題可知, APP 在 Background 下的時間是非常短的,只能迅速執行一些必要的 APP 狀態資料儲存(以便將來回到 Foreground 可以回復到先前狀態),但有某些 OS 特別允許的 Task 是例外,這些 Tasks 是可以長時間佔用CPU運算資源而一直處於 Background 狀態下的唷!

iOS 可「長時間」在 Background 下可執行的 Task,我記得主要有以下三種:

1. audio (例如音樂播放器,再按 Home 鍵回主畫面後音樂可持續播放)
2. location (例如導航軟體或行程軌跡記錄軟體)
3. voip (例如 Skype、Viber等 VOIP 軟體)

但後來看了一下官方文件,他後來又新增了以下幾種: 

4. newsstand-content (官方雜誌架APP的內容背景下載)
5. external-accessory (連接外部裝置保持持續作用,例如跑步時外接心跳頻率機)
6. bluetooth-central (保持藍牙裝置連接性)
7. bluetooth-peripheral (保持藍牙周邊裝置連接性)

無論如何,「只有」以上的 tasks 才被允許長時間在 Background 執行 (其餘的都不被允許!)且需要先被註冊,其方法是: 在APP內的 Info.plist 新增一個 UIBackgroundModes 的 Key,然後 Value 以 Array 形式填以上有用到的 task string (例如audio)。


Q:收到來自 APNS 的 Push Notification後APP可如何處理? 
A:

將 APP 開啟至前景後,該 APP 始有權限處理 Push 內容。細節來說,當收到 Push 時只可能有兩種可能:
Case 1 : APP尚未被執行過
Case 2 : APP執行過 (無論正在 Foreground 執行或在 Suspended 狀態)

Case 1 :
點擊通知訊息開啟APP後會呼叫「application:didFinishLaunchingWithOptions」這個method
- (BOOL)application:(UIApplication *)app didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;

然而 Push Notification 的 Payload 就存在 launchOptions 裡頭,可在此 method 去做你想要的處理
他是個 NSDictionary,可用 UIApplicationLaunchOptionsRemoteNotificationKey 這個 key 去取值…
譬如:
NSDictionary* userInfo = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];


Case 2 :
點擊通知訊息開啟 APP 後會呼叫「 application:didReceiveRemoteNotification」這個method

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo;

Push Notification 的 Payload 存在 userInfo 裡頭,可在此 method 去做你想要的處理
也可以根據 APP 的現在狀態(是在前景或背景)分別去做不同的處理
譬如:

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo
{
    if ( application.applicationState == UIApplicationStateActive )
        // app was already in the foreground
    else
        // app was just brought from background to foreground
    ...
}


以上這只是我個人的理解,如果路過的網友發現我有說錯的地方,也歡迎留言指正,謝謝!^__^


參考官方文件來源:
  1. App States and Multitasking
  2. Scheduling, Registering, and Handling Notifications


留言

這個網誌中的熱門文章

[交車篇] 交車驗車注意事項大全

有關C語言的static用法

[購車篇] 新車購買要訣與菜單分享文