Поделиться через


Скачивание и установка обновлений пакетов из Магазина

Начиная с Windows 10 версии 1607, можно использовать методы класса StoreContext в пространстве имен Windows.Services.Store, чтобы программно проверить наличие обновлений пакета для текущего приложения из Microsoft Store, а также скачать и установить обновленные пакеты. Вы также можете запросить пакеты, помеченные как обязательные в Центре партнеров, и отключить функциональные возможности в приложении до тех пор, пока не будет установлено обязательное обновление.

Дополнительные методы StoreContext, представленные в Windows 10 версии 1803, позволяют автоматически загружать и устанавливать обновления пакетов (без отображения пользовательского интерфейса уведомления пользователю), удаления необязательного пакетаи получения сведений о пакетах в очереди загрузки и установки приложения.

Эти функции помогают автоматически обновлять базу пользователей с последней версией приложения, необязательными пакетами и связанными службами в Магазине.

Скачивание и установка обновлений пакетов с разрешением пользователя

В этом примере кода показано, как использовать метод GetAppAndOptionalStorePackageUpdatesAsync для обнаружения всех доступных обновлений пакетов из Магазина, а затем вызова метода RequestDownloadAndInstallStorePackageUpdatesAsync для скачивания и установки обновлений. При использовании этого метода для скачивания и установки обновлений ОС отображается диалоговое окно, которое запрашивает разрешение пользователя перед загрузкой обновлений.

Заметка

Эти методы поддерживают необходимые и необязательные пакеты для вашего приложения. Необязательные пакеты полезны для дополнений, загружаемых в виде DLC, управления размером большого приложения или доставки дополнительного содержимого отдельно от основного приложения. Чтобы получить разрешение на отправку приложения, использующего необязательные пакеты (включая надстройки DLC) в магазин, см. поддержку разработчиков Windows.

В этом примере кода предполагается:

  • Код выполняется в контексте страницы .
  • Страница содержит ProgressBar с именем downloadProgressBar для отображения статуса операции скачивания.
  • Файл кода содержит с помощью инструкции для Windows.Services.Store, Windows.Threading.Tasksи пространства имен Windows.UI.Popups.
  • Приложение — это однопользовательское приложение, которое запускается только в контексте пользователя, запускающего приложение. Для многопользовательского приложения используйте метод GetForUser для получения объекта StoreContext вместо метода 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();
        }
    }
}

Заметка

Чтобы скачать только (но не установить) доступные обновления пакетов, используйте метод RequestDownloadStorePackageUpdatesAsync.

Отображение сведений о ходе скачивания и установки

При вызове метода RequestDownloadStorePackageUpdatesAsync или RequestDownloadAndInstallStorePackageUpdatesAsync можно назначить обработчик Progress, который вызывается один раз для каждого шага скачивания (или скачивания и установки) для каждого пакета в этом запросе. Обработчик получает объект StorePackageUpdateStatus, предоставляющий сведения о пакете обновления, вызвавшим уведомление о ходе выполнения. В предыдущем примере используется поле PackageDownloadProgress объекта StorePackageUpdateStatus для отображения хода выполнения процесса скачивания и установки.

Помните, что при вызове RequestDownloadAndInstallStorePackageUpdatesAsync для загрузки и установки обновлений пакетов в одной операции поле PackageDownloadProgress увеличивается с 0,0 до 0,8 во время загрузки пакета, а затем увеличивается с 0,8 до 1,0 во время установки. Таким образом, если вы сопоставляете процент, отображаемый в пользовательском интерфейсе хода выполнения, непосредственно со значением поля PackageDownloadProgress, пользовательский интерфейс будет отображать 80% после завершения загрузки пакета, а ОС отобразит диалоговое окно установки. Если вы хотите, чтобы ваш пользовательский интерфейс прогресса отображал 100% при загрузке и готовности пакета для установки, вы можете изменить код так, чтобы назначить интерфейсу значение 100%, когда поле PackageDownloadProgress достигает 0,8.

Скачивание и установка обновлений пакетов без уведомлений

Начиная с Windows 10 версии 1803, можно использовать методы TrySilentDownloadStorePackageUpdatesAsync и TrySilentDownloadAndInstallStorePackageUpdatesAsync для автоматического скачивания и установки обновлений пакетов без отображения интерфейса уведомлений пользователю. Эта операция будет выполнена успешно, только если пользователь включил настройку автоматического обновления приложений в Магазине приложений и не подключен к сети с учётом трафика. Перед вызовом этих методов сначала можно проверить свойство CanSilentlyDownloadStorePackageUpdates, чтобы определить, выполнены ли эти условия.

В этом примере кода показано, как использовать метод GetAppAndOptionalStorePackageUpdatesAsync для обнаружения всех доступных обновлений пакетов, а затем вызова метода TrySilentDownloadStorePackageUpdatesAsync и TrySilentDownloadAndInstallStorePackageUpdatesAsync для загрузки и установки обновлений автоматически.

В этом примере кода предполагается:

  • Файл кода содержит инструкцию using для пространств имен Windows.Services.Store и System.Threading.Tasks.
  • Приложение — это однопользовательское приложение, которое запускается только в контексте пользователя, запускающего приложение. Для многопользовательского приложения используйте метод GetForUser для получения объекта StoreContext вместо метода GetDefault.

Заметка

IsNowAGoodTimeToRestartApp, RetryDownloadAndInstallLaterи RetryInstallLater — это заполнительные методы, которые вызываются кодом в этом примере и должны быть реализованы при необходимости в соответствии с дизайном вашего приложения.

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

Обязательные обновления пакетов

При создании отправки пакета в Центре партнеров для приложения, предназначенного для Windows 10 версии 1607 или более поздней, можно пометить пакет как обязательный и дату и время, в течение которого он становится обязательным. Если это свойство задано и приложение обнаруживает, что обновление пакета доступно, ваше приложение может определить, является ли пакет обновления обязательным и изменять его поведение до установки обновления (например, приложение может отключить функции).

Заметка

Обязательное состояние обновления пакета не применяется корпорацией Майкрософт, и ОС не предоставляет пользовательский интерфейс для указания пользователям, что необходимо установить обязательное обновление приложения. Разработчики должны использовать обязательные настройки для принудительного обновления приложений в своем коде.

Чтобы пометить отправку пакета как обязательную:

  1. Войдите в центр партнеров и перейдите на страницу обзора приложения.
  2. Щелкните имя отправки, содержащей обновление пакета, которое требуется сделать обязательным.
  3. Перейдите на страницу пакетов для отправки. В нижней части этой страницы выберите Сделать это обновление обязательным, а затем выберите день и время, в течение которого обновление пакета становится обязательным. Этот параметр применяется ко всем пакетам UWP в отправке.

Дополнительные сведения см. в разделе Отправка пакетов приложений.

Заметка

При создании пакетного рейса , можно пометить пакеты как обязательные, используя аналогичный пользовательский интерфейс на странице пакетов для рейса. В этом случае обязательное обновление пакета применяется только к клиентам, которые входят в группу полетов.

Пример кода для обязательных пакетов

В следующем примере кода показано, как определить, являются ли пакеты обновления обязательными. Как правило, вы должны снизить уровень качества работы приложения безболезненно для пользователя, если обязательное обновление пакета не удалось скачать или установить.

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()
{
}

Удаление необязательных пакетов

Начиная с Windows 10 версии 1803, можно использовать методы RequestUninstallStorePackageAsync или RequestUninstallStorePackageByStoreIdAsync для удаления необязательного пакета (включая пакет DLC) для текущего приложения. Например, если у вас есть приложение с содержимым, установленным с помощью необязательных пакетов, может потребоваться предоставить пользовательский интерфейс, позволяющий пользователям удалять необязательные пакеты для освобождения места на диске.

В следующем примере кода показано, как вызывать RequestUninstallStorePackageAsync. В этом примере предполагается:

  • Файл кода содержит с помощью инструкции для пространств имен Windows.Services.Store и System.Threading.Tasks.
  • Приложение — это однопользовательское приложение, которое запускается только в контексте пользователя, запускающего приложение. Для многопользовательского приложения используйте метод GetForUser для получения объекта StoreContext вместо метода GetDefault.
public async Task UninstallPackage(Windows.ApplicationModel.Package package)
{
    if (context == null)
    {
        context = StoreContext.GetDefault();
    }

    var storeContext = StoreContext.GetDefault();
    IAsyncOperation<StoreUninstallStorePackageResult> uninstallOperation =
        storeContext.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;
                }
        }
    };
}

Получение сведений о очереди загрузки

Начиная с Windows 10 версии 1803, можно использовать методы GetAssociatedStoreQueueItemsAsync и GetStoreQueueItemsAsync, чтобы получить сведения о пакетах, которые находятся в текущей очереди загрузки и установки из Магазина. Эти методы полезны, если ваше приложение или игра поддерживает большие необязательные пакеты (включая библиотеки DLL), которые могут занять несколько часов или дней для скачивания и установки, и вы хотите корректно обработать ситуацию, когда клиент закрывает приложение или игру до завершения загрузки и установки. Когда клиент снова запускает приложение или игру, код может использовать эти методы для получения сведений о состоянии пакетов, которые по-прежнему находятся в очереди загрузки и установки, чтобы вы могли отобразить состояние каждого пакета клиенту.

В следующем примере кода показано, как вызвать GetAssociatedStoreQueueItemsAsync, чтобы получить список обновлений пакета для текущего приложения и получить сведения о состоянии для каждого пакета. В этом примере предполагается:

  • Файл кода включает инструкцию using для пространств имён Windows.Services.Store и System.Threading.Tasks.
  • Приложение — это однопользовательское приложение, которое запускается только в контексте пользователя, запускающего приложение. Для многопользовательского приложения используйте метод GetForUser для получения объекта StoreContext вместо метода GetDefault.

Заметка

Методы MarkUpdateInProgressInUI, RemoveItemFromUI, MarkInstallCompleteInUI, MarkInstallErrorInUIи MarkInstallPausedInUI, вызываемые кодом в этом примере, — это методы-заполнители, которые должны быть реализованы по мере необходимости в соответствии с проектом вашего собственного приложения.

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