构建和发布 Linux 应用程序到 Snap Store

在典型的开发周期中,你可以使用命令行上的 flutter run 测试应用程序,或者使用 IDE 中的运行调试选项。默认情况下,Flutter 会构建应用程序的调试版本。

当你准备为应用程序准备发布版本时,例如 发布到 Snap Store,此页面可以提供帮助。

先决条件

要构建并发布到 Snap Store,你需要以下组件

设置构建环境

使用以下说明设置构建环境。

安装 snapcraft

在命令行中,运行以下命令

$ sudo snap install snapcraft --classic

安装 LXD

要安装 LXD,请使用以下命令

$ sudo snap install lxd

在 snap 构建过程中需要 LXD。安装后,需要配置 LXD 以供使用。默认答案适用于大多数用例。

$ sudo lxd init
Would you like to use LXD clustering? (yes/no) [default=no]:
Do you want to configure a new storage pool? (yes/no) [default=yes]:
Name of the new storage pool [default=default]:
Name of the storage backend to use (btrfs, dir, lvm, zfs, ceph) [default=zfs]:
Create a new ZFS pool? (yes/no) [default=yes]:
Would you like to use an existing empty disk or partition? (yes/no) [default=no]:
Size in GB of the new loop device (1GB minimum) [default=5GB]:
Would you like to connect to a MAAS server? (yes/no) [default=no]:
Would you like to create a new local network bridge? (yes/no) [default=yes]:
What should the new bridge be called? [default=lxdbr0]:
What IPv4 address should be used? (CIDR subnet notation, "auto" or "none") [default=auto]:
What IPv6 address should be used? (CIDR subnet notation, "auto" or "none") [default=auto]:
Would you like LXD to be available over the network? (yes/no) [default=no]:
Would you like stale cached images to be updated automatically? (yes/no) [default=yes]
Would you like a YAML "lxd init" preseed to be printed? (yes/no) [default=no]:

在首次运行时,LXD 可能无法连接到其套接字

An error occurred when trying to communicate with the 'LXD'
provider: cannot connect to the LXD socket
('/var/snap/lxd/common/lxd/unix.socket').

这意味着你需要将你的用户名添加到 LXD (lxd) 组,因此请注销你的会话,然后重新登录

$ sudo usermod -a -G lxd <your username>

snapcraft 概述

snapcraft 工具基于 snapcraft.yaml 文件中列出的说明构建 snap。要对 snapcraft 及其核心概念有一个基本的了解,请查看 Snap 文档snapcraft 简介。其他链接和信息列在本页底部。

Flutter snapcraft.yaml 示例

将 YAML 文件放在 Flutter 项目中的 <project root>/snap/snapcraft.yaml 下。(请记住,YAML 文件对空格敏感!)例如

name: super-cool-app
version: 0.1.0
summary: Super Cool App
description: Super Cool App that does everything!

confinement: strict
base: core22
grade: stable

slots:
  dbus-super-cool-app: # adjust accordingly to your app name
    interface: dbus
    bus: session
    name: org.bar.super_cool_app # adjust accordingly to your app name and
    
apps:
  super-cool-app:
    command: super_cool_app
    extensions: [gnome] # gnome includes the libraries required by flutter
    plugs:
    - network
    slots:
      - dbus-super-cool-app
parts:
  super-cool-app:
    source: .
    plugin: flutter
    flutter-target: lib/main.dart # The main entry-point file of the application

以下部分解释了 YAML 文件的各个部分。

元数据

snapcraft.yaml 文件的此部分定义和描述了应用程序。snap 版本是从构建部分派生(采用的)。

name: super-cool-app
version: 0.1.0
summary: Super Cool App
description: Super Cool App that does everything!

等级、限制和基础

此部分定义了如何构建 snap。

confinement: strict
base: core18
grade: stable
等级
指定 snap 的质量;这与后面的发布步骤相关。
限制
指定安装在最终用户系统上后 snap 将拥有的系统资源访问级别。严格限制会限制应用程序访问特定资源(由 app 部分中的插头定义)。
基础
Snap 被设计为自包含应用程序,因此,它们需要自己的私有核心根文件系统,称为 basebase 关键字指定用于提供最小公共库集的版本,并在运行时作为应用程序的根文件系统挂载。

应用程序

此部分定义了 snap 中存在的应用程序。每个 snap 可以有一个或多个应用程序。此示例有一个应用程序,即 super_cool_app。

apps:
  super-cool-app:
    command: super_cool_app
    extensions: [gnome]
命令
指向相对于 snap 根的二进制文件,并在调用 snap 时运行。
扩展
一个或多个扩展的列表。Snapcraft 扩展是可重用组件,可以在构建和运行时向 snap 公开一组库和工具,而无需开发人员具备所包含框架的具体知识。gnome 扩展向 Flutter snap 公开了 GTK 3 库。这确保了更小的占用空间和与系统的更好集成。
插头
一个或多个系统接口插头的列表。当 snap 受到严格限制时,需要这些插头来提供必要的功能。此 Flutter snap 需要访问网络。
DBus 接口
DBus 接口 提供了一种通过 DBus 进行通信的方式。提供 DBus 服务的 snap 声明了一个具有众所周知的 DBus 名称且使用其总线的插槽。想要与提供 snap 的服务进行通信的 snap 声明一个用于提供 snap 的插槽。请注意,需要一个 snap 声明才能通过 snap 商店提供你的 snap 并声明这个众所周知的 DBus 名称(只需将 snap 上传到商店并请求手动审核,审阅人员会进行查看)。

在安装提供 snap 时,snapd 将生成安全策略,允许其在指定总线上侦听众所周知的 DBus 名称。如果指定了系统总线,snapd 还将生成 DBus 总线策略,允许“root”拥有该名称,并允许任何用户与该服务进行通信。非 snap 进程允许在遵循传统权限检查后与提供 snap 进行通信。其他(使用)snap 可能只通过连接 snap 的接口与提供 snap 进行通信。

dbus-super-cool-app: # adjust accordingly to your app name
  interface: dbus
  bus: session
  name: dev.site.super_cool_app 

部分

本部分定义了组装 snap 所需的源。

可以使用插件自动下载和构建部分。与扩展类似,snapcraft 可以使用各种插件(例如 Python、C、Java 和 Ruby)来协助构建过程。Snapcraft 还有一些特殊插件。

nil 插件
不执行任何操作,实际构建过程使用手动覆盖来处理。
flutter 插件
提供必要的 Flutter SDK 工具,以便你无需手动下载和设置构建工具即可使用它。
parts:
  super-cool-app:
    source: .
    plugin: flutter
    flutter-target: lib/main.dart # The main entry-point file of the application

桌面文件和图标

桌面条目文件用于将应用程序添加到桌面菜单。这些文件指定应用程序的名称和图标、它所属的类别、相关的搜索关键字等。这些文件具有扩展名 .desktop,并遵循 XDG 桌面条目规范版本 1.1。

Flutter super-cool-app.desktop 示例

将 .desktop 文件放在 Flutter 项目中的 <project root>/snap/gui/super-cool-app.desktop 下。

注意:图标和 .desktop 文件名必须与 yaml 文件中的应用名称相同!

例如

[Desktop Entry]
Name=Super Cool App
Comment=Super Cool App that does everything
Exec=super-cool-app 
Icon=${SNAP}/meta/gui/super-cool-app.png # replace name to your app name
Terminal=false
Type=Application
Categories=Education; #adjust accordingly your snap category

将带有 .png 扩展名的图标放置在 Flutter 项目中的 <project root>/snap/gui/super-cool-app.png 下。

构建 snap

一旦 snapcraft.yaml 文件完成,从项目的根目录中运行 snapcraft,如下所示。

使用 Multipass VM 后端

$ snapcraft

使用 LXD 容器后端

$ snapcraft --use-lxd

测试 snap

一旦 snap 构建完成,你将在根项目目录中拥有一个 <name>.snap 文件。

$ sudo snap install ./super-cool-app_0.1.0_amd64.snap –dangerous

发布

你现在可以发布 snap。该过程包括以下内容

  1. snapcraft.io 上创建一个开发者帐户,如果你还没有这样做的话。
  2. 注册应用名称。注册可以通过 Snap Store Web UI 门户或从命令行完成,如下所示
    $ snapcraft login
    $ snapcraft register
    
  3. 发布应用。在阅读下一部分以了解如何选择 Snap Store 频道后,将 snap 推送到商店
    $ snapcraft upload --release=<channel> <file>.snap
    

Snap Store 频道

Snap Store 使用频道来区分不同版本的 snap。

snapcraft upload 命令将 snap 文件上传到商店。但是,在你运行此命令之前,你需要了解不同的发布频道。每个频道由三个组件组成

轨道
所有 snap 必须有一个名为 latest 的默认轨道。除非另有说明,否则这是隐含的轨道。
风险
定义应用程序的准备情况。snap 商店中使用的风险级别为:stablecandidatebetaedge
分支
允许创建短期 snap 序列来测试 bug 修复。

Snap Store 自动审核

Snap Store 对你的 snap 运行了几项自动检查。也可能有人工审核,具体取决于 snap 的构建方式,以及是否存在任何特定的安全问题。如果检查通过且没有错误,则 snap 将在商店中可用。

其他资源

你可以从 snapcraft.io 网站上的以下链接了解更多信息