Pobieranie i instalowanie aktualizacji pakietów ze Sklepu

Począwszy od Windows 10 w wersji 1607, można użyć metod klasy StoreContext w przestrzeni nazw Windows.Services.Store programowo sprawdzić dostępność aktualizacji pakietów dla bieżącej aplikacji z Microsoft Store i pobrać i zainstalować zaktualizowane pakiety. Możesz również wykonywać zapytania dotyczące pakietów oznaczonych jako obowiązkowe w Centrum partnerskim i wyłączyć funkcje w aplikacji do momentu zainstalowania obowiązkowej aktualizacji.

Dodatkowe metody StoreContext wprowadzone w Windows 10, wersja 1803 umożliwiają pobieranie i instalowanie aktualizacji pakietów w trybie dyskretnym (bez wyświetlania interfejsu użytkownika powiadomienia dla użytkownika), odinstalowanie opcjonalnego pakietu i uzyskanie informacji o pakietach w kolejce pobierania i instalowania aplikacji.

Te funkcje ułatwiają automatyczne aktualizowanie bazy użytkowników przy użyciu najnowszej wersji aplikacji, opcjonalnych pakietów i powiązanych usług w Sklepie.

Note

Interfejsy API Windows.Services.Store wymagają tożsamości pakietu i działają w przypadku każdej aplikacji spakowanej jako MSIX i rozpowszechnianej za pośrednictwem Microsoft Store, w tym aplikacji WinUI 3 utworzonych przy użyciu zestawu Zestaw SDK do aplikacji systemu Windows. Przykłady kodu w tym artykule zostały pierwotnie napisane dla platformy UWP. Jeśli dostosowujesz je do aplikacji WinUI 3, zastąp element this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, ...) elementem DispatcherQueue.GetForCurrentThread().TryEnqueue(...), a element MessageDialog (który w WinUI 3 wymaga interoperacyjności HWND) elementem ContentDialog lub użyj WinRT.Interop.InitializeWithWindow.Initialize, aby skojarzyć okno dialogowe z uchwytem okna.

Pobieranie i instalowanie aktualizacji pakietów przy użyciu uprawnień użytkownika

W tym przykładzie kodu pokazano, jak użyć metody GetAppAndOptionalStorePackageUpdatesAsync , aby odnaleźć wszystkie dostępne aktualizacje pakietów ze Sklepu, a następnie wywołać metodę RequestDownloadAndInstallStorePackageUpdatesAsync w celu pobrania i zainstalowania aktualizacji. W przypadku używania tej metody do pobierania i instalowania aktualizacji system operacyjny wyświetla okno dialogowe z pytaniem o uprawnienie użytkownika przed pobraniem aktualizacji.

Note

Te metody obsługują wymagane i opcjonalne pakiety dla aplikacji. Opcjonalne pakiety są przydatne w przypadku dodatków zawartości do pobrania (DLC), dzielenia dużej aplikacji pod kątem ograniczeń rozmiaru lub wysyłania dodatkowej zawartości niezależnie od podstawowej aplikacji. Aby uzyskać zgodę na przesłanie do Sklepu aplikacji korzystającej z opcjonalnych pakietów (w tym dodatków DLC), zobacz pomoc techniczna dla deweloperów systemu Windows.

W tym przykładzie kodu przyjęto założenie:

  • Kod jest uruchamiany w kontekście strony XAML platformy UWP (Windows.UI.Xaml.Controls.Page). Te przykłady zostały napisane dla platformy UWP; zobacz uwagę na początku tego artykułu, aby uzyskać informacje o dostosowaniach dla WinUI 3.
  • Strona zawiera pasek postępu o nazwie downloadProgressBar , aby zapewnić stan operacji pobierania.
  • Plik kodu zawiera instrukcję using dla przestrzeni nazw Windows.Services.Store, System.Threading.Tasks i Windows.UI.Popups.
  • Aplikacja to aplikacja pojedynczego użytkownika, która działa tylko w kontekście użytkownika, który uruchomił aplikację. W przypadku aplikacji z wieloma użytkownikami użyj metody GetForUser , aby uzyskać obiekt StoreContext zamiast metody 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();
        }
    }
}

Note

Aby pobrać tylko (ale nie zainstalować) dostępne aktualizacje pakietu, użyj metody RequestDownloadStorePackageUpdatesAsync .

Wyświetlanie informacji o postępie pobierania i instalowania

Po wywołaniu metody RequestDownloadStorePackageUpdatesAsync lub RequestDownloadAndInstallStorePackageUpdatesAsync można przypisać procedurę obsługi postępu wywoływaną jednorazowo dla każdego kroku procesu pobierania (lub pobierania i instalowania) dla każdego pakietu w tym żądaniu. Procedura obsługi odbiera obiekt StorePackageUpdateStatus zawierający informacje o pakiecie aktualizacji, który zgłosił powiadomienie o postępie. W poprzednim przykładzie użyto pola PackageDownloadProgress obiektu StorePackageUpdateStatus w celu wyświetlenia postępu procesu pobierania i instalacji.

Należy pamiętać, że po wywołaniu metody RequestDownloadAndInstallStorePackageUpdatesAsync w celu pobrania i zainstalowania aktualizacji pakietów w ramach jednej operacji pole PackageDownloadProgress zwiększa się z zakresu od 0,0 do 0,8 podczas procesu pobierania pakietu, a następnie zwiększa się z zakresu od 0,8 do 1,0 podczas instalacji. W związku z tym, jeśli przypiszesz wartość procentową wyświetlaną w niestandardowym interfejsie postępu bezpośrednio do wartości pola PackageDownloadProgress, interfejs użytkownika wyświetli 80%, gdy pakiet zakończy pobieranie, a system operacyjny wyświetli okno dialogowe instalacji. Jeśli chcesz, aby niestandardowy interfejs postępu wyświetlał 100% po pobraniu pakietu i gdy będzie on gotowy do zainstalowania, możesz zmodyfikować kod tak, aby ustawiał wartość 100% w interfejsie postępu, gdy pole PackageDownloadProgress osiągnie wartość 0,8.

Pobieranie i instalowanie aktualizacji pakietów w trybie dyskretnym

Począwszy od Windows 10 w wersji 1803, można użyć metod TrySilentDownloadStorePackageUpdatesAsync i TrySilentDownloadAndInstallStorePackageUpdatesAsync w celu dyskretnego pobierania i instalowania aktualizacji pakietów bez wyświetlania użytkownikowi interfejsu użytkownika powiadomienia. Ta operacja powiedzie się tylko wtedy, gdy użytkownik włączył automatyczne ustawienie Aktualizuj aplikacje w Sklepie, a użytkownik nie znajduje się w sieci taryfowej. Przed wywołaniem tych metod można najpierw sprawdzić właściwość CanSilentlyDownloadStorePackageUpdates , aby określić, czy te warunki są obecnie spełnione.

W tym przykładzie kodu pokazano, jak za pomocą metody GetAppAndOptionalStorePackageUpdatesAsync odnaleźć wszystkie dostępne aktualizacje pakietów, a następnie wywołać metodę TrySilentDownloadStorePackageUpdatesAsync i TrySilentDownloadAndInstallStorePackageUpdatesAsync , aby pobrać i zainstalować aktualizacje w trybie dyskretnym.

W tym przykładzie kodu przyjęto założenie:

  • Plik kodu zawiera instrukcję using dla przestrzeni nazw Windows.Services.Store i System.Threading.Tasks.
  • Aplikacja to aplikacja pojedynczego użytkownika, która działa tylko w kontekście użytkownika, który uruchomił aplikację. W przypadku aplikacji z wieloma użytkownikami użyj metody GetForUser , aby uzyskać obiekt StoreContext zamiast metody GetDefault .

Note

Metody IsNowAGoodTimeToRestartApp, RetryDownloadAndInstallLater i RetryInstallLater wywoływane przez kod w tym przykładzie to metody zastępcze, które mają być implementowane zgodnie z potrzebami zgodnie z projektem własnej aplikacji.

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

Obowiązkowe aktualizacje pakietów

Podczas tworzenia przesyłania pakietu w Centrum partnerskim dla aplikacji, która jest przeznaczona dla Windows 10 w wersji 1607 lub nowszej, możesz oznaczyć pakiet jako obowiązkowy oraz datę i godzinę, o której stanie się obowiązkowy. Gdy ta właściwość jest ustawiona i aplikacja wykryje, że aktualizacja pakietu jest dostępna, aplikacja może określić, czy pakiet aktualizacji jest obowiązkowy i zmienić jego zachowanie do momentu zainstalowania aktualizacji (na przykład aplikacja może wyłączyć funkcje).

Note

Obowiązkowy stan aktualizacji pakietu nie jest wymuszany przez Microsoft, a system operacyjny nie udostępnia interfejsu użytkownika wskazującego użytkownikom, że należy zainstalować obowiązkową aktualizację aplikacji. Deweloperzy mają używać obowiązkowego ustawienia w celu wymuszania obowiązkowych aktualizacji aplikacji we własnym kodzie.

Aby oznaczyć przesyłanie pakietu jako obowiązkowe:

  1. Zaloguj się do Centrum partnerskiego i przejdź do strony przeglądu aplikacji.
  2. Kliknij nazwę przesłania zawierającego aktualizację pakietu, która ma być obowiązkowa.
  3. Przejdź do strony Pakiety na potrzeby przesyłania. W dolnej części tej strony wybierz pozycję Ustaw tę aktualizację jako obowiązkową , a następnie wybierz dzień i godzinę, w której aktualizacja pakietu stanie się obowiązkowa. Ta opcja dotyczy wszystkich pakietów w zgłoszeniu.

Aby uzyskać więcej informacji, zobacz Przekazywanie pakietów aplikacji.

Note

Jeśli tworzysz pakiet lotu, możesz oznaczyć pakiety jako obowiązkowe za pomocą podobnego interfejsu użytkownika na stronie Pakiety dla lotu. W takim przypadku obowiązkowa aktualizacja pakietu ma zastosowanie tylko do klientów, którzy są częścią grupy lotów.

Przykład kodu dla obowiązkowych pakietów

Poniższy przykład kodu pokazuje, jak określić, czy jakiekolwiek pakiety aktualizacji są obowiązkowe. Zazwyczaj należy zapewnić użytkownikowi ograniczoną funkcjonalność aplikacji, jeśli pobranie lub zainstalowanie obowiązkowej aktualizacji pakietu nie powiedzie się.

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

Odinstalowywanie opcjonalnych pakietów

Począwszy od Windows 10 w wersji 1803, można użyć metody RequestUninstallStorePackageAsync lub RequestUninstallStorePackageByStoreIdAsync, aby odinstalować opcjonalny pakiet (w tym pakiet DLC) dla bieżącej aplikacji. Jeśli na przykład masz aplikację z zawartością zainstalowaną za pośrednictwem opcjonalnych pakietów, możesz podać interfejs użytkownika, który umożliwia użytkownikom odinstalowanie opcjonalnych pakietów w celu zwolnienia miejsca na dysku.

W poniższym przykładzie kodu pokazano, jak wywołać metodę RequestUninstallStorePackageAsync. W tym przykładzie przyjęto założenie:

  • Plik kodu zawiera instrukcję using dla przestrzeni nazw Windows.Services.Store i System.Threading.Tasks.
  • Aplikacja to aplikacja pojedynczego użytkownika, która działa tylko w kontekście użytkownika, który uruchomił aplikację. W przypadku aplikacji z wieloma użytkownikami użyj metody GetForUser , aby uzyskać obiekt StoreContext zamiast metody 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;
                }
        }
    };
}

Pobierz informacje o kolejce pobierania

Począwszy od Windows 10 w wersji 1803, możesz użyć metod GetAssociatedStoreQueueItemsAsync i GetStoreQueueItemsAsync, aby uzyskać informacje o pakietach, które znajdują się w bieżącej kolejce pobierania i instalacji ze Sklepu. Te metody są przydatne, jeśli aplikacja lub gra obsługuje duże opcjonalne pakiety (w tym biblioteki DLL), które mogą potrwać kilka godzin lub dni do pobrania i zainstalowania, i chcesz bezpiecznie obsłużyć przypadek, w którym klient zamyka aplikację lub grę przed zakończeniem pobierania i instalacji. Gdy klient ponownie uruchomi aplikację lub grę, kod może użyć tych metod, aby uzyskać informacje o stanie pakietów, które są nadal w kolejce pobierania i instalacji, dzięki czemu można wyświetlić stan każdego pakietu klientowi.

W poniższym przykładzie kodu pokazano, jak wywołać metodę GetAssociatedStoreQueueItemsAsync , aby pobrać listę aktualizacji pakietów w toku dla bieżącej aplikacji i pobrać informacje o stanie dla każdego pakietu. W tym przykładzie przyjęto założenie:

  • Plik kodu zawiera instrukcję using dla przestrzeni nazw Windows.Services.Store i System.Threading.Tasks.
  • Aplikacja to aplikacja pojedynczego użytkownika, która działa tylko w kontekście użytkownika, który uruchomił aplikację. W przypadku aplikacji z wieloma użytkownikami użyj metody GetForUser , aby uzyskać obiekt StoreContext zamiast metody GetDefault .

Note

Metody MarkUpdateInProgressInUI, RemoveItemFromUI, MarkInstallCompleteInUI, MarkInstallErrorInUI i MarkInstallPausedInUI wywoływane przez kod w tym przykładzie są metodami zastępczymi, przeznaczonymi do zaimplementowania w razie potrzeby zgodnie z założeniami własnej aplikacji.

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