[G.1] 独立应用(standalone App)快速构建指北

助教-郭晓燕 2024-03-11 14:57:34

原文 notion 链接: https://slash-shampoo-aba.notion.site/GuideArticle-90b19e5f3a374381a2449c205179ffde

引言

在不断演变的软件开发领域中,网页端应用(Web App)一直是数字体验的基石。在已经过去的数据库原理实验课程上,我们体验的也都是 Web App 的构建流程。然而,日常生活中,我们接触到的软件仍有相当大的体量来自桌面端或移动端独立应用,对于一些需要支持本地化存储等功能的软件,构建本地应用也是必然的选择。

本文旨在为那些对独立应用构建感兴趣的同学提供过渡支持(当然,本课程完全支持以 Web App 作为最终项目),构建独立应用并没有你想象中的那么困难!具体地,本文将介绍原生应用(Native App)和渐进式网页应用(Progressive Web App, PWA)的基础构建方法。希望在本文的支持下,本届软件工程课程可以诞生更多有创意的作品。祝开发愉快!😊

🚨注意:大部分开发中遇到的问题都能通过阅读开发文档 / Google / 进一步询问助教 / ChatGPT 等得到回答,本文提供的仅是入门介绍、快速上手流程和资料推荐,供同学们选择适合自己开发习惯 / 有眼缘的框架。

选择合适的应用程序类型

在介绍具体的开发框架之前,有必要简单介绍基本的应用程序类型,同学们可根据自身的开发需求或产品设计的内容,选择最合适的类型进行进一步开发构建。对于某些类型的应用,反而 Web App 才是最恰当的选择。

Web App

Web App 是 通过浏览器访问 的应用程序,通常由 HTML、CSS 和 JavaScript 构建,也是大部分同学现在最熟悉其开发形式的应用类型。Web 应用可以在各种设备上运行,而无需安装,是一种轻量级的应用形式。

img

Native App

原生应用是专门为特定平台(如 iOS、Android)使用原生编程语言(如 Swift / Objective-C 或 Java / Kotlin)开发的 独立应用程序。它有自己的桌面小图标,它与设备的操作系统直接交互,具有完全访问硬件和系统功能的能力,例如,应用通常可以访问类似相机、GPS、陀螺仪这样的设备功能,也可以管理操作系统中的文件(如果你开发了相关的功能的话)。同时,此类软件能够在用户不与它们交互和设备离线时运行。例如,聊天应用可以在不打开时接收消息,并向用户显示通知。

我们在应用商店中能够下载到的应用一般属于这种类型。

img

比较特殊的是,一些软件的开发是通过使用特定构建工具把 HTML 应用打包成可执行文件实现的,比如 .apk.exe 等等,此类技术也将是本文介绍的重点。这类软件在定义上更贴近原生应用,因为用户还是需要下载并在其计算机上安装它们,而且使用此类软件时也无需打开浏览器,而是可以通过双击桌面上的应用图标启动应用。不过,与 Web App 相比,这个策略在跨平台问题上可能会给程序员增加一些工作量。

Progressive Web App / Hybrid App

渐进式网络应用(Progressive Web App, PWA)是使用 Web 平台技术构建的应用程序,但可以提供类似特定平台应用,也即原生应用的用户体验。PWA 很多时候不需要 “安装”,要下载一个 PWA,只需要访问它的网站,然后将其作为快捷键保存到主屏幕上即可。以 Microsoft Edge 浏览器为例,当你打开 PWA 的网页时,浏览器会显示 “将其安装到桌面的选项”,如下图所示。

img

又例如下图所示的 Soundcloud 软件,可以看到它具有能在主屏幕访问的图标,但本质上还是一个 “网站”,具备 Web App 的一切特性(包括你安装过的浏览器插件和浏览器本身的侧边栏搜索此时都会生效)。

img

当然,开发者也可以使用 PWA Builder 将 PWA 发布到适用于 Windows 的 Microsoft Store、适用于 iOS 的应用商店或适用于 Android 的 Play Store,供用户在这些地方下载。

将 PWA 与普通网站区别开的是它需要满足的 10 个核心概念列表。下面是直接从 Google 开发者网站 上摘录的这个列表:

  1. 安全 – 通过 HTTPS 提供服务来防止网络窥探,保证内容不被篡改
  2. 渐进式 – 能够让每一位用户使用,无论用户使用什么浏览器,因为它是始终以渐进增强为原则
  3. 响应式 – 适应任何环境:桌面电脑、智能手机、平板电脑,或者其他设备
  4. 不依赖网络连接 – 通过用 service workers 增强,可以在离线或者低质量网络下工作
  5. 类原生应用 – 有像原生应用般的交互和导航给用户原生应用般的体验,因为它是建立在 app shell model 上的
  6. 持续更新 – 受益于 service worker 的更新进程,应用能够始终保持更新
  7. ⭐可发现 – 可识别为“应用程序”,本质上是得益于 W3C manifests 元数据和 service worker 的登记,让搜索引擎能够找到 web 应用
  8. 可再次访问 – 通过推送通知等特性让用户再次访问变得容易
  9. 可安装 – 允许用户保留对他们有用的应用在主屏幕上,而不需要通过应用商店
  10. 可链接 – 通过 URL 可以轻松分享应用,不用复杂的安装即可运行

img


综上所述,同学们可以根据自己团队的开发需求选择合适的应用类型进行开发,可供参考的指南是:

  • 需求优先: 如果目标应用的需求侧重于性能、完全访问设备硬件(例如需要维护本地存储文件)和提供最佳用户体验,原生应用是首选。
  • 跨平台需求: 如果需要在多个平台上运行并希望减少开发和维护成本,可以选择 PWA 或 Web App。
  • 离线访问: 如果离线访问是首要需求,可选择 PWA 或原生应用。
  • 开发成本: 考虑项目资源、开发成本和版本维护成本,Web App 通常是更经济和迅速的选择。如果你的应用需要频繁更新或者快速发布,也最好采用 Web App 或者 PWA。

img

从 Web 到独立应用:只差一个框架!

由于本课程的教学中心是 敏捷开发,让同学们从头开始学习一个新的技术栈并不现实,因此本文将舍弃引入类似 Flutter 这样的框架(当然,非常鼓励有相关技术背景的团队使用其他技术栈),而是介绍一些直接从 Web 应用构建独立应用的框架,让大家只需掌握基础的 HTML、CSS、Javascript 就能够快速得到反馈。是的,其实从网页到独立应用很多时候只差一个框架,相信所有的与课同学都有能力掌握!它们使得独立应用的开发被划分为了 “网页” 部分“打包” 部分,感兴趣的团队可以提前做好对应的分工。

这种 “从 Web 应用直接构建” 的特性导致这些框架基本都是基于 Chromium 内核和 Node.js 的,相当于跑两部分的 js 运行时,通俗点说,这个桌面软件就是一个 “浏览器”。感兴趣的同学可以自行进一步了解。

常用的 Native App 构建框架

本节简要介绍一些开发框架,它们能够帮助开发者将基于 Web 的应用封装成可在桌面上运行的应用程序,上手快捷,易于入门。

Electron

📑开发文档链接:Introduction | Electron (electronjs.org)

Electron 是由 GitHub 开发的开源框架,允许使用 HTML、CSS 和 JavaScript 构建跨平台的桌面应用。它基于 Chromium 和 Node.js,诸如 Atom、Postman、Notion、Vscode 等著名的软件都是使用 Electron 构建的。它也支持跨平台构建(Windows、Mac、Linux)。

p.s. 2020 级软工项目 Ficus 即使用 Electron 构建。


使用示例

确认了本地环境下已经安装了 Node.js 和 npm / yarn 等包管理器之后,就可以开始构建你的第一个 Electron 项目。

  1. 打开终端创建新项目,并进入该目录:
mkdir my-electron-app
cd my-electron-app
  1. 初始化 Node.js:
// npm
npm init
// yarn
yarn init

这将创建一个 package.json 文件,其中包含了项目的基本信息,你可以在其中编辑一些可调整参数。

{
  "name": "my-electron-app",
  "version": "1.0.0",
  "description": "",
  "main": "main.js",
  "scripts": {
    "start": "electron .",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "BUAASE2024",
  "license": "ISC",
  "devDependencies": {
    "electron": "^29.1.0"
  }
}
  1. 安装 Electron:
// npm
npm install electron --save-dev
// yarn
yarn add electron --dev

💡提示 1:后续构建团队的软工项目时,请尽量提前调研好需要用到的 包依赖!经验证明,版本依赖问题导致的非必要工作量很有可能是课程压力的主要来源(详见往届博客)。有些包支持的 Electron 版本比较旧,所以在构建团队项目时最好不要直接安装最新版,建议安装比较保守的老版本,例如 Electron 13 等。

💡提示 2:由于 npm 淘宝源的证书过期,如果你在过去的开发中曾经为 node 配置了淘宝源,请务必将镜像源更新至新域名 https://npmmirror.com/mirrors/ ,以免后续无法正常安装。

  1. 创建主页面 index.html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>😀My Electron App😀</title>
  </head>
  <body>
    <h1>Hello Electron!</h1>
        <p>BUAA SE 2024</p>
  </body>
</html>

这一部分想必同学们已经非常熟悉,按照曾经的网页开发经验书写即可!当然,你完全可以使用类似 Vue.js 这样的前端框架构建软件的 “网页” 部分,相关内容会在后文的 “进阶资料” 一节叙述。

  1. 创建 Electron 应用的入口文件 main.js
const { app, BrowserWindow } = require('electron/main')

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600
  })

  win.loadFile('index.html')
}

app.whenReady().then(() => {
  createWindow()

  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow()
    }
  })
})

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

Electron 应用需要用一个 .js 文件作为主要入口文件,类似的思路想必同学们在数据库课程的开发中已经亲身体会过(例如 Vue.js ),此处不再进行赘述。

  1. 运行应用,并做相应调试:
// npm
npm run start
// yarn
yarn run start

/my-electron-app 下运行命令之后,你将看到一个桌面窗口弹出,显示前面编写过的 HTML 页面。你还可以打开开发者模式,像以往调试 Web App 那样调试软件。

img

img

  1. 打包构建可执行文件:

完成了软件的书写之后,为了分发软件,需要将其打包成可安装的可执行文件。首先,需要安装构建工具 electron-builder:

// npm
npm install electron-builder --save-dev
// yarn 
yarn add electron-builder --save-dev

然后,在 package.json 中配置打包需要的内容:

"scripts": {
  "pack": "electron-builder --dir",
  "dist": "electron-builder"
},
"build": {
  "appId": "com.example.myelectronapp",
  "directories": {
    "output": "dist"
  }
}

最后,执行以下命令打包应用:

// npm
npm run dist
// yarn
yarn run dist

执行完毕后,你就可以在 /dist 文件夹下找到对应的可执行文件,可以将它分享给用户安装使用了。

img

NW.js

📑开发文档链接:Homepage - NW.js Documentation (nwjs.readthedocs.io)

NW.js(以前的 node-webkit)是一个使用 HTML、CSS 和 JavaScript 构建桌面应用的框架,基于 Chromium 和 Node.js。跟 Electron 一样,它支持将 Web 应用封装成独立的桌面应用,提供了更多的本地系统访问能力。我们熟悉的微信开发工具即为 NW.js。

它跟 Electron 有很多相似之处,孰优孰劣的问题也至今没有准确的答案。下面提供一个 Electron 与 NW.js 的对比图(from NW.js & Electron Compared - TangibleJS):

img


使用示例

  1. Downloads (nwjs.io) 下载新版本的 NW.js-SDK,并在项目根目录下解压文件。注意到解压目录下有个叫做 nw.exe 的文件,事实上这就是最终的软件。

  2. 在解压目录下,手动创建 package.json 和入口页面 index.html

{
  "name": "helloworld",
  "main": "index.html"
}
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>😀My NWJS App😀</title>
  </head>
  <body>
    <h1>Hello NWJS!</h1>
        <p>BUAA SE 2024</p>
  </body>
</html>
  1. 直接运行解压目录下的 nw.exe,即可获得最终的独立软件(可以看到,与 Electron 相比少了手动 “打包” 这一步):

img

AppJS

📑开发文档链接:AppJS

AppJS 是一个基于 Node.js 和 Chromium 的开源框架,支持将 Web 技术封装成原生桌面应用。它提供了一系列的 API,允许访问本地文件系统、数据库等功能。与前面提到的两个 “巨头” 相比,APPJS 最大的优点大概就是 简单,不需要像 Electron 或 NW.js 那样额外掌握一些 API。然而,不幸的是 APPJS 已经有若干年没有积极开发了,其官网也建议用户转而使用 Electron 或 NW.js。如果你有时间,拿它当个小玩具 / 研究一下开发团队的求助信息或许不错。

img

PWA 快速构建

话不多说,直接进入 使用示例

  1. 创建新项目,启动 Web 服务器:
mkdir my-pwa
cd my-pwa
npx http-server

此处提及服务器是因为:PWA 平台的关键部分需要使用 HTTPS。PWA 上线后,必须将其发布到 HTTPS URL 上。仅仅出于调试目的,Microsoft Edge 等浏览器允许 localhost Web 服务器在没有 HTTPS 的情况下使用 PWA API。如果你的团队项目想采用这一个软件构建方式,请提前准备好网页托管策略。

  1. 创建主页 index.html

    <!DOCTYPE html>
    <html>
      <head>
        <meta charset="UTF-8">
        <title>😀My PWA😀</title>
      </head>
      <body>
        <h1>Hello PWA!</h1>
            <p>BUAA SE 2024</p>
      </body>
    </html>
    
  2. 新建 manifest.json,以创建可安装到本地的 Web 应用(因为 PWA 依靠 W3C manifest 提供相关支持):

{
    "name": "BUAASE2024",
    "short_name": "hello buaa se 2024",
    "description": "",
    "start_url": "/",
    "background_color": "#2f3d58",
    "theme_color": "#2f3d58",
    "orientation": "any",
    "display": "standalone",
    "icons": [
        {
            "src": "/icon200.png",
            "sizes": "200x200"
        }
    ]
}

由于桌面端应用需要有一个图标,而 PWA 没有默认图标,故这里还需要将名为 icon200.png 的 200x200 像素应用图标图像添加到项目中。

🚨注意:真实的 icon 绝不允许使用这种低清小图像!这里只是为了方便演示在网上随便找了张图(Google 关键词 “BUAA SE”)。

  1. index.html<head> 标签中添加以下代码:
<link rel="manifest" href="/manifest.json">
  1. 添加 PWA 辅助文件 sw.js
const CACHE_NAME = `BUAASE2024-v1`;

// Use the install event to pre-cache all initial resources.
self.addEventListener('install', event => {
  event.waitUntil((async () => {
    const cache = await caches.open(CACHE_NAME);
    cache.addAll([
      '/'
    ]);
  })());
});

self.addEventListener('fetch', event => {
  event.respondWith((async () => {
    const cache = await caches.open(CACHE_NAME);

    // Get the resource from the cache.
    const cachedResponse = await cache.match(event.request);
    if (cachedResponse) {
      return cachedResponse;
    } else {
        try {
          // If the resource was not in the cache, try the network.
          const fetchResponse = await fetch(event.request);

          // Save the resource in the cache and return it.
          cache.put(event.request, fetchResponse.clone());
          return fetchResponse;
        } catch (e) {
          // The network failed.
        }
    }
  })());
});

在主页面 index.html 末尾的 <body> 标签注册 PWA 辅助文件:

<script>
if('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js', { scope: '/' });
}
</script>
  1. 现在再转入 localhost 页面中,会发现你的 PWA 已经可以安装到本地了!

img

img

img

* GUI 库

在过去,你可能已经在 OO 作业等场景中使用过了一些 GUI 库。实际上,这也是一个可行的 “构建独立软件” 的方式,更是往届结对编程作业中最常被同学们使用的类型。因此,笔者打算在此也简要介绍一部分相关的工具。

针对不同的编程语言,有不同的 GUI 库可供使用,每个库都有其独特的特性。你也可以使用语言特定的方法把具备 GUI 的程序打包成一些可执行文件,具体细节感兴趣的同学可自行调研,难度不高。

Tkinter(Python)

Tkinter 是 Python 的标准 GUI 库,它基于 Tk GUI 工具包。它简单易用,适合初学者,同时也提供了足够的功能来构建各种 GUI 应用。它内置于 Python,易于学习和使用,适合快速原型设计。

使用示例:

import tkinter as tk

root = tk.Tk()
label = tk.Label(root, text="BUAASE2024")
label.pack()
root.mainloop()

JavaFX(Java)

JavaFX 是 Java 平台上的现代 GUI 工具包,支持丰富的图形和媒体功能。它是 Java 8 之后版本的标准一部分,可以与 Java 后端集成。

使用示例:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;

public class HelloWorld extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        Label label = new Label("BUAASE2024");
        Scene scene = new Scene(label, 300, 200);
        primaryStage.setScene(scene);
        primaryStage.setTitle("buaase2024");
        primaryStage.show();
    }
}

Qt(C++)

Qt 是一种强大的跨平台 GUI 框架,支持 C++ 编程语言。它提供了大量的 GUI 组件和工具,适用于开发大型应用程序。同时,它支持跨平台,可用于开发比较复杂的图形应用。

使用示例:

#include <QApplication>
#include <QLabel>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QLabel label("BUAASE2024");
    label.show();
    return app.exec();
}

PyQt(Python)

Qt for Python(PyQt)是一个基于 Qt 框架的 Python GUI 库,支持跨平台,且提供了丰富的预定义控件、灵活的布局管理器等,还可以与可视化工具 QtDesigner 集成。正如上节所说,Qt 本身是一个跨平台的 C++ 框架,Qt for Python 只是为 Python 开发者提供了使用 Qt 框架的能力。

使用示例:

from PyQt5.QtWidgets import QApplication, QWidget, QPushButton

class MyWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        btn = QPushButton('Click me', self)
        btn.clicked.connect(self.buttonClicked)

        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('BUAASE2024')
        self.show()

    def buttonClicked(self):
        print('Button clicked!')

if __name__ == '__main__':
    app = QApplication([])
    window = MyWindow()
    app.exec_()

* Electron + Non-Web

如果你想使用非 Web 语言完成软件的后端,但又觉得程序语言的 GUI 库过于原始而丑陋,你可以尝试使用 Electron + 其他语言后端的技术链完成此类独立软件的构建。具体地,你需要准备好原始程序的可链接后端,然后用程序特定的方式与 Electron 引擎进行 “对接”。

  • 对于 C、C++、C# 等,需要 .dll
  • 对于 python 程序,需要用 JavaScript 书写 linker 工具
  • 对于 Java 程序,可以参考这个 已有项目
  • ……

往届的结对编程作业中,有一些组就采用了 .dll + Electron 的方式,构建比较美观的独立软件界面。由于相关开发资料在网上很容易搜集到,请对此部分感兴趣的同学在网上自行搜索,此处不占用篇幅。必要时可以在课程群联系助教寻求帮助。

进阶资料

在体验过前述的入门玩法之后,想必大家已经对独立应用的构建有了初步的了解,或许也已经有了第一印象比较好的框架。以上的内容并不足以支撑大家直接上手构建复杂的软工项目,但这实际上也并不会太难。下面针对 Electron、NW.js 和 PWA 推荐一些学习资料,供大家进一步了解如何将复杂的 Web 应用构建部署成独立软件。

当然,也希望同学们善用搜索引擎,锻炼自己的信息搜集能力。

Electron

  • Vue CLI Plugin Electron Builder:可以使用 Electron + VUE CLI 轻松将 Vue.js 应用构建成桌面端软件,在该项目的结构基础上进行修改即可。
  • electron-vue:开箱即用的 Vue+Electron 脚手架。
  • electron-vite:开箱即用的 Vite+Electron 脚手架,如果你是 Typescript 选手,可以考虑使用它。
  • Electron Forge:一个打包和分发 Electron 应用程序的一站式工具。它将许多单一用途的软件包组合在一起,创建一个开箱即用的完整构建流水线,支持 Vue、TS、React 等多种 Web 前端。
  • Quick Start with Electron using React:一个简单的教授如何部署 React + Electron 工作流的技术博客。入选它是因为它展现了比较完整的 “用 Electron 跑 Web” 的思路(当然,前面的脚手架也都可以体现,只不过需要主动阅读代码和项目结构)。

NW.js

比起 Electron,NW.js 的 “打包” 操作会自然一些。

PWA

PWA 的 “打包” 操作应该是最简单的了,基本上可以当成一个 Web 应用去处理。


感谢你阅读到这里。最后再次强调,本文篇幅有限,笔者的水平也极其非常有限,只是主要起一个扫盲的作用🙇‍♀️🙇‍♀️🙇‍♀️如果有技术力更高、对相关领域了解更多更深入的同学,欢迎在课程群或者课程社区向同学们分享!

Sharing makes us all happy 😊

...全文
5598 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

73

社区成员

发帖
与我相关
我的任务
社区描述
2024年北航敏捷软件工程
软件工程团队开发结对编程 高校 北京·海淀区
社区管理员
  • clotho67
  • Yeyanhan
  • HJin_Gwok
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧