UWP - 新 BackgroundMediaPlayback 架構

Windows 10 version 14332 開始針對 Background Media Player 的架構再一次被調整了,過去需要分開撰寫 Foreground/Background 兩個部分的 process,現在提供了合并為一個 process 的選擇。快來學習怎麽使用吧。

根據<Background activity with the Single Process Model>的介紹,version 14332 (Windows 10 Anniversary Update)之後,如果開發的 App 需要用到 background task 的話,開發者可以選擇:

  • 分開 foreground/background 兩個 process 的方式 (現在方式)
  • 選擇 single prcess 開發支援 background 運作的 Apps (新方式)

 支援 single process model 的 background task 有:

  • Background Triggers
  • App Services
  • Background media playback using Activity Sponsored Execution
  • Extened Execution

 

single process model 要注意幾個新的機制:

  • App 的 Lifecycle 增加新的通知: EnteredBackgroundLeavingBackground 的機制:

1_lifecycle

流程:

a. App 啓動之後不是進 Launch 而是先 active 到 Running in background

b. 接著再到 leaving background 到 Running in foreground

c. 如果這個時候離開 App 會 entered background 到 Running in background

d. 如果 background 沒有要處理什麽事情接著會 suspending 到 Suspended

e. 在 Suspended 過程裏面再開啓 App 會 resuming 到 Running in background

 

  • Entering the background

EnteredBackground 讓 app 知道它從 foreground 顯示中的狀態完全離開了。

之前的版本用戶完成一個 session 而離開 app(或是退到 background )時,Suspending callback 最好是用來保持 app 運作的狀態。

single process model 架構下 app 在進入 background 或是從 foreground 離開後任然會持續執行,而 Suspended state 再不會立即被觸發

因此,原本放在 Suspened callback 保存 status 的時機要移動到 EnteredBackground,記憶體限制也會改變 app 進入 background

如果需要確認 app 不會得到 terminated,最好先確認 memory manager 與 drop memory 。

原本的 App 在 Life cycle 需要調整

a. 離開 App 不會馬上進去 Suspended,而是進入 EnteredBackground

b. 在還沒有被 Suspended 之前回到 App,而是進入 LeavingBackground

c. Suspended 后整個 App 是停止,返回時 resume 再進去 EnteredBackground

 

  • Leaving the background

App 被 actived 或 resumed 預設的狀態是 Running in background。依照 activation 的類型,app 可能移動到 running in the foreground 或是繼續待在 background

LeavingBackground 事件是在當 App UI 可以被用戶看見時才會被觸發

之前的版本會在 Activated 或是 Resuming 事件處理載入 UI 的任務;現在 LeavingBackground 則是最好檢查 UI 是否要被載入準備呈現的最好位置

也代表說 LeavingBackground 是最後可以檢查 visual assets 是否已經 ready 的時間。

2_background流程:

a. not running 的 app 被開啓,先進入 activated 再到 Running in background

b. 如果 app 確定要回到 foreground 會進入 LeavingBackground,接著 Running in foreground

c. 如果 app 從 foreground 離開會進入 EnteredBackground 再到 Running in background

d. 接著重覆,可以發現 actived 衹有一次的機會。(取代了過去的 Launched)

 

利用 EnteredBackground 與 LeavingBackground 將可以讓 App 很順暢地切換 foreground 與 background ,就像是同一個 process application。

接著往下説明會影響的對象:

  • Background Triggers

Single process background activity 的注冊方式跟過去一樣,使用 BackgroundTaskBuilder 設定需要的 triggers。

新的機制不需要再 BackgroundTaskBuilder 設定 entry point,它會預設使用 application object 的 OnBackgroundActivated() 來啓動。

triggers 被注冊之後就會立即啓動,并且通知 OnBackgroundActivated(),可以藉由得到的 BackgroundActivatedEventArgs 如同 BackgroundTask.Run() 一樣可以得到 background instance 開啓 background 功能。

如下範例:

var builder = new BackgroundTaskBuilder();
builder.Name = "My Background Trigger";
builder.SetTrigger(new TimeTrigger(15, true));
 
// use builder.TaskEntryPoint if you want to not use the default OnBackgroundActivated
// we’ll register it and now will start work based on the trigger, here we used a Time Trigger
BackgroundTaskRegistration task = builder.Register();

// Since we didn’t use TaskEntryPoint, this is the default constructor used
protected override void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
   base.OnBackgroundActivated(args);
   DoBackgroundWork(args.TaskInstance);  
}

如果需要參考過去 multiple background 的範例可參考<Background Activation Sample>,可以利用 BackgroundActivatedEventArgs.TaskInstance.Task.Name 識別 task 是否被初始化。

如果現在已經有因爲支援 background / foreground process 所增加的那些 state management 與 communicaton code 都可以拿掉了。 因爲 single process 直接讓 app 同時可以執行在 foreground / background 之中。

 

  • App Services

雖然 trigger 被系統使用來通知啓動 app 在 background 下運行。而 App Service Connection 允許其他 app 從 background 叫醒你的 app 進行溝通與交易。

App service 不是永遠都活著,需要依賴 forground app 來啓動它。

現在 App service 可以運作在 single process model,直接與 forground apps 溝通不需要再切割成兩個 process。

a. 要讓 app service 可以支援 single process model,需要先宣告:

<uap:Extension Category="windows.appService">
    <uap:AppService Name="SingleProcessAppService" />
</uap:Extension>

拿掉 EntryPoint 屬性,如同上述提到的 BackgroundTaskBuilder,同樣是用 OnBackgroundActivated() callback 處理 background 的任務。

 

b. 接著移動原本寫在 IBackgroundTask project 的 methods 移動到 OnBackgroundActivated():

private AppServiceConnection appServiceconnection;
private BackgroundTaskDeferral appServiceDeferral;
protected override async void OnBackgroundActivated(BackgroundActivatedEventArgs args)
{
    base.OnBackgroundActivated(args);
    IBackgroundTaskInstance taskInstance = args.TaskInstance;
    AppServiceTriggerDetails appService = taskInstance.TriggerDetails as AppServiceTriggerDetails;
    appServiceDeferral = taskInstance.GetDeferral();
    taskInstance.Canceled += OnAppServicesCanceled;
    appServiceConnection = appService.AppServiceConnection;
    appServiceConnection.RequestReceived += OnAppServiceRequestReceived;
    appServiceConnection.ServiceClosed += AppServiceConnection_ServiceClosed;
}
private async void OnAppServiceRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
    AppServiceDeferral messageDeferral = args.GetDeferral();
    ValueSet message = args.Request.Message;
    string text = message["Request"] as string;
             
    if ("Value" == text)
    {
        ValueSet returnMessage = new ValueSet();
        returnMessage.Add("Response", "True");
        await args.Request.SendResponseAsync(returnMessage);
    }
    messageDeferral.Complete();
}
private void OnAppServicesCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason)
{
    appServiceDeferral.Complete();
}
private void AppServiceConnection_ServiceClosed(AppServiceConnection sender, AppServiceClosedEventArgs args)
{
    appServiceDeferral.Complete();
}

在 OnBackgroundActiaved() 負責利用 AppServiceConnection 注冊接受來自外部 app 請求的任務。

利用 ValueSet 設定要回傳給請求 app 的内容。更多的範例説明可以參考<Create and Consume an App Service>。

 

  • Background media playback using Activity Sponsored Execution

過去開發 Background media playback 非常痛苦,因爲需要爲了 state management 與 commuication 花很多力氣來控制。

現在不需要了,提供 single process 讓 foreground / background 直接整合 (如果你開發過 Windows RT 的 app 你會發現其實這個架構在 RT 時候已經存在),大量減少了控制代碼,讓 playback 持續活著。

使用方式:

<Package
  xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
  xmlns:mp="http://schemas.microsoft.com/appx/2014/phone/manifest"
  xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
  xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
  IgnorableNamespaces="uap uap3 mp">
...
<Capabilities>
<uap3:Capability Name="backgroundMediaPlayback"/>
</Capabilities>

引入新的 new uap schema namespace,在 <Capabilities /> 加入新的 element:<uap3:Capability Name="backgroundMediaPlayback“ />。

所有的 media playback APIs 都適用于 foreground/background,不需要再分成兩個 process。

另外,這樣的方式即是讓系統知道 app 是支援背景播放的應用,自動將它移動到 background 延伸 lifetime。

更多範例可參考<Background Media Playback Sample>。

 

  • Extended Excution

Extended Execution 是一個讓 app 可以持續從 foreground 到 background 一直運行的方法。

利用這個方式可以讓當 app 有重要完成的任務時,延後 app 進入 suspended 的時間,讓任務有更多的時間可以被完成。

與注冊 background activity 是不同的,這個像是讓 app 直接從 foreground 到 background 持續運作,而不理會前面的狀態改變。

使用方式:

ExtendedExecutionSession Session = new ExtendedExecutionSession();
Session.Reason = ExtendedExecutionReason.Unspecified;
Session.Description = BackgroundActivityDescription;
Session.Revoked += SessionRevoked;
ExtendedExecutionResult result = await Session.RequestExtensionAsync();

建立一個 ExtendedExecutionSession,設定理由跟描述,需要注冊 Revoked 處理當 Session 被取消的時候要做的事情,最後在請求 Extension,它不是每次都會可以請求的到所以要特別判斷 ExtendedExecutionResult。

Extended Execution 會皆有 ExtendedExecutionReason 不同而給予不同的運算時間來完成任務。更多範例可以參考<Extended Execution Sample>。

 

[Unsupported Scenarios]
  • Background activity 依舊是有可能會被結束的 (例如:超過可時間限時)
  • 建議如果是需要 background 直接處理的任務就不一定需要 single process model
  • 不支援 single progress model 的有
    • DeviceUseTrigger
    • DeviceServicingTrigger
    • IoTStartupTask
    • VoIP background task
    • 這些任然是使用 multiple process
======
針對 Background task 的開發機制統一成 single process model 之後,讓整個開發都相對於過去簡單不少,
但是 app 的 lifecycle 要特別注意,因爲新的 EnteredBackground 與 LeavingBackground 讓整個緩存跟還原資料的時間更複雜,
如果您的 app 本身就很依賴 Suspended 與 Resume 的話,這個兩個部分要特別驗證與調整。
 

References: