使用 Swift 编写 Gnome 应用程序
Writing Gnome Apps with Swift

原始链接: https://www.swift.org/blog/adwaita-swift/

该文本讲述的是一位名叫 David 的学生,他对使用 Swift 开发 GNOME 应用程序感兴趣。 他提到,Swift 适合创建用户界面,因为它具有简洁的语法、静态类型,并且 Swift 的结果生成器与闭包表达式语法相结合,增强了代码的可读性。 然后,学生介绍了 Adwaita for Swift,这是一个旨在促进 GNOME 应用程序的 Swift 开发的软件包。 该包采用以数据为中心的方法,与传统的命令式绑定方法相比,使代码更简单、更具可读性、更易于维护。 此外,该包允许开发人员声明性地定义其用户界面,从而实现设计人员和开发人员之间更好的协作。 此外,Adwaita for Swift 支持跨平台应用程序开发(Linux、macOS 和 Windows),在 SwiftUI 应用程序和 GNOme 应用程序之间共享后端代码,并与用于分发桌面 Linux 应用程序的流行应用程序商店 Flathub 良好集成。 最后,该软件包通过贡献、问题报告、文档创建、在 GitHub 上观星、探索 Memorize(第一个 Adwaita for Swift 应用程序)等方式鼓励社区参与。 文本最后提供了许可信息以及 Apple 和 Swift 的联系方式。

这是不正确的。 Ubuntu 安装程序附带的 Unity 桌面环境是用 C++ 编写的,Shell 的某些部分是用 Ruby 编写的。 在 Ubuntu 17.10 及更高版本中,它被 GNOME 桌面环境取代。 适用于 Ubuntu 的 Flutter 端口可通过 Snapcraft 获得,但并未得到官方支持,这意味着除了 Snap 维护者提供的之外,不保证更新和错误修复。 此外,它还需要单独安装 Dart SDK 和 FLANNGI 索引库,这对于喜欢为其首选生产力软件提供更集成解决方案的用户来说增加了额外的复杂性。 关于有关 SwiftUI 与 Gtk 的原始问题,我建议根据目标应用程序的要求和约束来评估这两种解决方案。 对于简单、快速的原型或需要低学习曲线和良好性能的个人项目,如果安装了 Swift 运行时和 LSP 客户端,我会倾向于 SwiftUI。 然而,对于需要广泛定制和与现有系统紧密集成的大型项目,我更喜欢 Gtk,因为它具有经过验证的稳定性、成熟度和社区支持。 这两种工具都有各自的优点和挑战,根据场景的不同,没有一种工具本质上优于另一种工具。 为了提供更多背景信息,请考虑分享有关预期用例和期望结果的详细信息,包括速度、大小、复杂性、兼容性和学习曲线等因素。 此外,考虑到技术领域不断发展的本质,在选择面向未来的 UI 技术堆栈时,优先考虑适应性和灵活性至关重要。 密切关注 SwiftUI 生态系统的发展和进步可能有利于整体用户体验和开发效率的潜在改善。
相关文章

原文

David is a student interested in Swift and the GNOME Project.

Swift is well-suited for creating user interfaces thanks to the clean syntax, static typing, and special features making code easier to write. Result builders, combined with Swift’s closure expression syntax, can significantly enhance code readability.

Adwaita for Swift leverages these Swift features to provide an intuitive interface for developing applications for the GNOME platform. GNOME is a popular, open source desktop environment for Linux, known for its emphasis on simplicity and accessibility. It offers an intuitive user interface, with a vast app ecosystem built using its modern Adwaita design language. Explore a collection of great apps under Apps for GNOME.

Let’s look at a code example of using Adwaita for Swift. The following code snippet defines a view, which represents a part of the user interface inside a window.

struct Counter: View {

    @State private var count = 0

    var view: Body {
        HStack {
            Button(icon: .default(icon: .goPrevious)) {
                count -= 1
            }
            Text("\(count)")
                .style("title-1")
                .frame(minWidth: 100)
            Button(icon: .default(icon: .goNext)) {
                count += 1
            }
        }
    }

}

A view can be nested within other views or added as the child of a window.

Its content can be modified from outside that view and is influenced by its position in the view hierarchy. This makes it easier to compose views to produce different results. The screenshot shows one simple possibility.

A screenshot of the counter example app.

Motivation

The primary motivation for this package is to enable the use of Swift when writing GNOME apps, for all the reasons outlined above. But there are a few additional reasons:

Declarative

While there are already libadwaita and GTK bindings for numerous modern programming languages, including Rust, Python, and JavaScript, all official bindings follow an imperative coding style. This can be verbose and harder to follow than a declarative style as user interfaces are constructed using a series of commands. The following Python code serves as an illustration of this.

class Counter(Gtk.Box):

    def __init__(self):
        Gtk.Box.__init__(self, orientation=Gtk.Orientation.HORIZONTAL, spacing=6)
        self.count = 0

        button_prev = Gtk.Button.new_from_icon_name("go-previous", Gtk.IconSize.BUTTON)
        button_prev.connect("clicked", self.on_prev_clicked)
        self.pack_start(button_prev, True, True, 0)

        self.label = Gtk.Label(label=str(self.count))
        self.label.set_name("title-1")
        self.pack_start(self.label, True, True, 0)

        button_next = Gtk.Button.new_from_icon_name("go-next", Gtk.IconSize.BUTTON)
        button_next.connect("clicked", self.on_next_clicked)
        self.pack_start(button_next, True, True, 0)

    def on_prev_clicked(self, button):
        self.count -= 1
        self.label.set_text(str(self.count))

    def on_next_clicked(self, button):
        self.count += 1
        self.label.set_text(str(self.count))

This Python code uses the PyGObject library and produces the same user interface as the Swift code above.

Ease of Use

As you can see, Adwaita for Swift is built around data. For example, changing the variable count when pressing one of the buttons in the sample app will automatically update the user interface. Traditional bindings require you to call a function on the object holding a widget that should update its content once a value changes.

If you decide to store the value on the disk so that it persists between startups of the app, you would have to add a lot of complexity to your code using traditional bindings. Adwaita for Swift enables you to simply add a unique identifier to the variable that should be stored, and will take care of the rest.

@State("count") private var count = 0

There is also a simple and safe approach for localization with the Localized package.

Readability

The simplicity coming with the data-centric approach has a positive impact on readability.

Another point is the declarative definition of the user interface itself. You can focus on what the app should look like and how it should behave rather than how to achieve those results.

While there are other solutions available, such as defining the UI with XML and Blueprint, they require the user interface and actual code to be written in different files. Also, updating the user interface has to be done manually whenever data changes. This makes it more difficult to follow the logic as a reader.

As the user interface is written in Swift, you can use convenient Swift syntax directly in your user interface definition.

var view: Body {
    if count == 0 {
        Text("😍")
    } else {
        Text("\(count)")
    }
}

Cross-Platform App Development

Adwaita for Swift is useful in a number of ways:

  • You can write apps that run on Linux, macOS and Windows with a single codebase.
  • You can share backend Swift code between SwiftUI apps and GNOME apps.
  • You can create entirely new GNOME apps using Swift, achieving great code readability and memory safety.

Publish Apps

In addition to traditional distribution packages, Adwaita for Swift works great with Flathub. Flathub is an app store powered by Flatpak which simplifies the installation and publishing of apps for desktop Linux.

There is the Freedesktop SDK Extension for Swift 5 which adds support for Swift, and a tool to convert Swift Package Manager dependencies into Flatpak sources.

Learn how to publish your apps in the Adwaita for Swift documentation.

Get Involved

Each contribution to this project is highly appreciated.

You can:

  • Create an app! Use the template repository as a starting point and refer to the tutorial. Feel free to showcase your project in the discussions. Note that libadwaita works best on Linux. If you’re on a newer Mac and interested in Linux, check out Asahi Linux.
  • Open issues if you find any problems or if you have an idea, or participate in the dicussions by asking questions, dicussing ideas, or informing others about your work.
  • Write documentation to help others understand Adwaita for Swift.
  • Simply star the repository to improve its discoverability.
  • Take a look at the Memorize app. It is the first app on Flathub built using Adwaita for Swift.

Thanks for your participation ❤️

联系我们 contact @ memedata.com