从代码更新非 Store 发布的应用包
以 MSIX 形式交付应用时,可通过编程方式启动应用程序的更新。 如果将应用部署到 Store 外部,则只需在服务器上检查是否有新版应用并安装新版本。 应用更新的方式取决于是否使用应用安装程序文件部署应用包。 若要从代码应用更新,应用包必须声明 packageManagement
功能。 请注意,对于跨发布者方案,必须声明该功能,但管理自己的应用应该无需声明。
本文提供的示例演示如何在程序包清单中声明 packageManagement
功能,以及如何从代码应用更新。 第一部分介绍如何使用应用安装程序文件来执行此操作,而第二部分介绍如何在不使用应用安装程序文件时执行此操作。 最后一部分将介绍如何在应用更新后确保应用重启。
将 PackageManagement 功能添加到包清单
若要使用 PackageManager
API,应用必须在包清单中声明 packageManagement
受限功能。
<Package>
...
<Capabilities>
<rescap:Capability Name="packageManagement" />
</Capabilities>
...
</Package>
使用应用安装程序文件更新部署的包
如果你使用应用安装程序文件部署应用程序,则你执行的任何代码驱动的更新都必须使用应用安装程序文件 API。 这样做可确保定期应用安装程序文件更新将继续工作。 若要从代码初始化应用安装程序的更新,可以使用 PackageManager.AddPackageByAppInstallerFileAsync 或 PackageManager.RequestAddPackageByAppInstallerFileAsync。 可以使用 Package.CheckUpdateAvailabilityAsync API 检查更新是否可用。 下面是示例代码:
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;
}
}
在不使用应用安装程序文件的情况下更新部署的包
检查服务器上的更新
如果未使用应用安装程序文件来部署应用包,则第一步是直接检查是否有新版本的应用程序可用。 以下示例检查服务器上的包版本是否大于当前版本的应用(此示例指的是用于演示的测试服务器)。
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();
}
}
注意
targetPackageFileName
代表打包的应用的全名。 (示例:Contoso.HeadTrax_1.0.0.0_x64__PublisherHash)
应用更新
确定更新已发布后,可以让其排队等待下载并使用 AddPackageAsync API 进行安装。 只要主包已经安装在设备上,则也应该可以安装可选包。 下次关闭应用时,会应用此更新。 应用重启后,新版本将可供用户使用。 下面是示例代码:
// 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
);
}
}
更新后自动重启应用
如果应用程序是 UWP 应用,则在应用更新时传入 AddPackageByAppInstallerOptions.ForceApplicationShutdown 或 AddPackageOptions.ForceTargetAppShutdown 应安排应用在关闭 + 更新后重启。 对于非 UWP 应用,需要在应用更新之前调用 RegisterApplicationRestart。
在开始关闭应用之前,必须先调用 RegisterApplicationRestart。 下面是使用互操作服务以 C# 调用原生方法的示例:
// Register the active instance of an application for restart in your Update method
uint res = RelaunchHelper.RegisterApplicationRestart(null, RelaunchHelper.RestartFlags.NONE);
使用帮助程序类以 C# 调用原生 RegisterApplicationRestart 方法的示例:
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
}
}