共用方式為


iOS 背景處理與工作

在 iOS 上執行背景處理最簡單的方式,就是將背景需求分成工作,並在背景中執行工作。 工作在嚴格的時間限制下,在應用程式移至iOS 6的背景之後,通常大約需要600秒(10分鐘)的處理時間,而iOS 7+ 上不到10分鐘。

背景工作可以分成三個類別:

  1. 背景 保管庫 工作 - 在應用程式中,如果應用程式進入背景,您不想中斷的工作,就會呼叫 。
  2. DidEnterBackground 工作 - 在 DidEnterBackground 應用程式生命週期方法期間呼叫,以協助清除和狀態儲存。
  3. 背景傳輸 (iOS 7+) - 用於在 iOS 7 上執行網路傳輸的特殊背景工作類型。 不同於一般工作,背景傳輸沒有預先決定的時間限制。

背景安全,工作 DidEnterBackground 在iOS 6和iOS 7上都安全使用,有些微差異。 讓我們更詳細地調查這兩種類型的工作。

建立背景 保管庫 工作

某些應用程式包含不應由iOS中斷的工作,應用程式應該變更狀態。 保護這些工作免於中斷的其中一種方式,就是將工作註冊到iOS做為長時間執行的工作。 您可以在應用程式中的任何位置使用此模式,而當使用者將應用程式放入背景時,不想中斷工作。 此模式的絕佳候選專案是工作,例如將新用戶的註冊資訊傳送至您的伺服器,或驗證登入資訊。

下列代碼段示範註冊工作以在背景中執行:

nint taskID = UIApplication.SharedApplication.BeginBackgroundTask( () => {});

//runs on main or background thread
FinishLongRunningTask(taskID);

UIApplication.SharedApplication.EndBackgroundTask(taskID);

註冊程式會將工作與唯一標識碼配對, taskID然後將它包裝在相符 BeginBackgroundTaskEndBackgroundTask 呼叫中。 為了產生標識符,我們會呼叫 BeginBackgroundTask 物件上的 UIApplication 方法,然後啟動長時間執行的工作,通常是在新線程上。 當工作完成時,我們會呼叫 EndBackgroundTask 並傳入相同的標識碼。 這很重要,因為如果呼叫沒有相符 EndBackgroundTask的 ,iOS 將會終止應用程式BeginBackgroundTask

重要

根據應用程式的需求,背景安全工作可以在主線程或背景線程上執行。

在 DidEnterBackground 期間執行工作

除了讓長時間執行的工作背景安全之外,註冊還可用來啟動工作,因為應用程式正在置於背景中。 iOS 會在名為的 AppDelegate 類別 DidEnterBackground 中提供事件方法,可用來儲存應用程式狀態、儲存用戶數據,以及在應用程式進入背景之前加密敏感性內容。 應用程式大約要從這個方法傳回五秒,否則將會終止。 因此,從方法內呼叫可能需要超過五秒才能完成的 DidEnterBackground 清除工作。 必須在個別線程上叫用這些工作。

此程式與註冊長時間執行的工作幾乎完全相同。 下列代碼段說明此動作:

public override void DidEnterBackground (UIApplication application) {
  nint taskID = UIApplication.SharedApplication.BeginBackgroundTask( () => {});
  new Task ( () => {
    DoWork();
    UIApplication.SharedApplication.EndBackgroundTask(taskID);
  }).Start();
}

首先,我們會在 中AppDelegate覆寫 DidEnterBackground 方法,其中我們會依照上一個範例中所做的一樣註冊工作BeginBackgroundTask。 接下來,我們會繁衍新的線程,並執行長時間執行的工作。 請注意, EndBackgroundTask 呼叫現在是從長時間執行的工作內進行,因為 DidEnterBackground 方法已經傳回。

重要

iOS 會使用 監視程式機制 來確保應用程式的 UI 保持回應。 花費太多時間 DidEnterBackground 的應用程式會在UI中變得沒有回應。 開始在背景中執行的工作可讓您 DidEnterBackground 及時返回,讓 UI 保持回應,並防止監視程式終止應用程式。

處理背景工作時間限制

iOS 會對背景工作執行的時間長度設定嚴格的限制,如果 EndBackgroundTask 呼叫未在分配的時間內進行,應用程式將會終止。 藉由追蹤剩餘的背景時間,並在必要時使用到期處理程式,我們可以避免 iOS 終止應用程式。

存取剩餘的背景時間

如果具有已註冊工作的應用程式會移至背景,則已註冊的工作將得到大約 600 秒的執行。 我們可以使用 類別的UIApplication靜態BackgroundTimeRemaining屬性,檢查工作必須完成多少時間。 下列程式代碼會提供背景工作已離開的時間,以秒為單位:

double timeRemaining = UIApplication.SharedApplication.BackgroundTimeRemaining;

避免使用到期處理程序終止應用程式

除了授與屬性的BackgroundTimeRemaining存取權之外,iOS 還提供一個正常的方式,透過到期處理程序處理背景時間到期。 這是選擇性的程式代碼區塊,會在指派工作的時間即將到期時執行。 到期處理程式中的程式代碼會呼叫 EndBackgroundTask 並傳入工作標識碼,這表示應用程式運作良好,並防止 iOS 終止應用程式,即使工作用完時間也一樣。 EndBackgroundTask 必須在到期處理程式內以及正常執行過程中呼叫。

到期處理程式會使用 Lambda 表達式以匿名函式表示,如下所示:

Task.Factory.StartNew( () => {

    //expirationHandler only called if background time allowed exceeded
    var taskId = UIApplication.SharedApplication.BeginBackgroundTask(() => {
        Console.WriteLine("Exhausted time");
        UIApplication.SharedApplication.EndBackgroundTask(taskId); 
    });
    while(myFlag == true)
    {
        Console.WriteLine(UIApplication.SharedApplication.BackgroundTimeRemaining);
        myFlag = SomeCalculationNeedsMoreTime();
    }
    //Only called if loop terminated due to myFlag and not expiration of time
    UIApplication.SharedApplication.EndBackgroundTask(taskId);
});

雖然程式代碼執行不需要到期處理程式,但您應該一律使用具有背景工作的到期處理程式。

iOS 7+ 中的背景工作

iOS 7 中與背景工作相關的最大變更不是如何實作工作,而是在工作執行時。

回想一下,在iOS 7之前,背景中執行的工作需要600秒才能完成。 此限制的其中一個原因是背景中執行的工作會讓裝置在工作持續期間保持清醒:

Graph of the task keeping the app awake pre-iOS 7

iOS 7 背景處理已針對較長的電池使用時間進行優化。 在 iOS 7 中,背景變成機會:而不是讓裝置保持清醒,當裝置進入睡眠時,工作會受到尊重,而是在裝置喚醒以處理電話、通知、內送電子郵件和其他常見中斷時,以區塊方式進行處理。 下圖提供工作分拆方式的深入解析:

Graph of the task being broken into chunks post-iOS 7

由於工作運行時間不再持續,因此必須在iOS 7中以不同的方式處理執行網路傳輸的工作。 鼓勵開發人員使用 NSURlSession API 來處理網路傳輸。 下一節是背景傳輸的概觀。

背景傳輸

iOS 7 中背景傳輸的骨幹是新的 NSURLSession API。 NSURLSession 可讓我們建立工作以:

  1. 透過網路和裝置中斷傳輸內容。
  2. 上傳和下載大型檔案 ( 背景傳輸服務 )。

讓我們進一步瞭解其運作方式。

NSURLSession API

NSURLSession 是透過網路傳輸內容的強大 API。 它提供一組工具,可透過網路中斷和應用程式狀態的變更來處理數據傳輸。

NSURLSession API 會建立一或多個會話,進而繁衍工作,以跨網路對相關數據的區塊進行穿梭。 工作會以異步方式執行,以快速且可靠地傳輸數據。 因為 NSURLSession 是異步的,每個會話都需要完成處理程式區塊,讓系統和應用程式知道傳輸何時完成。

若要在 iOS 7 和後 iOS 7 上執行有效的網路傳輸,請檢查 是否可以 NSURLSession 加入佇列傳輸,並使用一般背景工作執行傳輸,如果不是:

if ([NSURLSession class]) {
  // Create a background session and enqueue transfers
}
else {
  // Start a background task and transfer directly
  // Do NOT make calls to update the UI here!
}

重要

避免從 iOS 6 相容程式代碼的背景呼叫更新 UI,因為 iOS 6 不支援背景 UI 更新,而且會終止應用程式。

NSURLSession API 包含一組豐富的功能,可處理驗證、管理失敗的傳輸,以及報告用戶端 -- 而非伺服器端 - 錯誤。 它有助於橋接 iOS 7 中引進的工作運行時間中斷,也支援快速且可靠地傳輸大型檔案。 下一節會探索第二個功能。

背景傳輸服務

在 iOS 7 之前,上傳或下載背景中的檔案是不可靠的。 背景工作會獲得有限的運行時間,但傳輸檔案所需的時間會隨著網路和檔案的大小而有所不同。 在 iOS 7 中,我們可以使用 NSURLSession 來成功上傳和下載大型檔案。 處理背景中大型檔案網路傳輸的特定 NSURLSession 會話類型稱為 背景傳輸服務

使用背景傳輸服務起始的傳輸是由操作系統管理,並提供 API 來處理驗證和錯誤。 由於傳輸不會受到任意時間限制的限制,因此可用來上傳或下載大型檔案、背景中的自動更新內容等等。 如需如何實作服務的詳細資訊, 請參閱背景傳輸 逐步解說。

背景傳輸服務通常會與背景擷取或遠端通知配對,以協助應用程式在背景重新整理內容。 在接下來的兩節中,我們會介紹註冊整個應用程式的概念,以在iOS 6和iOS 7的背景中執行。