概述
前面一篇 About Windows 10 SDK Preview Build 17110 中,我們簡單介紹了 Multi-instance UWP Apps,今天結合開發過程詳細講解一下。
在 Windows 10 Version 1803 以前,UWP App 同一時間只能啟動一個例項,而在 1803 開始,UWP App 可以通過開發者的配置選擇來支援多例項。如果一個多例項 UWP App 正在執行,這時一個啟用請求傳送過來,平臺不會直接啟用當前的例項,而是會建立一個新的例項,執行在單獨的程序中。
開發過程
配置多例項支援
多例項特性需要在 Visual Studio 中安裝新的專案模板:Multi-Instance App Project Templates.VSIX, 安裝後,使用 C# 和 C++ 都可以建立專案。
兩個模板會被安裝:
- Multi-Instance UWP app -- 建立一個多例項的 App
- Multi-Instance Redirection UWP app -- 提供一個附加的邏輯,讓使用者可以選擇啟動新例項,或者選擇目前啟用的例項。可以想象一下 Office 開啟或編輯檔案時的場景。
這兩個模板都會在 manifest 檔案中新增 SupportsMultipleInstances,其中 desktop4 和 iot2 字首標誌了專案只支援傳統桌面 Windows 和 IoT 系統。manifest 配置如下,我們只保留了新增的部分:
<Package
...
xmlns:desktop4="http://schemas.microsoft.com/appx/manifest/desktop/windows10/4"
xmlns:iot2="http://schemas.microsoft.com/appx/manifest/iot/windows10/2"
IgnorableNamespaces="uap mp desktop4 iot2">
...
<Applications>
<Application Id="App"
...
desktop4:SupportsMultipleInstances="true"
iot2:SupportsMultipleInstances="true">
...
</Application>
</Applications>
...
</Package>
實際執行時,每次點選 App 的磁貼,都會啟動一個新的例項。如下圖中,App 顯示了啟動的時間,在工作列和執行視窗可以看到,兩個例項同一時間在執行狀態。
多例項啟用重定向
UWP App 對多例項的支援,可以讓同一 App 的多個例項可以同時在執行。它執行開發者自己定義,是每次開啟一個新的例項,還是重定向某個目前啟用的應用。舉例來說,讓你想使用 App 編輯一個檔案,而這個檔案正在 App 中被編輯,這時就不應該再開啟一個新的例項,而是應該重定向當前正在編輯檔案的例項。這就會用到 Multi-Instance Redirection UWP app 模板。
Multi-Instance Redirection UWP app 模板和我們上面看到的一樣,對 manifest 檔案會做同樣的調整。同時該模板會增加一個 Program.cs 檔案,在檔案中包含一個 Main() 方法,靠這個方法來實現多例項啟用的重定向操作。
我們來重點看看 Program.cs 檔案中的 Main() 方法
- activatedArgs 中包含了應用啟動時我們定義的引數,我們根據這些引數,比如 key 來決定多例項的重定向方式;
- AppInstance.RecommendedInstance 系統推薦的例項,如果有,我們可以重定向到這個例項;
- 多例項間唯一性的標識 key 的生成方式,我們可以根據 activatedArgs 來自定義,在預設的示例程式碼中,採用了隨機數判斷單雙數的方式;
- FindOrRegisterInstanceForKey(key) 會查詢當前對應 key 的例項,如果沒有則新註冊一個例項;
- 判斷例項是不是新註冊的,如果是則啟動,如果是查詢到的原有例項,則重定向到那個例項;
static void Main(string[] args)
{
// First, we'll get our activation event args, which are typically richer
// than the incoming command-line args. We can use these in our app-defined
// logic for generating the key for this instance.
IActivatedEventArgs activatedArgs = AppInstance.GetActivatedEventArgs(); // In some scenarios, the platform might indicate a recommended instance.
// If so, we can redirect this activation to that instance instead, if we wish.
if (AppInstance.RecommendedInstance != null)
{
AppInstance.RecommendedInstance.RedirectActivationTo();
}
else
{
// Define a key for this instance, based on some app-specific logic.
// If the key is always unique, then the app will never redirect.
// If the key is always non-unique, then the app will always redirect
// to the first instance. In practice, the app should produce a key
// that is sometimes unique and sometimes not, depending on its own needs.
uint number = CryptographicBuffer.GenerateRandomNumber();
string key = (number % == ) ? "even" : "odd";
var instance = AppInstance.FindOrRegisterInstanceForKey(key);
if (instance.IsCurrentInstance)
{
// If we successfully registered this instance, we can now just
// go ahead and do normal XAML initialization.
global::Windows.UI.Xaml.Application.Start((p) => new App());
}
else
{
// Some other instance has registered for this key, so we'll
// redirect this activation to that instance instead.
instance.RedirectActivationTo();
}
}
}
對於 key 的構造和判斷,以及判斷後的處理,是多例項重定向的關鍵,我們先看看 FindOrRegisterInstanceForKey(key) 和 IsCurrentInstance 的註釋:
//
// 摘要:
// 如果另一個例項已註冊該金鑰,使用平臺註冊一個應用例項,或查詢現有例項。
//
// 引數:
// key:
// 作為例項金鑰的非空字串。
//
// 返回結果:
// 表示已註冊金鑰的第一個應用的應用例項。
public static AppInstance FindOrRegisterInstanceForKey(string key); //
// 摘要:
// 應用的當前例項是否是該例項定義的特定金鑰的已註冊例項。
//
// 返回結果:
// 指示當前應用是否為該應用的已註冊例項的布林值。
public bool IsCurrentInstance { get; }
後臺任務和多例項
關於後臺任務的多例項,官方有以下說明:
- 程序外的後臺任務支援多例項,通常,每個新觸發的結果會獨立在一個後臺任務的例項中;
- 程序內的後臺任務不支援多例項;
- 後臺音樂任務不支援多例項;
- 當應用註冊一個後臺任務時,它通常會首先檢查這個任務是否已經註冊了,如果已註冊,或刪除重新建立它,或維持當前的註冊。這也是多例項應用的典型特點。然而,多例項應用可能會選擇在每個例項的基礎上註冊一個不同的後臺任務名。這對導致多次註冊相同的觸發器,並且觸發器觸發時將會啟用多個任務例項;
- 應用服務會為每一個應用服務後臺任務的連線啟動一個單獨的例項,這對多例項應用保持不變,即多例項應用的每個例項都會獲得自己的應用服務後臺任務例項;
其他注意事項
關於多例項應用,官方文件還提示了一些額外的注意事項:
- 支援多例項應用的 UWP 應用,只能面向傳統桌面系統和 IoT;
- 為避免競爭條件和資源爭奪的問題,多例項應用需要採取措施,分割槽和同步許可權到對訪問進行設定,應用本地儲存和任何其他資源(如使用者檔案,資料儲存等),以在多個例項間完成共享。標準的同步機制包括 mutexes,semaphores,events 等都是可用的;
- 如果應用的 Package.appxmanifest 檔案中存在 SupportsMultipleInstances 欄位,那麼他的擴充套件中不需要再宣告 SupportsMultipleInstances;
- 如果你把 SupportsMultipleInstances 新增到除後臺任務,應用服務之外的的任何其他擴充套件中,並且託管該擴充套件的應用沒有在 Package.appxmanifest 中宣告 SupportsMultipleInstances,則會發生模式錯誤;
- 應用可以在 manifest 中使用 ResourceGroup 來把多個後臺任務分組到同一個宿主中, 這和多例項是衝突的,每個活動都會出現在單獨的宿主中。因為一個應用不能同時宣告 SupportsMultipleInstances 和 ResourceGroup;
多例項應用的介紹就到這裡,大家可以結合自己應用的實際場景,更加合理的設定 key 和判斷條件來使用多例項,謝謝!