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 和判断条件来使用多实例,谢谢!

相关文章
相关标签/搜索