Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 40 additions & 13 deletions shell/platform/windows/uwptool_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,54 @@ namespace {
// Prints a list of installed UWP apps to stdout.
void PrintInstalledApps() {
flutter::ApplicationStore app_store;
for (const flutter::Application& app : app_store.GetInstalledApplications()) {
for (const flutter::Application& app : app_store.GetApps()) {
std::wcout << app.GetPackageFamily() << std::endl;
}
}

// Launches the app installed on the system whose Application User Model ID is
// prefixed with app_id, with the specified arguments list.
// Launches the app installed on the system with the specified package.
//
// Returns -1 if no matching app, or multiple matching apps are found, or if
// the app fails to launch. Otherwise, the process ID of the launched app is
// returned.
int LaunchApp(const std::wstring_view package_family,
const std::wstring_view args) {
flutter::ApplicationStore app_store;
std::optional<flutter::Application> app =
app_store.GetInstalledApplication(package_family);
if (!app) {
return -1;
for (flutter::Application& app : app_store.GetApps(package_family)) {
int process_id = app.Launch(args);
if (process_id != -1) {
return process_id;
}
}
return app->Launch(args);
return -1;
}

// Uninstalls the app with the specified package.
//
// Returns true on success.
bool UninstallApp(const std::wstring_view package_family) {
bool success = true;
flutter::ApplicationStore app_store;
for (flutter::Application& app : app_store.GetApps(package_family)) {
if (app.Uninstall()) {
std::wcerr << L"Uninstalled application " << app.GetPackageFullName()
<< std::endl;
} else {
std::wcerr << L"error: Failed to uninstall application "
<< app.GetPackageFullName() << std::endl;
success = false;
}
}
return success;
}

// Prints the command usage to stderr.
void PrintUsage() {
std::cerr << "usage: uwptool COMMAND [APP_ID]" << std::endl;
std::cerr << "usage: uwptool COMMAND [ARGUMENTS]" << std::endl;
std::cerr << "commands:" << std::endl;
std::cerr << " listapps list installed applications" << std::endl;
std::cerr << " launch launch an application" << std::endl;
std::cerr << " listapps list installed apps" << std::endl;
std::cerr << " launch PACKAGE_FAMILY launch an app" << std::endl;
std::cerr << " uninstall PACKAGE_FAMILY uninstall an app" << std::endl;
}

} // namespace
Expand All @@ -67,12 +87,12 @@ int main(int argc, char** argv) {
PrintInstalledApps();
return 0;
} else if (command == "launch") {
if (command_line.positional_args().size() < 1) {
if (args.size() < 2) {
PrintUsage();
return 1;
}

// Get the package family.
// Get the package family name.
std::string package_family = args[1];

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

std::cerr << "Unknown command: " << command << std::endl;
Expand Down
65 changes: 51 additions & 14 deletions shell/platform/windows/uwptool_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,20 @@
#include <winrt/Windows.Management.Deployment.h>
#include <winrt/base.h>

#include <iostream>
#include <optional>
#include <string>
#include <unordered_set>
#include <vector>

namespace flutter {

Application::Application(const std::wstring_view package_family,
Application::Application(const std::wstring_view package_name,
const std::wstring_view package_family,
const std::wstring_view package_full_name)
: package_family_(package_family), package_full_name_(package_full_name) {}
: package_name_(package_name),
package_family_(package_family),
package_full_name_(package_full_name) {}

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

std::vector<Application> ApplicationStore::GetInstalledApplications() const {
bool Application::Uninstall() {
using winrt::Windows::Foundation::AsyncStatus;
using winrt::Windows::Management::Deployment::PackageManager;
using winrt::Windows::Management::Deployment::RemovalOptions;

PackageManager package_manager;
auto operation = package_manager.RemovePackageAsync(
package_full_name_, RemovalOptions::RemoveForAllUsers);
operation.get();

if (operation.Status() == AsyncStatus::Completed) {
return true;
} else if (operation.Status() == AsyncStatus::Canceled) {
return false;
} else if (operation.Status() == AsyncStatus::Error) {
auto result = operation.GetResults();
std::wcerr << L"error: uninstall failed for package " << package_full_name_
<< L" with error: " << result.ErrorText().c_str() << std::endl;
return false;
}
return false;
}

std::vector<Application> ApplicationStore::GetApps() const {
using winrt::Windows::ApplicationModel::Package;
using winrt::Windows::Management::Deployment::PackageManager;

// Find packages for the current user (default for empty string).
PackageManager package_manager;
std::vector<Application> apps;
for (const Package& package : package_manager.FindPackagesForUser(L"")) {
apps.emplace_back(package.Id().FamilyName().c_str(),
package.Id().FullName().c_str());
try {
PackageManager package_manager;
for (const Package& package : package_manager.FindPackagesForUser(L"")) {
apps.emplace_back(package.Id().Name().c_str(),
package.Id().FamilyName().c_str(),
package.Id().FullName().c_str());
}
} catch (winrt::hresult_error error) {
return {};
}
return apps;
}

std::optional<Application> ApplicationStore::GetInstalledApplication(
std::vector<Application> ApplicationStore::GetApps(
const std::wstring_view package_family) const {
using winrt::Windows::ApplicationModel::Package;
using winrt::Windows::Management::Deployment::PackageManager;

// Find packages for the current user (default for empty string).
PackageManager package_manager;
std::vector<Application> apps;
for (const Package& package :
package_manager.FindPackagesForUser(L"", package_family)) {
return std::optional(Application(package.Id().FamilyName().c_str(),
package.Id().FullName().c_str()));
try {
PackageManager package_manager;
for (const Package& package :
package_manager.FindPackagesForUser(L"", package_family)) {
apps.emplace_back(package.Id().Name().c_str(),
package.Id().FamilyName().c_str(),
package.Id().FullName().c_str());
}
} catch (winrt::hresult_error error) {
return {};
}
return std::nullopt;
return apps;
}

} // namespace flutter
30 changes: 25 additions & 5 deletions shell/platform/windows/uwptool_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,43 @@ namespace flutter {
// A UWP application.
class Application {
public:
explicit Application(const std::wstring_view package_family,
explicit Application(const std::wstring_view package_name,
const std::wstring_view package_family,
const std::wstring_view package_full_name);
Application(const Application& other) = default;
Application& operator=(const Application& other) = default;

// Returns the package name.
//
// The package name is a globally unique name that represents the 'friendly'
// name of a package.
std::wstring GetPackageName() const { return package_name_; }

// Returns the package family.
//
// The package family is a serialized form of the package identifiers that
// includes the package name and publisher.
std::wstring GetPackageFamily() const { return package_family_; }

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

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

// Uninstalls the application.
//
// Returns true on success.
bool Uninstall();

private:
std::wstring package_name_;
std::wstring package_family_;
std::wstring package_full_name_;
};
Expand All @@ -44,11 +64,11 @@ class ApplicationStore {
ApplicationStore(const ApplicationStore& other) = delete;
ApplicationStore& operator=(const ApplicationStore& other) = delete;

// Returns a list of all installed application user model IDs.
std::vector<Application> GetInstalledApplications() const;
// Returns all installed applications.
std::vector<Application> GetApps() const;

// Returns a list of all installed application user model IDs.
std::optional<Application> GetInstalledApplication(
// Returns all installed applications with the specified family name.
std::vector<Application> GetApps(
const std::wstring_view package_family) const;
};

Expand Down
28 changes: 15 additions & 13 deletions shell/platform/windows/uwptool_utils_unittests.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ namespace testing {

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

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

// Verify that we can look up an app by family name.
TEST(ApplicationStore, GetInstalledApplication) {
ApplicationStore app_store;
std::vector<Application> apps = app_store.GetInstalledApplications();
EXPECT_FALSE(apps.empty());

std::optional<Application> found_app =
app_store.GetInstalledApplication(apps[0].GetPackageFamily());
ASSERT_TRUE(found_app != std::nullopt);
EXPECT_EQ(found_app->GetPackageFamily(), apps[0].GetPackageFamily());
EXPECT_EQ(found_app->GetPackageFullName(), apps[0].GetPackageFullName());
TEST(ApplicationStore, GetAppsByPackageFamily) {
ApplicationStore store;
std::vector<Application> all_apps = store.GetApps();
EXPECT_FALSE(all_apps.empty());

Application app = all_apps[0];
std::vector<Application> found_apps = store.GetApps(app.GetPackageFamily());
ASSERT_FALSE(found_apps.empty());
for (const Application& found_app : found_apps) {
EXPECT_EQ(found_app.GetPackageName(), app.GetPackageName());
EXPECT_EQ(found_app.GetPackageFamily(), app.GetPackageFamily());
}
}

} // namespace testing
Expand Down