我正在使用打包为 MSIX 并通过 Microsoft Store 发布的 win32 桌面应用程序进行测试。我正在尝试使用 TrySilentDownloadAndInstallStorePackageUpdatesAsync 来更新应用程序,这似乎确实有效,但在安装更新后立即退出并且不会重新启动应用程序。
MS 文档似乎表明此函数将重新启动应用程序(正如恰当命名的函数 IsNowAGoodTimeToRestartApp 所建议的那样): https://learn.microsoft.com/en-us/windows/uwp/packaging/self-install-package-updates
然而,这不是我所观察到的。调用后的调试语句似乎都没有命中,因此看起来确实正在终止应用程序;它只是没有重新启动它。
寻找替代方案,似乎有一个名为 RegisterApplicationRestart 的旧 win32 API: https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-registerapplicationrestart
但它有一个警告: “为了防止周期性重启,系统只会在应用程序运行至少 60 秒时才会重新启动该应用程序。”
这不太理想;我们想要完成的是快速检查更新、安装它们并重新启动,因此在下次运行时应该没有要应用的更新,也不需要重新启动。在这里等待 60 秒违背了快速检查的目的。
有哪些替代方案?有什么方法可以让应用程序在安装 MS Store 更新后重新启动吗?
(顺便说一句:有没有办法在不经过认证过程的情况下测试 MS 商店更新?这可能需要几个小时,这完全消除了写入-构建-测试周期。)。
IsNowAGoodTimeToRestartApp
方法只是一个占位符,它代表您需要执行的逻辑来检查应用程序是否准备好安装更新。
StoreContext.TrySilentDownloadAndInstallStorePackageUpdatesAsync 方法不会重新启动应用程序。
我也遇到过同样的问题。这真是一场噩梦。我的应用程序也是 win32 桌面应用程序 MSIX 包。我很自信地告诉您,您的应用程序没有尝试重新启动。相反,它崩溃了。如果您阅读合作伙伴中心的运行状况报告,您将看到所有崩溃事件。如果您像我一样,继续上传新版本以使事情正常运行,您可以轻松地将崩溃事件与最新版本联系起来。
经过一番尝试,我发现是对
TrySilentDownloadAndInstallStorePackageUpdatesAsync
的调用导致了崩溃。而问题的解决方案让我感到惊讶。虽然文档说此方法将下载并安装更新,但不要相信它!
相反:
TrySilentDownloadStorePackageUpdatesAsync
下载更新TrySilentDownloadAndInstallStorePackageUpdatesAsync
!然后没有崩溃!
为了让您的一天更轻松,我将把整个该死的事情发布在这里。应该可以节省您几天的工作时间:
typedef void(*WindowsStoreCallback) (int error);
namespace winrt
{
using namespace winrt;
using namespace winrt::Windows::Services::Store;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
}
winrt::Windows::Foundation::IAsyncAction TrySilentDownloadAndInstallUpdate(WindowsStoreCallback callback)
{
// return control to caller
co_await winrt::resume_background();
// check update
winrt::IAsyncOperation<winrt::IVectorView<winrt::StorePackageUpdate>> op_check = m_storeContext.GetAppAndOptionalStorePackageUpdatesAsync();
winrt::IVectorView<winrt::StorePackageUpdate> updates = co_await op_check;
if (updates.Size() <= 0) {
callback(E_FAIL); // handle any other ways to fit your need
co_return;
}
// Download only
winrt::IAsyncOperationWithProgress<winrt::StorePackageUpdateResult, winrt::StorePackageUpdateStatus> op_download =
m_storeContext.TrySilentDownloadStorePackageUpdatesAsync(updates);
bool is_completed = false;
while (!is_completed) { // I don't know if the loop is necessary, just added to be safe. The documentation is unclear anyway ...
winrt::StorePackageUpdateResult result = co_await op_download;
switch (result.OverallState()) {
case winrt::StorePackageUpdateState::Pending:
case winrt::StorePackageUpdateState::Downloading:
case winrt::StorePackageUpdateState::Deploying:
::Sleep(100);
continue;
case winrt::StorePackageUpdateState::Completed:
is_completed = true;
break;
case winrt::StorePackageUpdateState::Canceled:
callback(E_ABORT);
co_return;
// all other errors
case winrt::StorePackageUpdateState::OtherError:
case winrt::StorePackageUpdateState::ErrorLowBattery:
case winrt::StorePackageUpdateState::ErrorWiFiRecommended:
case winrt::StorePackageUpdateState::ErrorWiFiRequired:
default:
callback(E_FAIL);
co_return;
}
}
// (Download) and install
winrt::IAsyncOperationWithProgress<winrt::StorePackageUpdateResult, winrt::StorePackageUpdateStatus> op_install =
m_storeContext.TrySilentDownloadAndInstallStorePackageUpdatesAsync(updates);
while (true) { // Again, I don't know if the loop is necessary, just to be safe.
winrt::StorePackageUpdateResult result = co_await op_install; // Wait for completion
switch (result.OverallState()) {
case winrt::StorePackageUpdateState::Pending:
case winrt::StorePackageUpdateState::Downloading:
case winrt::StorePackageUpdateState::Deploying:
break;
case winrt::StorePackageUpdateState::Completed:
callback(S_OK);
co_return;
case winrt::StorePackageUpdateState::Canceled:
callback(E_ABORT);
co_return;
// all other errors
case winrt::StorePackageUpdateState::OtherError:
case winrt::StorePackageUpdateState::ErrorLowBattery:
case winrt::StorePackageUpdateState::ErrorWiFiRecommended:
case winrt::StorePackageUpdateState::ErrorWiFiRequired:
default:
callback(E_FAIL);
co_return;
}
::Sleep(100);
}
co_return;
}
希望这有帮助。
旁注: 如果有人可以联系 Microsoft 团队,请告诉他们通过提供适用于所有支持的语言的示例代码(直到今天,相应文档中的“示例”类别仍然为空)来让开发人员的日子变得更轻松,并提供一个模拟器测试!仅仅为了测试如此简单的东西而一次又一次地部署是没有乐趣的。你知道,每次更改代码时我都必须部署两次(一次用于代码更改,另一次用于提供更新)。所以我才说这是一场噩梦!