我们如何构建一个使用 Rust 的 Swift 应用
信任动态数据
昨天,我们团队 发布了 Portals ,这是一款用 Swift 构建的开源 Mac 应用。它使用 Ockam Rust 库,通过端到端加密的 Ockam Portals,将您的 Mac 上的 TCP 或 HTTP 服务私密地分享给您的朋友。共享服务会显示在他们 本地主机 上!
在这篇文章中,我将 深入研究 SwiftUI macOS 应用程序如何与 Rust 代码交互。
如果你对 Mac 版 Portals 感兴趣,可以阅读 本文 了解更多信息,并使用 Homebrew 进行安装,步骤如下:
brew install build-trust/ockam/portals
Enter fullscreen mode
Exit fullscreen mode
以下是该应用程序运行的 2 分钟视频:
VIDEO
Swift <> Rust
Portals 功能已在 Ockam Rust 库中实现。我们致力于打造出色的 macOS 原生体验。
我们最初尝试使用 Tauri 来构建这款应用。这很合理,因为我们想使用 Ockam Rust 库,而且我们团队中的大多数人都熟悉用 Rust 构建。这个初始版本很容易构建,并且具备我们所需的所有基本功能。然而,这款应用的使用体验并不理想。Tauri 只允许我们对菜单的渲染方式以及用户与菜单交互时的操作进行有限的控制。与 macOS Sonoma 内置的超级易用的菜单栏项目相比,这个版本的应用感觉就像是 macOS 十年前的旧版本。
我们意识到,要获得我们想要的丰富体验,我们必须使用 SwiftUI 构建应用程序。
遗憾的是,我们找不到一个现成的解决方案来整合 Swift 和 Rust,从而兼顾两者的优势:Rust 的安全性和 SwiftUI 丰富的 macOS 原生体验。经过进一步的研究,我们意识到可以使用 C-89 将两者连接起来。Rust 兼容 C 调用约定,而 Swift 可以与 Objective-C(C-89 的超集)互操作。
我们编写了两次需要 Swift 可见的 Rust 数据结构。一个版本符合 Rust 的惯用语言规范,易于使用。另一个版本与 C 兼容,使用指针和手动分配的内存 malloc
。我们还公开了一些 C 兼容 API,这些 API 使用非安全 Rust 中的原始指针,将惯用数据结构转换为 C 兼容版本。最后,我们借助 cbindgen
库自动生成了 C 头文件。
在 Swift 方面,我们可以直接调用 C API,但 C 数据结构在 Swift 中并非“一等公民”。这使得它们在 SwiftUI 代码中难以惯用。因此,我们选择在 Swift 中复制数据结构,并在 C 和 Swift 之间进行转换。这看起来可能很麻烦,但实际上,共享状态并不会经常更改。能够使用诸如 、 等结构在 SwiftUI 中快速构建组件 if let ..
非常 ForEach
实用 enum
,值得为此付出代价。
以下是相同结构 4 种形式的示例:
// Rust idiomatic structure
#[derive(Default, Clone, Debug, Eq, PartialEq)]
pub struct LocalService {
pub name: String,
pub address: String,
pub port: u16,
pub shared_with: Vec<Invitee>,
pub available: bool,
}
// Rust C-compatible structure
#[repr(C)]
pub struct LocalService {
pub(super) name: *const c_char,
pub(super) address: *const c_char,
pub(super) port: u16,
pub(super) shared_with: *const *const Invitee,
pub(super) available: u8,
}
// Generated C header structure
typedef struct C_LocalService {
const char *name;
const char *address;
uint16_t port;
const struct C_Invitee *const *shared_with;
uint8_t available;
} C_LocalService;
// Swift idiomatic structure
class LocalService {
let name: String
@Published var address: String?
@Published var port: UInt16
@Published var sharedWith: [Invitee]
@Published var available: Bool
}
Enter fullscreen mode
Exit fullscreen mode
Swift 应用在编译时静态链接到我们的 Rust 库。数据流很简单:UI 交互通过调用 C API 从 Swift 发送到 Rust,作为操作;更改事件仅由 Rust 发出;然后使用回调通知 Swift,从而更新 UI。
SwiftUI 视图中的大多数代码看起来就像任何其他 SwiftUI 应用程序一样。
VStack ( alignment : . leading , spacing : 0 ) {
Text ( service . sourceName ) . lineLimit ( 1 )
HStack ( spacing : 0 ) {
Image ( systemName : "circle.fill" )
. font ( . system ( size : 7 ))
. foregroundColor ( service . enabled ? ( service . available ? . green : . red ) : . orange )
if ! service . enabled {
Text ( verbatim : "Not connected" )
} else {
if service . available {
Text ( verbatim : service . address . unsafelyUnwrapped + ":" + String ( service . port ))
} else {
Text ( verbatim : "Connecting" )
}
}
}
...
Enter fullscreen mode
Exit fullscreen mode
如果您想了解更多信息,请查看 ockam_app_lib 包 和 Portals 应用的 Swift 代码。swift文件夹中的 Makefile 也是探索所有内容如何构建和链接在一起的好地方。
如果您有兴趣为应用的 Swift 或 Rust 代码做出贡献,我们 每周都会 添加新的 优质首发问题,并乐于帮助新的贡献者。欢迎在 贡献者 Discord 上加入我们。
了解有关 Mac 版 Portal 的更多信息
大规模协调分布式应用程序之间的端到端加密、加密身份、相互认证和授权策略。
🚀 Mac 版 Portals – 一款使用 Swift 构建的 macOS 应用,它使用 Ockam Rust 库,可在 Mac 上与任何人、任何地点私密共享服务。该服务通过端到端加密且相互认证的 Ockam Portal 安全共享。您的朋友可以在 本地主机 上访问它!这款应用是您使用 Ockam 构建各种应用的绝佳范例 👉
信任动态数据
Ockam 是一套开源编程库和命令行工具,用于大规模协调端到端加密、相互认证、密钥管理、凭证管理和授权策略实施。
现代应用程序是分布式的,拥有大量必须可靠地交换数据的互连。为了确保数据在传输过程中的可信度,应用程序需要端到端地保证数据的真实性、完整性和机密性。为了在设计上确保隐私和安全,应用程序必须对每个信任和访问决策进行精细的控制。……
鏂囩珷鏉ユ簮锛�https://dev.to/build-trust/how-we-built-a-swift-app-that-uses-rust-102f