我们每天都会使用各种应用程序。 在不同的平台上运行它们,包括手机、Web、桌面、平板电脑和电视。 每个软件公司都会自行决定其应用程序应该支持哪些平台。

有些情况下,仅限于一个平台是不可行的,有必要让应用程序在不同平台上可用。 为每个平台开发独立的应用程序需要大量的时间和精力。 必须为每个平台创建一个独立的开发团队,这是相当昂贵的。 此外,还需要单独维护每个应用程序,这也需要额外的资源。

我们都知道,目前最流行的平台是互联网。 根据 2023 年的顶级网站统计数据, 截至 2023 年,互联网上大约有 11.3 亿个网站。 每三秒就有一个新网站建成。

这就是为什么,许多公司更愿意先创建一个 Web 应用程序,然后将其转换为移动或桌面应用程序。 这样的应用看起来就像是普通的本地应用,但实际上,它们显示的是一个 Web 应用程序或其特殊版本。

这种支持多平台的方法为软件公司和开发者节省了大量的时间和金钱。 使得公司能够迅速创建移动或桌面应用程序,并在投入更多资源使用本地开发工具为每个平台开发独立应用程序之前,在这些平台上测试其需求。

在这篇文章中,我将讨论何时将 Web 应用程序或网站转换为桌面应用程序是有意义的,以及如何使用 Molybden 进行专业的转换。

何时将 Web 应用程序转换为桌面应用程序

首先,让我们讨论何时应该将 Web 应用程序转换为桌面应用程序。

我认为创建一个仅仅用于显示 Web 应用程序或网站的桌面应用程序是没有意义的。 如果用户在访问他们最喜欢的网络浏览器中的URL时不会获得任何额外价值,那么要求他们下载并安装您的桌面应用程序是不公平的。

如果用户希望通过单击任务栏(Windows、Linux)或 Dock(macOS)上的图标,或通过桌面上的快捷方式快速打开 Web 应用程序或网站,他们可以在 Google Chrome 中为该网站创建一个快捷方式,或者如果可用的话, 下载 Web 应用程序的 PWA 版本

当您能够通过与桌面和操作系统的集成增强 Web 应用程序的功能时,将 Web 应用程序转换为桌面应用程序是有意义的。 例如,这可能包括访问文件系统、访问硬件、显示本地桌面通知、开机启动、运行命令行实用程序、在 Web 应用程序中自动执行特定场景等。

如何将 Web 应用程序转换为桌面应用程序

要将任何 Web 应用程序或网站转换为现代跨平台桌面应用程序,您可以使用 Molybden。

什么是 Molybden

Molybden 是用于构建现代跨平台桌面应用程序的软件开发工具包(SDK)。 它提供了一组工具和框架,可简化跨平台桌面应用程序的开发过程,使您能够更快地构建、测试和部署跨平台桌面应用程序。 它允许软件公司通过在所有平台上重复使用相同的代码库来节省时间和金钱。

Molybden 的特色之一是它使用 Chromium 来渲染应用程序窗口内的用户界面。 这使您能够使用 Web 技术构建应用程序的整个用户界面,或者直接在桌面应用程序中加载和显示任何现代 Web 应用程序或网站。

此外,Molybden 提供了一个框架,允许 Web 应用程序与低级本机 API 进行交互,并利用操作系统的功能。 这极大地扩展了 Web 应用程序的功能,并消除了通常在标准 Web 浏览器中运行 Web 应用程序时遇到的限制。

在接下来的部分,我将向您展示如何使用 Molybden 将 Web 应用程序转换为桌面应用程序。

从模板生成项目

首先,我们需要生成一个项目。 Molybden 提供了一个名为 create-molybden-app 的特殊实用程序。 这是官方的项目脚手架工具,允许您基于特定模板创建项目。 要生成项目,请执行以下命令:

npm create molybden-app@latest

指定您的应用程序的名称,选择 Website 项目模板,并提供您的 Web 应用程序的 URL:

? Project name: PurePhotos
? Select project template: Website
? Enter the website URL: https://purephotos.app/my/dashboard

Done! To get started run:
cd PurePhotos
npm install
npm run molybden dev

运行应用程序

项目生成后,您可以执行以下命令来构建和运行您的桌面应用程序:

cd PurePhotos
npm install
npm run molybden dev

启动后,您将看到一个登录表单,用于访问 Web 应用程序:

Pure Photos 应用登录页面

Pure Photos 应用仪表板页面

关于 Pure Photos

在这个例子中,我们将把名为 Pure Photos 的 Web 应用程序转换为桌面应用程序。 它允许您自动删除照片的任何背景并隐藏照片中的任何瑕疵。

使用 Pure Photos,您可以:

  • 找到照片中的人物,并将他们的头部对齐,使整批照片中的人物处于同一水平。
  • 校正曝光和颜色。
  • 检测并去除噪声。
  • 消除痘痘、雀斑和斑点。
  • 生成以 Adobe Photoshop 文档(APD)文件格式为基础的分层图像。

在集成开发环境 (IDE) 中工作

让我们通过添加一些功能来扩展我们的桌面应用程序。

Molybden 生成的项目采用了所有现代 C++ 集成开发环境(IDE)支持的格式,如 MS Visual Studio、Qt Creator 和 CLion。

为了对应用程序代码进行更改,我在 CLion(我最喜欢的 IDE)中打开项目,并选择 src-cpp/src/main.cc 文件。 这个文件包含在启动应用程序时执行的主函数。 在这个文件中,我们可以实现桌面应用程序的逻辑。

CLion 中的 Molybden 项目

在系统托盘中显示应用程序

为了使应用程序出现在系统托盘中。 我们将创建并配置应用程序托盘,如下所示:

#include "molybden.hpp"

using namespace molybden;

void launch() {
  App::init([](std::shared_ptr<App> app) {
    // 配置应用程序托盘。
    auto tray = Tray::create(app);
    tray->setImage(app->getPath(PathKey::kAppResources) + "/imageTemplate.png");
    tray->setTooltip("Pure Photos");
    tray->setMenu(menu::Menu({
      menu::Item("About Pure Photos", [app](const CustomMenuItemActionArgs& args) {
        app->desktop()->openUrl("https://purephotos.app");
      }),
      menu::Separator(),
      menu::MacQuitApp()
    }));

    // 显示应用程序窗口。
    auto browser = Browser::create(app);
    browser->loadUrl(app->baseUrl());
    browser->show();
  });
}

Pure Photos 应用程序托盘

显示本地桌面通知

我们的 Web 应用程序在照片处理完成时会通知用户。 在标准的 Web 浏览器中,用户必须授予 Web 应用程序显示桌面通知的权限。 Molybden 允许您通过编程方式进行配置。

让我们允许 Web 应用程序始终显示本机桌面通知:

// 授予桌面通知权限。
auto permissions = app->profile()->permissions();
permissions->onRequestPermission = [](const RequestPermissionArgs& args,
                                      RequestPermissionAction action) {
  if (args.permission_type == PermissionType::kNotifications) {
    action.grant();
  } else {
    action.ask();
  }
};

从 Web 应用程序中访问本机 API

让我们通知正在我们的桌面应用程序中运行的 Web 应用程序。 在这种情况下,Web 应用程序可以显示用户界面的附加元素或调整其内部逻辑。 为此,我们将创建一个特定的变量,供 Web 应用程序检查以了解它是在哪里运行(在标准 Web 浏览器中还是桌面应用程序中):

browser->onInjectJs = [](const InjectJsArgs& args, InjectJsAction action) {
  auto window = args.frame->executeJavaScript("window").asJsObject();
  window->putProperty("isDesktop", true);
  action.proceed();
};

Web 应用程序可以在 JavaScript 中访问此变量,如下所示:

if (isDesktop !== undefined && isDesktop) {
    // 该 Web 应用程序正在桌面应用程序中运行。
}

现在,当 Web 应用程序能够理解它正在我们的桌面应用程序中运行时,它可以访问操作系统的各种功能。 让我们实现显示本机 Open Folder 对话框并获取所选文件夹中所有文件列表的功能。

Molybden 允许您在桌面应用程序中定义一个函数,并将其 “注入” 到 Web 应用程序中,以便可以直接从 JavaScript 中调用它。

让我们声明一个函数,该函数将向用户显示一个本机 Open Folder 对话框,并将所选文件夹中的文件列表作为 JSON 字符串返回:

std::string ShowOpenDialogAndGetDirFiles(std::shared_ptr<App> app) {
  std::promise<std::string> dir_path;

  // 显示允许用户选择目录的打开对话框。
  OpenDialogOptions options;
  options.features.allow_multiple_selections = false;
  options.selection_policy = OpenDialogSelectionPolicy::kDirectories;
  OpenDialog::show(app, options, [&](const OpenDialogResult& result) {
    if (!result.paths.empty()) {
      dir_path.set_value(result.paths[0]);
    }
  });
  std::filesystem::path dir = dir_path.get_future().get();

  // 将所选目录的文件以 JSON 字符串的形式返回。
  std::string result = "{ \"files\": [";
  if (std::filesystem::is_directory(dir)) {
    for (const auto& entry : std::filesystem::directory_iterator(dir)) {
      if (std::filesystem::is_regular_file(entry)) {
        result += "\"" + entry.path().string() + "\", ";
      }
    }
  }
  result += "]}";
  return result;
}

在 JavaScript 中注册这个函数:

window->putProperty("GetDirectoryFiles", [app]() -> std::string {
  return ShowOpenDialogAndGetDirFiles(app);
});

现在,您可以从 Web 应用程序的 JavaScript 代码中调用这个函数:

if (isDesktop !== undefined && isDesktop) {
    console.log(GetDirectoryFiles());
}

在从 Web 应用程序调用此 JavaScript 代码之后,您将在 JavaScript 控制台中看到以下输出:

Pure Photos 应用程序的 Open Folder 对话框

Pure Photos 应用程序的 JavaScript 控制台

自定义应用程序图标

要自定义应用程序图标,我们可以使用官方 Pure Photos 标志, 转换为所需的格式,并用它替换默认的应用程序图标。

启动应用程序并确保新的图标正在使用中:

Pure Photos 应用程序图标

生成应用程序安装程序

一旦我们的桌面应用程序中实现了所有必要的功能,我们就可以将其交付给终端用户。 为了提供流畅的用户体验,Molybden 会自动生成当前操作系统的本机格式的 应用程序安装程序

要构建桌面应用程序的生产版本并生成应用程序安装程序,请执行以下命令:

npm run molybden build

安装程序将被放置在 ./build-dist/pack 目录中。

Pure Photos 的 DMG(磁盘映像)

在将应用程序分发给终端用户之前,建议您 对应用程序进行签名和公证。 这是因为 macOS 要求所有应用程序必须经过签名和公证才能运行。

就是这样! 使用 Molybden,您可以为桌面应用程序添加许多其他功能,但 如果将所有内容都涵盖进来,这篇文章就太长了。

顺便说一句,您不仅可以转换自己的 Web 应用程序或网站 ;)

完整实例

以下是创建的桌面应用程序的完整源代码:

#include <filesystem>
#include <future>

#include "molybden.hpp"

using namespace molybden;

/**
  * 显示打开对话框并将所选目录的文件以 JSON 格式返回。
  */
std::string ShowOpenDialogAndGetDirFiles(std::shared_ptr<App> app) {
  std::promise<std::string> dir_path;

  // 显示允许用户选择目录的打开对话框。
  OpenDialogOptions options;
  options.features.allow_multiple_selections = false;
  options.selection_policy = OpenDialogSelectionPolicy::kDirectories;
  OpenDialog::show(app, options, [&](const OpenDialogResult& result) {
    if (!result.paths.empty()) {
      dir_path.set_value(result.paths[0]);
    }
  });
  std::filesystem::path dir = dir_path.get_future().get();

  // 将所选目录的文件以 JSON 字符串的形式返回。
  std::string result = "{ \"files\": [";
  if (std::filesystem::is_directory(dir)) {
    for (const auto& entry : std::filesystem::directory_iterator(dir)) {
      if (std::filesystem::is_regular_file(entry)) {
        result += "\"" + entry.path().string() + "\", ";
      }
    }
  }
  result += "]}";
  return result;
}

void launch() {
  App::init([](std::shared_ptr<App> app) {
    // 配置应用程序托盘。
    auto tray = Tray::create(app);
    tray->setImage(app->getPath(PathKey::kAppResources) + "/imageTemplate.png");
    tray->setTooltip("Pure Photos");
    tray->setMenu(menu::Menu({
      menu::Item("About Pure Photos", [app](const CustomMenuItemActionArgs& args) {
        app->desktop()->openUrl("https://purephotos.app");
      }),
      menu::Separator(),
      menu::MacQuitApp()
    }));

    // 授予桌面通知权限。
    auto permissions = app->profile()->permissions();
    permissions->onRequestPermission = [](const RequestPermissionArgs& args,
                                          RequestPermissionAction action) {
      if (args.permission_type == PermissionType::kNotifications) {
        action.grant();
      } else {
        action.ask();
      }
    };

    // 显示应用程序窗口。
    auto browser = Browser::create(app);
    browser->onInjectJs = [app](const InjectJsArgs& args,
                                InjectJsAction action) {
      auto window = args.frame->executeJavaScript("window").asJsObject();
      // 注入指示这是桌面应用程序的变量。
      window->putProperty("isDesktop", true);
      // 注入返回目录文件的函数。
      window->putProperty("GetDirectoryFiles", [app]() -> std::string {
        return ShowOpenDialogAndGetDirFiles(app);
      });
      action.proceed();
    };
    browser->loadUrl(app->baseUrl());
    browser->show();
  });
}

Pure Photos 应用程序

接下来

在几分钟内使用 Molybden 将您的 Web 应用程序转换为桌面应用程序。 请自行了解 Molybden 如何简化开发过程,让您在更短的时间内构建现代且美观的跨平台桌面应用程序。

如果您有任何问题或需要专业指导,请随时 联系我们。 我们将很乐意协助您的公司创建现代、美观、功能丰富的跨平台桌面应用程序。