New Windows 10 SDK - Multi-instance UWP apps

概述ios

前面一篇 About Windows 10 SDK Preview Build 17110 中,咱們簡單介紹了 Multi-instance UWP Apps,今天結合開發過程詳細講解一下。windows

在 Windows 10 Version 1803 之前,UWP App 同一時間只能啓動一個實例,而在 1803 開始,UWP App 能夠經過開發者的配置選擇來支持多實例。若是一個多實例 UWP App 正在運行,這時一個激活請求發送過來,平臺不會直接激活當前的實例,而是會建立一個新的實例,運行在單獨的進程中。app

開發過程 dom

配置多實例支持ui

多實例特性須要在 Visual Studio 中安裝新的項目模板:Multi-Instance App Project Templates.VSIX, 安裝後,使用 C# 和 C++ 均可以建立項目。this

兩個模板會被安裝:spa

  • Multi-Instance UWP app -- 建立一個多實例的 App
  • Multi-Instance Redirection UWP app -- 提供一個附加的邏輯,讓用戶能夠選擇啓動新實例,或者選擇目前激活的實例。能夠想象一下 Office 打開或編輯文件時的場景。

      

這兩個模板都會在 manifest 文件中添加 SupportsMultipleInstances,其中 desktop4 和 iot2 前綴標誌了項目只支持傳統桌面 Windows 和 IoT 系統。manifest 配置以下,咱們只保留了新增的部分:code

<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 顯示了啓動的時間,在任務欄和運行窗口能夠看到,兩個實例同一時間在運行狀態。 orm

 

多實例激活重定向xml

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 % 2 == 0) ? "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 和判斷條件來使用多實例,謝謝!

相關文章
相關標籤/搜索