Aggiornare i pacchetti di app pubblicati non nello Store dal codice

Quando distribuisci la tua app come pacchetto MSIX, puoi avviare un aggiornamento dell'applicazione a livello di codice. Se distribuisci l'app al di fuori dello Store, devi solo verificare che nel server sia disponibile una nuova versione dell'app e installarla. La modalità di applicazione dell'aggiornamento dipende dal fatto che si distribuisca o meno il pacchetto dell'app usando un file del programma di installazione app. Per applicare gli aggiornamenti dal codice, il pacchetto dell'app deve dichiarare la packageManagement funzionalità. Si noti che questo è necessario per lo scenario tra editori, ma la gestione della propria app deve funzionare senza dover dichiarare la funzionalità.

Questo articolo fornisce esempi che illustrano come dichiarare la packageManagement funzionalità nel manifesto del pacchetto e come applicare un aggiornamento dal codice. La prima sezione illustra come eseguire questa operazione se si usa il file del programma di installazione app e la seconda sezione descrive come eseguire questa operazione quando non si usa il file del programma di installazione app. L'ultima sezione illustra come assicurarsi che l'app venga riavviata dopo l'applicazione di un aggiornamento.

Aggiungere la funzionalità PackageManagement al manifesto del pacchetto

Per usare le API, l'app PackageManager deve dichiarare la packageManagementfunzionalità con restrizioni nel manifesto del pacchetto.

<Package>
...

  <Capabilities>
    <rescap:Capability Name="packageManagement" />
  </Capabilities>
  
...
</Package>

Aggiornamento dei pacchetti distribuiti con un file del programma di installazione app

Se si distribuisce l'applicazione usando il file del programma di installazione app, tutti gli aggiornamenti basati sul codice eseguiti devono usare le API del file del programma di installazione app. In questo modo si garantisce che gli aggiornamenti regolari dei file del programma di installazione app continueranno a funzionare. Per inizializzare un aggiornamento basato sul programma di installazione app dal codice, puoi usare PackageManager.AddPackageByAppInstallerFileAsync o PackageManager.RequestAddPackageByAppInstallerFileAsync. È possibile verificare se un aggiornamento è disponibile usando l'API Package.CheckUpdateAvailabilityAsync . Di seguito è riportato il codice di esempio:

using Windows.Management.Deployment;

public async void CheckForAppInstallerUpdatesAndLaunchAsync(string targetPackageFullName, PackageVolume packageVolume)
{
    // Get the current app's package for the current user.
    PackageManager pm = new PackageManager();
    Package package = pm.FindPackageForUser(string.Empty, targetPackageFullName);

    PackageUpdateAvailabilityResult result = await package.CheckUpdateAvailabilityAsync();
    switch (result.Availability)
    {
        case PackageUpdateAvailability.Available:
        case PackageUpdateAvailability.Required:
            //Queue up the update and close the current instance
            await pm.AddPackageByAppInstallerFileAsync(
            new Uri("https://trial3.azurewebsites.net/HRApp/HRApp.appinstaller"),
            AddPackageByAppInstallerOptions.ForceApplicationShutdown,
            packageVolume);
            break;
        case PackageUpdateAvailability.NoUpdates:
            // Close AppInstaller.
            await ConsolidateAppInstallerView();
            break;
        case PackageUpdateAvailability.Unknown:
        default:
            // Log and ignore error.
            Logger.Log($"No update information associated with app {targetPackageFullName}");
            // Launch target app and close AppInstaller.
            await ConsolidateAppInstallerView();
            break;
    }
}

Aggiornamento dei pacchetti distribuiti senza un file del programma di installazione app

Verificare la disponibilità di aggiornamenti nel server

Se non si usa il file del programma di installazione app per distribuire il pacchetto dell'app, il primo passaggio consiste nel verificare direttamente se è disponibile una nuova versione dell'applicazione. Nell'esempio seguente viene verificato se la versione del pacchetto in un server è successiva alla versione corrente dell'app. Questo esempio si riferisce a un server di prova a scopo dimostrativo.

using Windows.Management.Deployment;

//check for an update on my server
private async void CheckUpdate(object sender, TappedRoutedEventArgs e)
{
    WebClient client = new WebClient();
    Stream stream = client.OpenRead("https://trial3.azurewebsites.net/HRApp/Version.txt");
    StreamReader reader = new StreamReader(stream);
    var newVersion = new Version(await reader.ReadToEndAsync());
    Package package = Package.Current;
    PackageVersion packageVersion = package.Id.Version;
    var currentVersion = new Version(string.Format("{0}.{1}.{2}.{3}", packageVersion.Major, packageVersion.Minor, packageVersion.Build, packageVersion.Revision));

    //compare package versions
    if (newVersion.CompareTo(currentVersion) > 0)
    {
        var messageDialog = new MessageDialog("Found an update.");
        messageDialog.Commands.Add(new UICommand(
            "Update",
            new UICommandInvokedHandler(this.CommandInvokedHandler)));
        messageDialog.Commands.Add(new UICommand(
            "Close",
            new UICommandInvokedHandler(this.CommandInvokedHandler)));
        messageDialog.DefaultCommandIndex = 0;
        messageDialog.CancelCommandIndex = 1;
        await messageDialog.ShowAsync();
    } else
    {
        var messageDialog = new MessageDialog("Did not find an update.");
        await messageDialog.ShowAsync();
    }
}

Nota

è targetPackageFileName rappresentativo del nome completo dell'app in pacchetto. (Esempio: Contoso.HeadTrax_1.0.0.0_x64__PublisherHash)

Applicare l'aggiornamento

Dopo aver determinato che è disponibile un aggiornamento, è possibile accodarlo per il download e l'installazione usando l'API AddPackageAsync . Deve anche funzionare per installare un pacchetto facoltativo, purché il pacchetto principale sia già installato nel dispositivo. L'aggiornamento verrà applicato la volta successiva che l'app viene arrestata. Dopo il riavvio dell'app, la nuova versione sarà disponibile per l'utente. Di seguito è riportato il codice di esempio:


// Queue up the update and close the current app instance.
private async void CommandInvokedHandler(IUICommand command)
{
    if (command.Label == "Update")
    {
        PackageManager packagemanager = new PackageManager();
        await packagemanager.AddPackageAsync(
            new Uri("https://trial3.azurewebsites.net/HRApp/HRApp.msix"),
            null,
            AddPackageOptions.ForceApplicationShutdown
        );
    }
}

Riavvio automatico dell'app dopo un aggiornamento

Se l'applicazione è un'app UWP, passando AddPackageByAppInstallerOptions.ForceApplicationShutdown O AddPackageOptions.ForceTargetAppShutdown quando si applica un aggiornamento, l'app deve pianificare il riavvio dopo l'arresto e l'aggiornamento. Per le app non UWP devi chiamare RegisterApplicationRestart prima di applicare l'aggiornamento.

Devi chiamare RegisterApplicationRestart prima che l'app inizi l'arresto. Di seguito è riportato un esempio di utilizzo di servizi di interoperabilità per chiamare il metodo nativo in C#:

 // Register the active instance of an application for restart in your Update method
 uint res = RelaunchHelper.RegisterApplicationRestart(null, RelaunchHelper.RestartFlags.NONE);

Esempio della classe helper per chiamare il metodo RegisterApplicationRestart nativo in C#:

using System;
using System.Runtime.InteropServices;

namespace MyEmployees.Helpers
{
    class RelaunchHelper
    {
        #region Restart Manager Methods
        /// <summary>
        /// Registers the active instance of an application for restart.
        /// </summary>
        /// <param name="pwzCommandLine">
        /// A pointer to a Unicode string that specifies the command-line arguments for the application when it is restarted.
        /// The maximum size of the command line that you can specify is RESTART_MAX_CMD_LINE characters. Do not include the name of the executable
        /// in the command line; this function adds it for you.
        /// If this parameter is NULL or an empty string, the previously registered command line is removed. If the argument contains spaces,
        /// use quotes around the argument.
        /// </param>
        /// <param name="dwFlags">One of the options specified in RestartFlags</param>
        /// <returns>
        /// This function returns S_OK on success or one of the following error codes:
        /// E_FAIL for internal error.
        /// E_INVALIDARG if rhe specified command line is too long.
        /// </returns>
        [DllImport("kernel32.dll", CharSet = CharSet.Unicode)]
        internal static extern uint RegisterApplicationRestart(string pwzCommandLine, RestartFlags dwFlags);
        #endregion Restart Manager Methods

        #region Restart Manager Enums
        /// <summary>
        /// Flags for the RegisterApplicationRestart function
        /// </summary>
        [Flags]
        internal enum RestartFlags
        {
            /// <summary>None of the options below.</summary>
            NONE = 0,

            /// <summary>Do not restart the process if it terminates due to an unhandled exception.</summary>
            RESTART_NO_CRASH = 1,
            /// <summary>Do not restart the process if it terminates due to the application not responding.</summary>
            RESTART_NO_HANG = 2,
            /// <summary>Do not restart the process if it terminates due to the installation of an update.</summary>
            RESTART_NO_PATCH = 4,
            /// <summary>Do not restart the process if the computer is restarted as the result of an update.</summary>
            RESTART_NO_REBOOT = 8
        }
        #endregion Restart Manager Enums

    }
}