Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 0f28cd6

Browse files
authored
[uwptool] Add uninstall command (#26122)
Adds an uninstall command that uninstalls the specified application by its package family name. This currently attempts to remove for all users, but in future, we may want to restrict install and uninstall to the current user only. Also renames ApplicationStore::GetInstalledApplications() to ApplicationStore::GetApps()
1 parent 4900682 commit 0f28cd6

File tree

4 files changed

+131
-45
lines changed

4 files changed

+131
-45
lines changed

shell/platform/windows/uwptool_main.cc

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,34 +20,54 @@ namespace {
2020
// Prints a list of installed UWP apps to stdout.
2121
void PrintInstalledApps() {
2222
flutter::ApplicationStore app_store;
23-
for (const flutter::Application& app : app_store.GetInstalledApplications()) {
23+
for (const flutter::Application& app : app_store.GetApps()) {
2424
std::wcout << app.GetPackageFamily() << std::endl;
2525
}
2626
}
2727

28-
// Launches the app installed on the system whose Application User Model ID is
29-
// prefixed with app_id, with the specified arguments list.
28+
// Launches the app installed on the system with the specified package.
3029
//
3130
// Returns -1 if no matching app, or multiple matching apps are found, or if
3231
// the app fails to launch. Otherwise, the process ID of the launched app is
3332
// returned.
3433
int LaunchApp(const std::wstring_view package_family,
3534
const std::wstring_view args) {
3635
flutter::ApplicationStore app_store;
37-
std::optional<flutter::Application> app =
38-
app_store.GetInstalledApplication(package_family);
39-
if (!app) {
40-
return -1;
36+
for (flutter::Application& app : app_store.GetApps(package_family)) {
37+
int process_id = app.Launch(args);
38+
if (process_id != -1) {
39+
return process_id;
40+
}
4141
}
42-
return app->Launch(args);
42+
return -1;
43+
}
44+
45+
// Uninstalls the app with the specified package.
46+
//
47+
// Returns true on success.
48+
bool UninstallApp(const std::wstring_view package_family) {
49+
bool success = true;
50+
flutter::ApplicationStore app_store;
51+
for (flutter::Application& app : app_store.GetApps(package_family)) {
52+
if (app.Uninstall()) {
53+
std::wcerr << L"Uninstalled application " << app.GetPackageFullName()
54+
<< std::endl;
55+
} else {
56+
std::wcerr << L"error: Failed to uninstall application "
57+
<< app.GetPackageFullName() << std::endl;
58+
success = false;
59+
}
60+
}
61+
return success;
4362
}
4463

4564
// Prints the command usage to stderr.
4665
void PrintUsage() {
47-
std::cerr << "usage: uwptool COMMAND [APP_ID]" << std::endl;
66+
std::cerr << "usage: uwptool COMMAND [ARGUMENTS]" << std::endl;
4867
std::cerr << "commands:" << std::endl;
49-
std::cerr << " listapps list installed applications" << std::endl;
50-
std::cerr << " launch launch an application" << std::endl;
68+
std::cerr << " listapps list installed apps" << std::endl;
69+
std::cerr << " launch PACKAGE_FAMILY launch an app" << std::endl;
70+
std::cerr << " uninstall PACKAGE_FAMILY uninstall an app" << std::endl;
5171
}
5272

5373
} // namespace
@@ -67,12 +87,12 @@ int main(int argc, char** argv) {
6787
PrintInstalledApps();
6888
return 0;
6989
} else if (command == "launch") {
70-
if (command_line.positional_args().size() < 1) {
90+
if (args.size() < 2) {
7191
PrintUsage();
7292
return 1;
7393
}
7494

75-
// Get the package family.
95+
// Get the package family name.
7696
std::string package_family = args[1];
7797

7898
// Concatenate the remaining args, comma-separated.
@@ -97,6 +117,13 @@ int main(int argc, char** argv) {
97117
// Write the PID to stdout. The flutter tool reads this value in.
98118
std::cout << process_id << std::endl;
99119
return 0;
120+
} else if (command == "uninstall") {
121+
if (args.size() < 2) {
122+
PrintUsage();
123+
return 1;
124+
}
125+
std::string package_family = args[1];
126+
return UninstallApp(flutter::Utf16FromUtf8(package_family)) ? 0 : 1;
100127
}
101128

102129
std::cerr << "Unknown command: " << command << std::endl;

shell/platform/windows/uwptool_utils.cc

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,20 @@
1212
#include <winrt/Windows.Management.Deployment.h>
1313
#include <winrt/base.h>
1414

15+
#include <iostream>
1516
#include <optional>
1617
#include <string>
1718
#include <unordered_set>
1819
#include <vector>
1920

2021
namespace flutter {
2122

22-
Application::Application(const std::wstring_view package_family,
23+
Application::Application(const std::wstring_view package_name,
24+
const std::wstring_view package_family,
2325
const std::wstring_view package_full_name)
24-
: package_family_(package_family), package_full_name_(package_full_name) {}
26+
: package_name_(package_name),
27+
package_family_(package_family),
28+
package_full_name_(package_full_name) {}
2529

2630
int Application::Launch(const std::wstring_view args) {
2731
// Create the ApplicationActivationManager.
@@ -45,34 +49,67 @@ int Application::Launch(const std::wstring_view args) {
4549
return process_id;
4650
}
4751

48-
std::vector<Application> ApplicationStore::GetInstalledApplications() const {
52+
bool Application::Uninstall() {
53+
using winrt::Windows::Foundation::AsyncStatus;
54+
using winrt::Windows::Management::Deployment::PackageManager;
55+
using winrt::Windows::Management::Deployment::RemovalOptions;
56+
57+
PackageManager package_manager;
58+
auto operation = package_manager.RemovePackageAsync(
59+
package_full_name_, RemovalOptions::RemoveForAllUsers);
60+
operation.get();
61+
62+
if (operation.Status() == AsyncStatus::Completed) {
63+
return true;
64+
} else if (operation.Status() == AsyncStatus::Canceled) {
65+
return false;
66+
} else if (operation.Status() == AsyncStatus::Error) {
67+
auto result = operation.GetResults();
68+
std::wcerr << L"error: uninstall failed for package " << package_full_name_
69+
<< L" with error: " << result.ErrorText().c_str() << std::endl;
70+
return false;
71+
}
72+
return false;
73+
}
74+
75+
std::vector<Application> ApplicationStore::GetApps() const {
4976
using winrt::Windows::ApplicationModel::Package;
5077
using winrt::Windows::Management::Deployment::PackageManager;
5178

5279
// Find packages for the current user (default for empty string).
53-
PackageManager package_manager;
5480
std::vector<Application> apps;
55-
for (const Package& package : package_manager.FindPackagesForUser(L"")) {
56-
apps.emplace_back(package.Id().FamilyName().c_str(),
57-
package.Id().FullName().c_str());
81+
try {
82+
PackageManager package_manager;
83+
for (const Package& package : package_manager.FindPackagesForUser(L"")) {
84+
apps.emplace_back(package.Id().Name().c_str(),
85+
package.Id().FamilyName().c_str(),
86+
package.Id().FullName().c_str());
87+
}
88+
} catch (winrt::hresult_error error) {
89+
return {};
5890
}
5991
return apps;
6092
}
6193

62-
std::optional<Application> ApplicationStore::GetInstalledApplication(
94+
std::vector<Application> ApplicationStore::GetApps(
6395
const std::wstring_view package_family) const {
6496
using winrt::Windows::ApplicationModel::Package;
6597
using winrt::Windows::Management::Deployment::PackageManager;
6698

6799
// Find packages for the current user (default for empty string).
68-
PackageManager package_manager;
69100
std::vector<Application> apps;
70-
for (const Package& package :
71-
package_manager.FindPackagesForUser(L"", package_family)) {
72-
return std::optional(Application(package.Id().FamilyName().c_str(),
73-
package.Id().FullName().c_str()));
101+
try {
102+
PackageManager package_manager;
103+
for (const Package& package :
104+
package_manager.FindPackagesForUser(L"", package_family)) {
105+
apps.emplace_back(package.Id().Name().c_str(),
106+
package.Id().FamilyName().c_str(),
107+
package.Id().FullName().c_str());
108+
}
109+
} catch (winrt::hresult_error error) {
110+
return {};
74111
}
75-
return std::nullopt;
112+
return apps;
76113
}
77114

78115
} // namespace flutter

shell/platform/windows/uwptool_utils.h

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,43 @@ namespace flutter {
1414
// A UWP application.
1515
class Application {
1616
public:
17-
explicit Application(const std::wstring_view package_family,
17+
explicit Application(const std::wstring_view package_name,
18+
const std::wstring_view package_family,
1819
const std::wstring_view package_full_name);
1920
Application(const Application& other) = default;
2021
Application& operator=(const Application& other) = default;
2122

23+
// Returns the package name.
24+
//
25+
// The package name is a globally unique name that represents the 'friendly'
26+
// name of a package.
27+
std::wstring GetPackageName() const { return package_name_; }
28+
2229
// Returns the package family.
30+
//
31+
// The package family is a serialized form of the package identifiers that
32+
// includes the package name and publisher.
2333
std::wstring GetPackageFamily() const { return package_family_; }
2434

2535
// Returns the package full name.
36+
//
37+
// The package full name is a serialized form of the package identifiers that
38+
// includes a particular version of the package on the computer. It encodes
39+
// package name, publisher, architecture and version information.
2640
std::wstring GetPackageFullName() const { return package_full_name_; }
2741

2842
// Launches the application with the specified list of launch arguments.
2943
//
3044
// Returns the process ID on success, or -1 on failure.
3145
int Launch(const std::wstring_view args);
3246

47+
// Uninstalls the application.
48+
//
49+
// Returns true on success.
50+
bool Uninstall();
51+
3352
private:
53+
std::wstring package_name_;
3454
std::wstring package_family_;
3555
std::wstring package_full_name_;
3656
};
@@ -44,11 +64,11 @@ class ApplicationStore {
4464
ApplicationStore(const ApplicationStore& other) = delete;
4565
ApplicationStore& operator=(const ApplicationStore& other) = delete;
4666

47-
// Returns a list of all installed application user model IDs.
48-
std::vector<Application> GetInstalledApplications() const;
67+
// Returns all installed applications.
68+
std::vector<Application> GetApps() const;
4969

50-
// Returns a list of all installed application user model IDs.
51-
std::optional<Application> GetInstalledApplication(
70+
// Returns all installed applications with the specified family name.
71+
std::vector<Application> GetApps(
5272
const std::wstring_view package_family) const;
5373
};
5474

shell/platform/windows/uwptool_utils_unittests.cc

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ namespace testing {
2020

2121
// Verify that at least one Microsoft app (e.g. Microsoft.WindowsCalculator) is
2222
// installed and can be found.
23-
TEST(ApplicationStore, GetInstalledApplications) {
24-
ApplicationStore app_store;
25-
std::vector<Application> apps = app_store.GetInstalledApplications();
23+
TEST(ApplicationStore, GetApps) {
24+
ApplicationStore store;
25+
std::vector<Application> apps = store.GetApps();
2626
EXPECT_FALSE(apps.empty());
2727

2828
auto ms_pos = std::find_if(apps.begin(), apps.end(), [](const auto& app) {
@@ -32,16 +32,18 @@ TEST(ApplicationStore, GetInstalledApplications) {
3232
}
3333

3434
// Verify that we can look up an app by family name.
35-
TEST(ApplicationStore, GetInstalledApplication) {
36-
ApplicationStore app_store;
37-
std::vector<Application> apps = app_store.GetInstalledApplications();
38-
EXPECT_FALSE(apps.empty());
39-
40-
std::optional<Application> found_app =
41-
app_store.GetInstalledApplication(apps[0].GetPackageFamily());
42-
ASSERT_TRUE(found_app != std::nullopt);
43-
EXPECT_EQ(found_app->GetPackageFamily(), apps[0].GetPackageFamily());
44-
EXPECT_EQ(found_app->GetPackageFullName(), apps[0].GetPackageFullName());
35+
TEST(ApplicationStore, GetAppsByPackageFamily) {
36+
ApplicationStore store;
37+
std::vector<Application> all_apps = store.GetApps();
38+
EXPECT_FALSE(all_apps.empty());
39+
40+
Application app = all_apps[0];
41+
std::vector<Application> found_apps = store.GetApps(app.GetPackageFamily());
42+
ASSERT_FALSE(found_apps.empty());
43+
for (const Application& found_app : found_apps) {
44+
EXPECT_EQ(found_app.GetPackageName(), app.GetPackageName());
45+
EXPECT_EQ(found_app.GetPackageFamily(), app.GetPackageFamily());
46+
}
4547
}
4648

4749
} // namespace testing

0 commit comments

Comments
 (0)