Transfira e instale atualizações de pacotes a partir da Loja

A partir do Windows 10, versão 1607, pode utilizar os métodos da classe StoreContext no espaço de nomes Windows.Services.Store para verificar programaticamente se existem atualizações de pacotes da aplicação atual na Microsoft Store e para transferir e instalar os pacotes atualizados. Também pode consultar pacotes que marcou como obrigatórios no Centro de Parceiros e desativar funcionalidades na sua aplicação até que a atualização obrigatória seja instalada.

Métodos adicionais do StoreContext introduzidos no Windows 10, versão 1803, permitem-lhe descarregar e instalar atualizações de pacotes silenciosamente (sem mostrar uma interface de notificação ao utilizador), desinstalar um pacote opcional e obter informações sobre pacotes na fila de download e instalação da sua aplicação.

Estas funcionalidades ajudam-no a manter automaticamente a sua base de utilizadores atualizada com a versão mais recente da sua aplicação, pacotes opcionais e serviços relacionados na Loja.

Observação

As Windows.Services.Store APIs exigem identidade de pacote e funcionam para qualquer aplicação MSIX distribuída através da Microsoft Store, incluindo aplicações WinUI 3 construídas com o SDK de Aplicações Windows. Os exemplos de código neste artigo foram originalmente escritos para UWP. Se os estiveres a adaptar para uma aplicação WinUI 3, substitui this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, ...) por DispatcherQueue.GetForCurrentThread().TryEnqueue(...), e substitui MessageDialog (que requer interoperabilidade HWND no WinUI 3) por ContentDialog ou usa WinRT.Interop.InitializeWithWindow.Initialize para associar o diálogo ao teu handle da janela.

Descarregue e instale atualizações de pacotes com a permissão do utilizador

Este exemplo de código demonstra como usar o método GetAppAndOptionalStorePackageUpdatesAsync para descobrir todas as atualizações de pacotes disponíveis na Store e depois chamar o método RequestDownloadAndInstallStorePackageUpdatesAsync para descarregar e instalar as atualizações. Ao usar este método para descarregar e instalar atualizações, o sistema operativo apresenta um diálogo que pede permissão ao utilizador antes de descarregar as atualizações.

Observação

Estes métodos suportam pacotes obrigatórios e opcionais para a sua aplicação. Pacotes opcionais são úteis para conteúdos descarregáveis (DLC), para dividir a sua aplicação grande por limitações de tamanho, ou para enviar conteúdo adicional separado da sua aplicação principal. Para obter permissão para submeter uma aplicação que utilize pacotes opcionais (incluindo add-ons DLC) para a Loja, consulte o suporte para desenvolvedores do Windows.

Este exemplo de código assume:

  • O código corre no contexto de uma página UWP XAML (Windows.UI.Xaml.Controls.Page). Estes exemplos são escritos para UWP; veja a NOTA no topo deste artigo para adaptações do WinUI 3.
  • A Página contém uma Barra de Progresso nomeada downloadProgressBar para fornecer o estado da operação de download.
  • O ficheiro de código contém uma instrução using para os espaços de nomes Windows.Services.Store, System.Threading.Tasks e Windows.UI.Popups.
  • A aplicação é para um único utilizador que funciona apenas no contexto do utilizador que a lançou. Para uma aplicação multiutilizador, use o método GetForUser para obter um objeto StoreContext em vez do método GetDefault .
private StoreContext context = null;

public async Task DownloadAndInstallAllUpdatesAsync()
{
    if (context == null)
    {
        context = StoreContext.GetDefault();
    }

    // Get the updates that are available.
    IReadOnlyList<StorePackageUpdate> updates =
        await context.GetAppAndOptionalStorePackageUpdatesAsync();

    if (updates.Count > 0)
    {
        // Alert the user that updates are available and ask for their consent
        // to start the updates.
        MessageDialog dialog = new MessageDialog(
            "Download and install updates now? This may cause the application to exit.", "Download and Install?");
        dialog.Commands.Add(new UICommand("Yes"));
        dialog.Commands.Add(new UICommand("No"));
        IUICommand command = await dialog.ShowAsync();

        if (command.Label.Equals("Yes", StringComparison.CurrentCultureIgnoreCase))
        {
            // Download and install the updates.
            IAsyncOperationWithProgress<StorePackageUpdateResult, StorePackageUpdateStatus> downloadOperation =
                context.RequestDownloadAndInstallStorePackageUpdatesAsync(updates);

            // The Progress async method is called one time for each step in the download
            // and installation process for each package in this request.
            downloadOperation.Progress = async (asyncInfo, progress) =>
            {
                await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
                () =>
                {
                    downloadProgressBar.Value = progress.PackageDownloadProgress;
                });
            };

            StorePackageUpdateResult result = await downloadOperation.AsTask();
        }
    }
}

Observação

Para descarregar apenas (mas não instalar) as atualizações de pacotes disponíveis, use o método RequestDownloadStorePackageUpdatesAsync .

Mostrar informações sobre o progresso do download e instalação

Quando chama o método RequestDownloadStorePackageUpdatesAsync ou RequestDownloadAndInstallStorePackageUpdatesAsync, pode atribuir um manipulador de progresso que é chamado uma vez por cada etapa do processo de transferência (ou transferência e instalação) de cada pacote nesta solicitação. O handler recebe um objeto StorePackageUpdateStatus que fornece informações sobre o pacote de atualização que levantou a notificação de progresso. O exemplo anterior utiliza o campo PackageDownloadProgress do objeto StorePackageUpdateStatus para mostrar o progresso do processo de download e instalação.

Tenha em atenção que, quando liga ao RequestDownloadAndInstallStorePackageUpdatesAsync para descarregar e instalar atualizações de pacotes numa única operação, o campo PackageDownloadProgress aumenta de 0.0 para 0.8 durante o processo de download de um pacote, e depois aumenta de 0.8 para 1.0 durante a instalação. Portanto, se associar a percentagem mostrada na sua interface personalizada de progresso diretamente ao valor do campo PackageDownloadProgress, a sua interface mostrará 80% quando o pacote tiver terminado de ser transferido e o sistema operativo apresentar a caixa de diálogo de instalação. Se quiser que a sua interface de progresso personalizada mostre 100% quando o pacote estiver descarregado e pronto para ser instalado, pode modificar o seu código para atribuir 100% à interface de progresso quando o campo PackageDownloadProgress atingir 0,8.

Descarregue e instale atualizações de pacotes silenciosamente

A partir do Windows 10, versão 1803, pode usar os métodos TrySilentDownloadStorePackageUpdatesAsync e TrySilentDownloadAndInstallStorePackageUpdatesAsync para descarregar e instalar atualizações de pacotes silenciosamente, sem apresentar uma interface de notificação ao utilizador. Esta operação só terá sucesso se o utilizador tiver ativado automaticamente a definição Atualizar aplicações na Loja e não estiver numa rede com medição. Antes de chamar estes métodos, pode primeiro verificar a propriedade CanSilentlyDownloadStorePackageUpdates para determinar se estas condições estão atualmente cumpridas.

Este exemplo de código demonstra como usar o método GetAppAndOptionalStorePackageUpdatesAsync para descobrir todas as atualizações de pacotes disponíveis e depois chamar os métodos TrySilentDownloadStorePackageUpdatesAsync e TrySilentDownloadAndInstallStorePackageUpdatesAsync para descarregar e instalar as atualizações silenciosamente.

Este exemplo de código assume:

  • O ficheiro de código contém uma instrução using dos espaços de nomes Windows.Services.Store e System.Threading.Tasks.
  • A aplicação é para um único utilizador que funciona apenas no contexto do utilizador que a lançou. Para uma aplicação multiutilizador, use o método GetForUser para obter um objeto StoreContext em vez do método GetDefault .

Observação

Os métodos IsNowAGoodTimeToRestartApp, RetryDownloadAndInstallLater e RetryInstallLater , chamados pelo código deste exemplo, são métodos provisórios que se destinam a serem implementados conforme necessário, de acordo com o design da sua própria aplicação.

private StoreContext context = null;

public async Task DownloadAndInstallAllUpdatesInBackgroundAsync()
{
    if (context == null)
    {
        context = StoreContext.GetDefault();
    }

    // Get the updates that are available.
    IReadOnlyList<StorePackageUpdate> storePackageUpdates =
        await context.GetAppAndOptionalStorePackageUpdatesAsync();

    if (storePackageUpdates.Count > 0)
    {

        if (!context.CanSilentlyDownloadStorePackageUpdates)
        {
            return;
        }

        // Start the silent downloads and wait for the downloads to complete.
        StorePackageUpdateResult downloadResult =
            await context.TrySilentDownloadStorePackageUpdatesAsync(storePackageUpdates);

        switch (downloadResult.OverallState)
        {
            case StorePackageUpdateState.Completed:
                // The download has completed successfully. At this point, confirm whether your app
                // can restart now and then install the updates (for example, you might only install
                // packages silently if your app has been idle for a certain period of time). The
                // IsNowAGoodTimeToRestartApp method is not implemented in this example, you should
                // implement it as needed for your own app.
                if (IsNowAGoodTimeToRestartApp())
                {
                    await InstallUpdate(storePackageUpdates);
                }
                else
                {
                    // Retry/reschedule the installation later. The RetryInstallLater method is not  
                    // implemented in this example, you should implement it as needed for your own app.
                    RetryInstallLater();
                    return;
                }
                break;
            // If the user cancelled the download or you can't perform the download for some other
            // reason (for example, Wi-Fi might have been turned off and the device is now on
            // a metered network) try again later. The RetryDownloadAndInstallLater method is not  
            // implemented in this example, you should implement it as needed for your own app.
            case StorePackageUpdateState.Canceled:
            case StorePackageUpdateState.ErrorLowBattery:
            case StorePackageUpdateState.ErrorWiFiRecommended:
            case StorePackageUpdateState.ErrorWiFiRequired:
            case StorePackageUpdateState.OtherError:
                RetryDownloadAndInstallLater();
                return;
            default:
                break;
        }
    }
}

private async Task InstallUpdate(IReadOnlyList<StorePackageUpdate> storePackageUpdates)
{
    // Start the silent installation of the packages. Because the packages have already
    // been downloaded in the previous method, the following line of code just installs
    // the downloaded packages.
    StorePackageUpdateResult downloadResult =
        await context.TrySilentDownloadAndInstallStorePackageUpdatesAsync(storePackageUpdates);

    switch (downloadResult.OverallState)
    {
        // If the user cancelled the installation or you can't perform the installation  
        // for some other reason, try again later. The RetryInstallLater method is not  
        // implemented in this example, you should implement it as needed for your own app.
        case StorePackageUpdateState.Canceled:
        case StorePackageUpdateState.ErrorLowBattery:
        case StorePackageUpdateState.OtherError:
            RetryInstallLater();
            return;
        default:
            break;
    }
}

Atualizações obrigatórias de pacotes

Quando cria uma submissão de pacote no Centro de Parceiros para uma aplicação direcionada ao Windows 10, versão 1607 ou posterior, pode marcar o pacote como obrigatório e a data e hora em que se torna obrigatório. Quando esta propriedade é definida e a sua aplicação descobre que a atualização do pacote está disponível, a sua aplicação pode determinar se o pacote de atualização é obrigatório e alterar o seu comportamento até a atualização ser instalada (por exemplo, a sua aplicação pode desativar funcionalidades).

Observação

O estado obrigatório de uma atualização de pacote não é aplicado pela Microsoft, e o sistema operativo não fornece uma interface que indique aos utilizadores que uma atualização obrigatória da aplicação deve ser instalada. Os programadores devem usar a configuração obrigatória para forçar atualizações obrigatórias da aplicação no respetivo código.

Para marcar a submissão de um pacote como obrigatória:

  1. Inicie sessão no Centro de Parceiros e navegue até à página de visão geral da sua aplicação.
  2. Clique no nome da submissão que contém a atualização do pacote que pretende tornar obrigatória.
  3. Navegue até à página de Pacotes para a submissão. Perto do final desta página, selecione Tornar esta atualização obrigatória e depois escolha o dia e a hora em que a atualização do pacote se torna obrigatória. Esta opção aplica-se a todos os pacotes na submissão.

Para mais informações, consulte Pacotes de Upload da aplicação.

Observação

Se criares um voo em pacote, podes marcar os pacotes como obrigatórios usando uma interface semelhante na página Pacotes do voo. Neste caso, a atualização obrigatória do pacote aplica-se apenas aos clientes que fazem parte do grupo de voo.

Exemplo de código para pacotes obrigatórios

O seguinte exemplo de código demonstra como determinar se algum pacote de atualização é obrigatório. Normalmente, deve fazer um downgrade da sua experiência de aplicação de forma elegante para o utilizador caso uma atualização obrigatória de pacote não seja descarregada ou instalada com sucesso.

private StoreContext context = null;

// Downloads and installs package updates in separate steps.
public async Task DownloadAndInstallAllUpdatesAsync()
{
    if (context == null)
    {
        context = StoreContext.GetDefault();
    }  

    // Get the updates that are available.
    IReadOnlyList<StorePackageUpdate> updates =
        await context.GetAppAndOptionalStorePackageUpdatesAsync();

    if (updates.Count != 0)
    {
        // Download the packages.
        bool downloaded = await DownloadPackageUpdatesAsync(updates);

        if (downloaded)
        {
            // Install the packages.
            await InstallPackageUpdatesAsync(updates);
        }
    }
}

// Helper method for downloading package updates.
private async Task<bool> DownloadPackageUpdatesAsync(IEnumerable<StorePackageUpdate> updates)
{
    bool downloadedSuccessfully = false;

    IAsyncOperationWithProgress<StorePackageUpdateResult, StorePackageUpdateStatus> downloadOperation =
        this.context.RequestDownloadStorePackageUpdatesAsync(updates);

    // The Progress async method is called one time for each step in the download process for each
    // package in this request.
    downloadOperation.Progress = async (asyncInfo, progress) =>
    {
        await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
        () =>
        {
            downloadProgressBar.Value = progress.PackageDownloadProgress;
        });
    };

    StorePackageUpdateResult result = await downloadOperation.AsTask();

    switch (result.OverallState)
    {
        case StorePackageUpdateState.Completed:
            downloadedSuccessfully = true;
            break;
        default:
            // Get the failed updates.
            var failedUpdates = result.StorePackageUpdateStatuses.Where(
                status => status.PackageUpdateState != StorePackageUpdateState.Completed);

            // See if any failed updates were mandatory
            if (updates.Any(u => u.Mandatory && failedUpdates.Any(
                failed => failed.PackageFamilyName == u.Package.Id.FamilyName)))
            {
                // At least one of the updates is mandatory. Perform whatever actions you
                // want to take for your app: for example, notify the user and disable
                // features in your app.
                HandleMandatoryPackageError();
            }
            break;
    }

    return downloadedSuccessfully;
}

// Helper method for installing package updates.
private async Task InstallPackageUpdatesAsync(IEnumerable<StorePackageUpdate> updates)
{
    IAsyncOperationWithProgress<StorePackageUpdateResult, StorePackageUpdateStatus> installOperation =
        this.context.RequestDownloadAndInstallStorePackageUpdatesAsync(updates);

    // The package updates were already downloaded separately, so this method skips the download
    // operation and only installs the updates; no download progress notifications are provided.
    StorePackageUpdateResult result = await installOperation.AsTask();

    switch (result.OverallState)
    {
        case StorePackageUpdateState.Completed:
            break;
        default:
            // Get the failed updates.
            var failedUpdates = result.StorePackageUpdateStatuses.Where(
                status => status.PackageUpdateState != StorePackageUpdateState.Completed);

            // See if any failed updates were mandatory
            if (updates.Any(u => u.Mandatory && failedUpdates.Any(failed => failed.PackageFamilyName == u.Package.Id.FamilyName)))
            {
                // At least one of the updates is mandatory, so tell the user.
                HandleMandatoryPackageError();
            }
            break;
    }
}

// Helper method for handling the scenario where a mandatory package update fails to
// download or install. Add code to this method to perform whatever actions you want
// to take, such as notifying the user and disabling features in your app.
private void HandleMandatoryPackageError()
{
}

Desinstalar pacotes opcionais

A partir do Windows 10, versão 1803, pode usar os métodos RequestUninstallStorePackageAsync ou RequestUninstallStorePackageByStoreIdAsync para desinstalar um pacote opcional (incluindo um pacote DLC) para a aplicação atual. Por exemplo, se tiver uma aplicação com conteúdo instalado através de pacotes opcionais, pode querer fornecer uma interface que permita aos utilizadores desinstalar os pacotes opcionais para libertar espaço em disco.

O exemplo de código seguinte demonstra como chamar o RequestUninstallStorePackageAsync. Este exemplo assume:

  • O ficheiro de código contém uma instrução using dos espaços de nomes Windows.Services.Store e System.Threading.Tasks.
  • A aplicação é para um único utilizador que funciona apenas no contexto do utilizador que a lançou. Para uma aplicação multiutilizador, use o método GetForUser para obter um objeto StoreContext em vez do método GetDefault .
public async Task UninstallPackage(Windows.ApplicationModel.Package package)
{
    if (context == null)
    {
        context = StoreContext.GetDefault();
    }

    IAsyncOperation<StoreUninstallStorePackageResult> uninstallOperation =
        context.RequestUninstallStorePackageAsync(package);

    // At this point, you can update your app UI to show that the package
    // is installing.

    uninstallOperation.Completed += (asyncInfo, status) =>
    {
        StoreUninstallStorePackageResult result = uninstallOperation.GetResults();
        switch (result.Status)
        {
            case StoreUninstallStorePackageStatus.Succeeded:
                {
                    // Update your app UI to show the package as uninstalled.
                    break;
                }
            default:
                {
                    // Update your app UI to show that the package uninstall failed.
                    break;
                }
        }
    };
}

Obtenha informações para a fila de download

A partir do Windows 10, versão 1803, pode usar os métodos GetAssociatedStoreQueueItemsAsync e GetStoreQueueItemsAsync para obter informações sobre os pacotes que estão na fila atual de download e instalação a partir da Loja. Estes métodos são úteis se a sua aplicação ou jogo suportar grandes pacotes opcionais (incluindo DLCs) que podem demorar horas ou dias a descarregar e instalar, e quiser gerir de forma elegante o caso em que um cliente feche a sua aplicação ou jogo antes de terminar o processo de download e instalação. Quando o cliente iniciar novamente a sua aplicação ou jogo, o seu código pode usar estes métodos para obter informações sobre o estado dos pacotes que ainda estão na fila de download e instalação, para que possa mostrar o estado de cada pacote ao cliente.

O exemplo de código seguinte demonstra como chamar o GetAssociatedStoreQueueItemsAsync para obter a lista de atualizações de pacotes em curso para a aplicação atual e obter informações de estado de cada pacote. Este exemplo assume:

  • O ficheiro de código contém uma instrução using dos espaços de nomes Windows.Services.Store e System.Threading.Tasks.
  • A aplicação é para um único utilizador que funciona apenas no contexto do utilizador que a lançou. Para uma aplicação multiutilizador, use o método GetForUser para obter um objeto StoreContext em vez do método GetDefault .

Observação

Os métodos MarkUpdateInProgressInUI,RemoveItemFromUI,MarkInstallCompleteInUI, MarkInstallErrorInUI e MarkInstallPausedInUI chamados pelo código deste exemplo são métodos provisórios que devem ser implementados conforme necessário de acordo com o design da sua própria aplicação.

private StoreContext context = null;

private async Task GetQueuedInstallItemsAndBuildInitialStoreUI()
{
    if (context == null)
    {
        context = StoreContext.GetDefault();
    }

    // Get the Store packages in the install queue.
    IReadOnlyList<StoreQueueItem> storeUpdateItems = await context.GetAssociatedStoreQueueItemsAsync();

    foreach (StoreQueueItem storeItem in storeUpdateItems)
    {
        // In this example we only care about package updates.
        if (storeItem.InstallKind != StoreQueueItemKind.Update)
            continue;

        StoreQueueItemStatus currentStatus = storeItem.GetCurrentStatus();
        StoreQueueItemState installState = currentStatus.PackageInstallState;
        StoreQueueItemExtendedState extendedInstallState =
            currentStatus.PackageInstallExtendedState;

        // Handle the StatusChanged event to display current status to the customer.
        storeItem.StatusChanged += StoreItem_StatusChanged;

        switch (installState)
        {
            // Download and install are still in progress, so update the status for this  
            // item and provide the extended state info. The following methods are not
            // implemented in this example; you should implement them as needed for your
            // app's UI.
            case StoreQueueItemState.Active:
                MarkUpdateInProgressInUI(storeItem, extendedInstallState);
                break;
            case StoreQueueItemState.Canceled:
                RemoveItemFromUI(storeItem);
                break;
            case StoreQueueItemState.Completed:
                MarkInstallCompleteInUI(storeItem);
                break;
            case StoreQueueItemState.Error:
                MarkInstallErrorInUI(storeItem);
                break;
            case StoreQueueItemState.Paused:
                MarkInstallPausedInUI(storeItem, installState, extendedInstallState);
                break;
        }
    }
}

private void StoreItem_StatusChanged(StoreQueueItem sender, object args)
{
    StoreQueueItemStatus currentStatus = sender.GetCurrentStatus();
    StoreQueueItemState installState = currentStatus.PackageInstallState;
    StoreQueueItemExtendedState extendedInstallState = currentStatus.PackageInstallExtendedState;

    switch (installState)
    {
        // Download and install are still in progress, so update the status for this  
        // item and provide the extended state info. The following methods are not
        // implemented in this example; you should implement them as needed for your
        // app's UI.
        case StoreQueueItemState.Active:
            MarkUpdateInProgressInUI(sender, extendedInstallState);
            break;
        case StoreQueueItemState.Canceled:
            RemoveItemFromUI(sender);
            break;
        case StoreQueueItemState.Completed:
            MarkInstallCompleteInUI(sender);
            break;
        case StoreQueueItemState.Error:
            MarkInstallErrorInUI(sender);
            break;
        case StoreQueueItemState.Paused:
            MarkInstallPausedInUI(sender, installState, extendedInstallState);
            break;
    }
}