Criar um aplicativo universal do Windows com várias instâncias

Este tópico descreve como criar aplicativos da Plataforma Universal do Windows (UWP) com várias instâncias.

Do Windows 10, versão 1803 (10.0; compilação 17134) em diante, seu aplicativo UWP pode aceitar trabalhar com várias instâncias. Se uma instância de um aplicativo UWP de várias instâncias estiver em execução e uma solicitação de ativação subsequente chegar, a plataforma não ativará a instância existente. Em vez disso, ela criará uma instância, executada em um processo separado.

Importante

O uso de várias instâncias é aceito para aplicativos JavaScript, mas o redirecionamento com múltiplas instâncias não é. Como o redirecionamento de várias instâncias não é suportado para aplicativos JavaScript, a classe AppInstance não é útil para esses aplicativos.

Aceitar o comportamento com várias instâncias

Se estiver criando um novo aplicativo com várias instâncias, você pode instalar o Multi-Instance App Project Templates.VSIX, disponível no Visual Studio Marketplace. Depois de instalar os modelos, eles estarão disponíveis na caixa de diálogo Novo projeto em Visual C# > Windows Universal (ou Outras linguagens > Visual C++ > Windows Universal).

Observação

O modelo de projeto de aplicativo com várias instâncias não está mais disponível. O modelo VSIX era uma conveniência, ou seja, você precisará modificar o projeto existente, conforme descrito abaixo. Adicione a constante DISABLE_XAML_GENERATED_MAIN aos símbolos da compilação do projeto para impedir que a compilação gere um Main() padrão. Isso permite o uso de uma versão do Main () específica e feita especificamente para o aplicativo.

Dois modelos são instalados: o aplicativo UWP de várias instâncias, que fornece o modelo para criar um aplicativo de várias instâncias, e o aplicativo UWP de redirecionamento de várias instâncias, que fornece lógica adicional para você executar uma nova instância ou ativar seletivamente uma instância que já foi iniciada. Por exemplo, talvez você queira apenas uma instância de cada vez editando o mesmo documento para colocar no primeiro plano a instância que tem esse arquivo aberto em vez de iniciar uma nova instância.

Ambos os modelos adicionam SupportsMultipleInstances ao arquivo package.appxmanifest. Observe o prefixo desktop4 e iot2 do namespace: somente projetos para a área de trabalho ou projetos da Internet das Coisas (IoT) oferecem suporte a várias instâncias.

<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>

Redirecionamento de ativação de várias instâncias

O suporte a várias instâncias para aplicativos UWP não serve só para iniciar várias instâncias do aplicativo. Ele permite a personalização nos casos em que você deseja selecionar se uma nova instância do seu aplicativo é iniciada ou se uma instância que já está em execução está ativada. Por exemplo, se o aplicativo for iniciado para editar um arquivo que já está sendo editado em outra instância, convém redirecionar a ativação para essa instância em vez de abrir outra instância que já esteja editando o arquivo.

Para saber como tudo isso funciona, assista a este vídeo sobre como criar aplicativos UWP com várias instâncias.

O modelo de aplicativo UWP de redirecionamento de várias instâncias adiciona SupportsMultipleInstances ao arquivo package.appxmanifest, conforme mostrado acima, e também adiciona um Program.cs (ou Program.cpp, se você estiver usando a versão C++ do modelo) ao seu projeto que contém uma funçãoMain(). A lógica para redirecionar a ativação tem a ver com a função Main. O modelo para Program.cs é mostrado abaixo.

A propriedade AppInstance.RecommendedInstance representa a instância preferencial fornecida pelo shell para essa solicitação de ativação, se houver uma (ou null se não houver). Se o shell fornecer uma preferência, você poderá redirecionar a ativação para essa instância ou ignorá-la, se desejar.

public static class Program
{
    // This example code shows how you could implement the required Main method to
    // support multi-instance redirection. The minimum requirement is to call
    // Application.Start with a new App object. Beyond that, you may delete the
    // rest of the example code and replace it with your custom code if you wish.

    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();

        // If the Windows shell indicates a recommended instance, then
        // the app can choose to redirect this activation to that instance instead.
        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.
            string key = Guid.NewGuid().ToString(); // always unique.
                                                    //string key = "Some-App-Defined-Key"; // never unique.
            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();
            }
        }
    }
}

Main() é a primeira coisa que é executada. A execução é feita antes de OnLaunched e OnActivated. Isso permite que você determine se deseja ativar essa ou outra instância antes que qualquer outro código de inicialização no seu aplicativo seja executado.

O código acima determina se uma instância existente ou nova do seu aplicativo está ativada. Uma chave é usada para determinar se há uma instância existente que você deseja ativar. Por exemplo, se o seu aplicativo puder ser iniciado para Trabalhar na ativação de arquivos, você poderá usar o nome do arquivo como uma chave. Em seguida, você pode verificar se uma instância do seu aplicativo já está registrada com essa chave e ativá-la em vez de abrir uma nova instância. A ideia por trás do código é a seguinte: var instance = AppInstance.FindOrRegisterInstanceForKey(key);

Se uma instância registrada com a chave for encontrada, essa instância será ativada. Se a chave não for encontrada, a instância atual (isto é, a instância que estiver rodando Main) criará seu objeto de aplicativo e começará a ser executada.

Tarefas em segundo plano e várias instâncias

  • Tarefas em segundo plano fora do processo oferecem suporte a várias instâncias. Normalmente, cada novo gatilho resulta em uma nova instância da tarefa em segundo plano (embora tecnicamente falando, várias tarefas em segundo plano possam ser executadas no mesmo processo do host). No entanto, uma instância diferente da tarefa em segundo plano é criada.
  • As tarefas em segundo plano no processo não oferecem suporte a várias instâncias.
  • As tarefas de áudio em segundo plano não oferecem suporte a várias instâncias.
  • Quando um aplicativo registra uma tarefa em segundo plano, ele geralmente verifica primeiro se a tarefa já está registrada e, em seguida, a exclui e registra novamente ou não faz nada para manter o registro existente. Esse ainda é o comportamento típico com aplicativos de várias instâncias. No entanto, um aplicativo com várias instâncias pode optar por registrar um nome de tarefa em segundo plano diferente por instância. Isso resultará em vários registros para o mesmo gatilho, e várias instâncias de tarefa em segundo plano serão ativadas quando o gatilho for acionado.
  • Os serviços de aplicativo iniciam uma instância separada da tarefa em segundo plano do serviço de aplicativo para cada conexão. Isso permanece inalterado para aplicativos com várias instâncias, ou seja, cada instância de um aplicativo com várias instâncias obterá sua própria instância da tarefa em segundo plano do serviço de aplicativo.

Considerações adicionais

  • O recurso de várias instâncias funciona em aplicativos UWP destinados a projetos de desktop e de Internet das Coisas (IoT).
  • Para evitar condições de corrida e problemas de contenção, os aplicativos com várias instâncias precisam tomar medidas para particionar/sincronizar o acesso às configurações, ao armazenamento local do aplicativo e a qualquer outro recurso (como arquivos do usuário, um armazenamento de dados e assim por diante) que possa ser compartilhado entre várias instâncias. Mecanismos de sincronização padrão, como mutexes, semáforos, eventos e assim por diante, estão disponíveis.
  • Se o aplicativo tiver SupportsMultipleInstances no arquivo Package.appxmanifest, suas extensões não precisarão declarar SupportsMultipleInstances.
  • Se você adicionar SupportsMultipleInstances a qualquer outra extensão, além de tarefas em segundo plano ou serviços de aplicativo, e o aplicativo que hospeda a extensão não declarar SupportsMultipleInstancesno arquivo Package.appxmanifest, isso vai gerar um erro de esquema.
  • Os aplicativos podem usar a declaração ResourceGroup em seu manifesto para agrupar várias tarefas em segundo plano no mesmo host. Isso entra em conflito com o recurso de várias instâncias, em que cada ativação vai para um host separado. Portanto, um aplicativo não pode declarar ambos SupportsMultipleInstances e ResourceGroup no manifesto.

Amostra

Consulte Exemplo com várias instâncias para saber como funciona o redirecionamento de ativação de várias instâncias.

Confira também

AppInstance.FindOrRegisterInstanceForKeyAppInstance.GetActivatedEventArgsAppInstance.RedirectActivationToTrabalhar na ativação do aplicativo