APNS和Background Fetch相關問題總結

1.1 Normal Push Notification

1.1.1 概述

app獲取deviceToken, 上報自己的服務端, 服務端維持一份用戶ID->deviceToken的映射;用戶退出登錄時需要調用解綁接口,否則會出現當前用戶收到發給其它用戶的信息.
在這裏插入圖片描述
如何把消息推送到用戶手機上:
在這裏插入圖片描述

1.1.2 deviceToken相關

  • iOS7之前,在iOS7之前單一環境下(Develop/Distribution)每一個設備一個DeviceToken;
  • iOS7+,單一環境下(Develop/Distribution),一個bundleId對應一個DeviceToken,app卸載後再重裝deviceToken會發生改變;

1.1.3 推送feedback接口

APNS的feedback service會返回那些已經卸載的設備的deviceToken。對於這些token,下次就不用再發了。可以節省點資源。需要注意的是:feedback的接口讀取一次,APNS就會清空它的列表,下次再讀取時,返回的就是這兩次讀取之間這段時間新產生的deviceToken.

1.1.4 badge點擊不消失的問題

如果推送到 APNs 時,Badge number 被指定爲0 ,則可能出現 push消息在通知中心被點擊後,儘管調用了 [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0]; 但 APNs 消息在通知中心不會被刪除的情況。 這種情況可以按如下代碼調用以清除通知中心的 push通知。

[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 1 ];
[[UIApplication sharedApplication] setApplicationIconBadgeNumber: 0];

1.1.5 定製push notification的推送時間段

如果用戶即想接收通知又不想接收其它不關注的通知, 可以對消息進行分類讓用戶進行定製.用戶也可以設置接收通知的時間段,來避免被騷擾.

1.1.6 push notification的功能擴展

  • 可以對一些實時性較強消息推送過來之後,運用today擴展進行展示,比如一些熱銷或促銷商品;
  • app未啓動或者處於後臺時收到推送進行相關資源下載,待app啓動/回到前臺時展示更新後的界面(詳看silent push notification);
  • 可結合Apple Watch做相應的展示,一些物流消息的展示如果與Apple Watch配對的iphone處於黑屏狀態下,則可在Watch上進行展示;

1.1.7 收不到push notification的情況總結

  • appID是否把push開關打開了;
  • 系統設置裏面是否把相應app的通知開關關閉了;
  • appID是否是帶"*"的;
  • 前後端證書appID和後端推送證書appID是否是同一個;
  • 前端環境和後端環境是否相同(同爲developer或同爲distribution);
  • 後端推送證書是否過期(有效期一般爲一年);
  • 如果是拿不到deviceToken,並且IOS系統設置中通知開關部分打開,這時手動切換一下其它開關的狀態,使其可接受到deviceToken(蘋果的bug,一般是由於用戶打開部分推送開關的情況下,把整個接受推送的開關關閉掉,然後卸載再重裝app所致);
  • app在系統設置通知裏關閉接受消息通知,這時如果再重新安裝app,開關狀態依舊關閉(ios8以上一個系統版本有這個問題);
  • 看看手機是否設置了代理,測試人員經常設置代理進行測試;
  • 後端推送數據包過大,IOS8之前推送支持256個字節,IOS8之後支持2K,這時候需要上報deviceToken時,把系統版本號也上報上去,便於推送時根據不同版本號進行不同長度的數據推送。
    在這裏插入圖片描述

1.1.8 測試工具

  • php推送腳本;
  • PushMeBaby;
  • SmartPush;

1.2 Silent Push Notification

1.2.1 概述

If your app’s server-based content changes infrequently, or at irregular intervals, you can use silent notifications to notify your app when new content is available. A silent notification is a remote notification that doesn't display an alert, play a sound, or badge your app’s icon. It wakes your app in the background and gives it time to initiate downloads from your server and update its content.
Important

The system treats silent notifications as low-priority. You can use them to refresh your app’s content, but the system doesn't guarantee their delivery. In addition, the delivery of silent notifications may be throttled if the total number becomes excessive. The actual number of silent notifications allowed by the system depends on current conditions, but don't try to send more than two or three silent notifications per hour.

1.2.2 開啓Silent Remote Notifications

在這裏插入圖片描述

1.2.3 Silent Notification Payload格式

{
   "aps" : {
      "content-available" : 1
   },
   "acme1" : "bar",
   "acme2" : 42
}

必須不能攜帶 alert、badge、sound,不然就不是靜默推送了。

When an iOS device receives a silent notification, the system wakes your app in the background and calls the application:didReceiveRemoteNotification:fetchCompletionHandler: method of its app delegate. Your app has `30` seconds of wall-clock time to perform any tasks and call the provided completion handler. For more information, see Handling Notifications and Notification-Related Actions.

1.2.3 版本限制

  • iOS7+

1.2.4 payload大小限制

A basic remote notification payload includes Apple-defined keys and their custom values. You may also add custom keys and values specific to your notifications. Apple Push Notification service (APNs) refuses a notification if the total size of its payload exceeds the following limits:
For Voice over Internet Protocol (VoIP) notifications, the maximum payload size is 5 KB (5120 bytes).
For all other remote notifications, the maximum payload size is 4 KB (4096 bytes).

1.2.5 靜默推送測試

版本 app未啓動 app處於後臺(包括掛起) app處於前臺
8.3 收不到 能收到 能收到
9.3.5 收不到 能收到 能收到
10.3.3 收不到 能收到 能收到
11.4.1 XCode連調強殺能收到, 直接強殺收不到 能收到 能收到
12.1 XCode連調強殺能收到, 直接強殺收不到 能收到 能收到

2.Background Fetch

2.1 概述

Background App Refresh lets your app run periodically in the background so that it can update its content. Apps that update their content frequently, such as news apps or social media apps, can use this feature to ensure that their content is always up to date. Downloading data in the background before it is needed minimizes the lag time in displaying that data when the user launches the app.

2.2 如何使用

To support Background App Refresh for your app, do the following:

  1.Enable the background fetch capability in your app ().

  2.Call the setMinimumBackgroundFetchInterval: method of UIApplication at launch time.

  3.Implement the application:performFetchWithCompletionHandler: method in your app delegate.
 

在這裏插入圖片描述

When the system calls your app delegate’s application:performFetchWithCompletionHandler: method, configure a NSURLSession object to download any new data.The system waits until network and power conditions are good, so you should be able to retrieve adequate amounts of data quickly. When you finish updating your app, call the completion handler and provide an accurate result of your outcome, which can include saying that no new data was available.

Important

Calling the completion handler in a timely manner, and with an accurate result, helps determine how much future execution time your app receives. If you take too long to update your app, the system may schedule your app less frequently in the future to save power.

2.3 後臺執行順序

應用程序可以從幾個不同的觸發點進入後臺.系統事件可以讓一個掛起的app進入後臺或者讓一個沒有運行的app直接啓動進入後臺.當另一個app啓動或者用戶返回到主屏幕時可以讓一個處於前臺的app進入後臺模式.

後臺執行順序圖如下:

在這裏插入圖片描述
當一個後臺事件到達app沒有處於運行狀態時,系統會按照如下順序把app啓動並直接移入後臺:

  1. The system launches the app and follows the initialization sequence described in About the App Launch Sequence.

  2. UIKit calls the app delegate's applicationDidEnterBackground: method.

  3. UIKit delivers the event that caused the launch.

  4. The app's snapshot is taken.

  5. The app may be suspended again.

當app處於掛起狀態時,當一個後臺事件到達時,遵循如下順序:

  1. The system resumes the app.

  2. UIKit calls the app delegate's applicationDidEnterBackground: method.

  3. UIKit delivers the event that caused the launch.

  4. The app's snapshot is taken.

  5. The app may be suspended again.

當另一個app啓動或者用戶返回到主屏幕,處於前臺的app會進入後臺模式,遵循如下順序:

  1. The user exits the running app.

  2. UIKit calls the app delegate's applicationWillResignActive: method.

  3. UIKit calls the app delegate's applicationDidEnterBackground: method.

  4. The app's snapshot is taken.

  5. The app may be suspended again.

2.4 延長app後臺執行時間

延長你的app後臺執行時間可以保證你有足夠的時間來執行重要任務.當app進入後臺模式時,系統調用app的代理的applicationDidEnterBackground:方法.該方法有5s的時間來執行任務並返回.該方法返回之後,系統馬上會把app置於掛起狀態.對於大部分app來說5s足夠來處理任何重要的任務,但是如果你需要更多時間,可以請求UIKit來延長你的app的運行時間.

通過調用beginBackgroundTaskWithName:expirationHandler:來延長你的app運行時間.通過調用該方法可以給你額外的時間來處理重要任務(通過backgroundTimeRemaining屬性來查看還剩多少時間).一旦你的任務完成了,立刻調用endBackgroundTask:來通知系統你已經處理完成.如果你不及時結束任務,系統會終止app的運行.

func sendDataToServer( data : NSData ) {
   // Perform the task on a background queue.
   DispatchQueue.global().async {
      // Request the task assertion and save the ID.
      self.backgroundTaskID = UIApplication.shared.
                 beginBackgroundTask (withName: "Finish Network Tasks") {
         // End the task if time expires.
         UIApplication.shared.endBackgroundTask(self.backgroundTaskID!)
         self.backgroundTaskID = UIBackgroundTaskInvalid
      }
            
      // Send the data synchronously.
      self.sendAppDataToServer( data: data)
            
      // End the task assertion.
      UIApplication.shared.endBackgroundTask(self.backgroundTaskID!)
      self.backgroundTaskID = UIBackgroundTaskInvalid
   }
}
Note

The beginBackgroundTaskWithName:expirationHandler: method cannot be called from an app extension. To request extra execution time from your app extension, call the performExpiringActivityWithReason:usingBlock: method of NSProcessInfo instead.

2.5 如何模擬Background Fetch

  • XCode運行程序後, 在Debug->Simulate Background Fetch.(模擬app在前臺和後臺時)
  • Product->Scheme->Edit scheme 在Debug模式選中Options,點選Launch due to a background fetch event.(模擬App沒有啓動的情況)

2.6 其它

  • 設置->通用->後臺應用程序刷新 中顯示了打開後臺應用刷新的應用.在代碼中我們可以通過[UIApplication sharedApplication].backgroundRefreshStatus == UIBackgroundRefreshStatusAvailable來進行相應的判斷;
A restricted user, such as one who is managed under parental controls, can't enable Background App Refresh.

Background App Refresh is disabled automatically when a device is operating in low-power mode. When this happens, the time available for performing background tasks is reduced to save power.

  • 版本要求: iOS 7.0+, tvOS 11.0+;

  • 後臺操作時的時間要求30s,如果不及時調用completionHandler,app將會被殺死.後臺操作耗時越長,app被調用的頻率將會降低;
    - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler;

    When this method is called, your app has up to 30 seconds of wall-clock time to perform the download operation and call the specified completion handler block. In practice, your app should call the completion handler block as soon as possible after downloading the needed data. If you do not call the completion handler in time, your app is terminated. More importantly, the system uses the elapsed time to calculate power usage and data costs for your app’s background downloads. If your app takes a long time to call the completion handler, it may be given fewer future opportunities to fetch data in the future. For more information about supporting background fetch operations, see Background Execution in App Programming Guide for iOS.
    
  • application: performFetchWithCompletionHandler;調用頻次:

    1. [[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum]; 時間間隔可以自定義.

    2. 和網絡和電量狀態有關;

    3. 後臺操作耗時越長,調用頻率會降低;

參考鏈接:
1.https://developer.apple.com/documentation/uikit/core_app/managing_your_app_s_life_cycle/preparing_your_app_to_run_in_the_background/extending_your_app_s_background_execution_time?language=objc

2.https://developer.apple.com/documentation/uikit/core_app/managing_your_app_s_life_cycle/preparing_your_app_to_run_in_the_background/about_the_background_execution_sequence?language=objc

3.https://developer.apple.com/documentation/uikit/core_app/managing_your_app_s_life_cycle/responding_to_the_launch_of_your_app/about_the_app_launch_sequence?language=objc

4.https://developer.apple.com/documentation/uikit/core_app/managing_your_app_s_life_cycle/preparing_your_app_to_run_in_the_background/updating_your_app_with_background_app_refresh

5.https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623125-application?changes=latest_minor&language=objc

6.https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/generating_a_remote_notification

7.https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/pushing_updates_to_your_app_silently

8.https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/APNSOverview.html#//apple_ref/doc/uid/TP40008194-CH8-SW1

9.https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CreatingtheNotificationPayload.html#//apple_ref/doc/uid/TP40008194-CH10-SW1

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章