一:后臺推送通知功能介紹
后臺推送是iOS7新增的功能,通過后臺推送可以把客戶端App喚醒,喚醒之后App將獲得30秒的后臺運行時間。注意這里寫的是后臺時間運行時間,有些方法不支持background mode 運行。
被kill掉的App,在發起靜默后是不能被喚醒的。
Tips
application:didReceiveRemoteNotification:fetchCompletionHandler:
Use this method to process incoming remote notifications for your app. Unlike the application:didReceiveRemoteNotification: method, which is called only when your app is running in the foreground, the system calls this method when your app is running in the foreground or background. In addition, if you enabled the remote notifications background mode, the system launches your app (or wakes it from the suspended state) and puts it in the background state when a remote notification arrives. However, the system does not automatically launch your app if the user has force-quit it. In that situation, the user must relaunch your app or restart the device before the system attempts to launch your app automatically again.
不能通過不斷發送后臺推送保持App長時間處于后臺時間,每小時能推送的Silent Notification次數有限制;
Tips
Background update notifications are not meant as a way to keep your app awake in the background beyond quick refresh operations, nor are they meant for high priority updates. APNs treats background update notifications as low priority and may throttle their delivery altogether if the total number becomes excessive. The actual limits are dynamic and can change based on conditions, but try not to send more than a few notifications per hour.
二:設置后臺推送
為了能讓App支持后臺推送,必須確保apns推送內容的aps字典中包含content-available字段且它的值為1。同時如果該推送有通知用戶信息,那么推送內容中也可以添加alert,sound或者badge。反之如果是靜默推送更新內容,那么可以不添加這幾個字段。
推送內容的aps字典中添加content-available后,還需要在項目工程中background modes 中設置?Remote notifications。如下圖:
設置了content-available?以及Remote notifications?之后,那么在Appdelegate的application:didReceiveRemoteNotification:fetchCompletionHandler:?收到后臺推送通知。
三:使用后臺推送的業務 – 日志上報
產品中有使用后臺推送的業務-日志上報。假設用戶使用App過程中出現了異常,而開發不能重現,或者產品運營中出現異常,需要撈用戶日志進行分析定位,需要獲取用戶App日志進行分析定位。
這種情況下可以給指定用戶下發后臺推送讓后臺運行的App或者休眠中的App上報日志動作,從而無需用戶操作配合或者不打擾用戶的情況下進行上報日志。
以上的業務場景,歸納起來就是后臺網絡上報操作,那么涉及的主要類就是?NSURLSession,NSURLSessionDataTask,?NSURLSessionUploadTask。
在Session 中的Task行為取決于三件事情:Session類型,Task類型,以及 Task的創建是否在App處于前端發生。
Session的類型
defaultSessionConfiguration?默認的會話行為類似于其他基礎網絡請求方法。他會通過磁盤對數據和憑證進行存儲。
ephemeralSessionConfiguration 該會話不會存在任何數據到磁盤;所有緩存,憑證等等都是在RAM中進行存貯。因為當session無效的時候,數據也被清除。
backgroundSessionConfigurationWithIdentifier: 類似?defaultSessionConfiguration,但是它是在另外獨立的進程處理網絡數據傳輸。而且它有一些注意事項。
Task的類型
NSURLSessionDataTask
NSURLSessionUploadTask? ?支持后臺上傳數據
NSURLSessionDownloadTask???支持后臺下載數據
后臺傳輸注意事項
當使用backgroundSessionConfiguration:初始化configuration對象并且把分配給Session會話后,那么該Session會話就支持后臺傳輸數據。
后臺Session會話,因為實際的傳輸是由一個單獨的進程,它與你的App交互相對比較昂貴,因此一些功能不可用,導致以下限制:
1:Session 會話必須是通過delegate 進行回調處理,不能使用block。(使用delegate處理與同一個進程使用方法一致)
2:僅支持http 以及 https協議
3:僅支持從file使用upload task (使用data 對象 或者 stream的方式上傳數據會失敗)
4:當在后臺傳輸數據的時候,分配給Session的configuration對象的discretionary屬性必須是true。(允許后臺任務調度系統的自由裁量權的最佳性能)
后臺任務完成操作
在切到后臺之后,Session的Delegate不會再收到,Task相關的消息,直到所有Task全都完成后,系統會調用ApplicationDelegate的application:handleEventsForBackgroundURLSession:completionHandler:回調,把通知App后臺Task已經完成,這里你需要completionHandler的bloack存起來下面會用到,接著每一個后臺的Task就會調用Session的Delegate中的URLSession:downloadTask:didFinishDownloadingToURL:和URLSession:task:didCompleteWithError: 。
各個Task在Session的delegate調用之后,最后會調用Session的Delegate回調URLSessionDidFinishEventsForBackgroundURLSession:。這個時候你可以調用上面保存completionHandler的bloack,告知系統你的后臺任務已經完成,系統可以安全的休眠你的App。
四:實施過程問題
以下是開發過程總結的問題
1:如果不是background創建的task,如果app處于后臺中接受到后臺推送,那么該任務將不能保證被完成的執行。
(測試過程中,經常是發送第一次推送,通過抓包看到http被發送成功,但response沒能回到回調中。需要發送第二次推送或者把app切換到前臺,那么response才能執行delegate回調)
2:處理 Session 以及 Task 不能使用block
3:使用NSURLSessionUploadTask 上傳數據的時候,只能使用 uploadTaskWithRequest:?fromFile:方法。調用方式是傳入request以及file的URL,該方法官方文檔說明它會忽略request中bogy(An?NSURLRequest?object that provides the URL, cache policy, request type, and so on. The body stream and body data in this request object are ignored.)。但是在具體開發過程對于fileURL我傳入nil,然后再request中設置body也是能上傳成功。這里與官方文檔說明有點不一致。