8 个版本
0.4.0-测试版2 | 2023 年 8 月 1 日 |
---|---|
0.4.0-测试版1 | 2023 年 6 月 8 日 |
0.3.2 | 2022 年 8 月 16 日 |
0.3.0 | 2022 年 7 月 12 日 |
0.1.0 | 2020 年 4 月 1 日 |
#1 in #appkit
每月 485 次下载
用于 2 crates
735KB
12K SLoC
Cacao
此库为 macOS (测试版,基本可用) 上的 AppKit
和 iOS/tvOS 上的 UIKit
提供安全的 Rust 绑定(alpha 版本,请参阅仓库)。它试图以一种方式做到这一点,如果您之前(在 Swift 或 Objective-C 中)为框架编写过程序,那么它将感觉熟悉。在 Rust 中,由于所有权模型,这很棘手,但一些创造性的编码和假设可以让我们走得很远。
此库存在于 crates.io 上,部分原因是为了使项目能够看到更广泛的使用,这可以指导开发。话虽如此,此库目前处于早期阶段,可能存在错误 - 您使用它时请自行承担风险。然而,如果您遵循规则(有关内存/所有权),它已经可以用于某些应用程序。核心仓库包含大量示例,可以帮助您开始。
重要
如果您正在从 0.2 迁移到 0.3,请在您的
Cargo.toml
中选择appkit
或uikit
作为功能。此更改是为了支持不仅限于 macOS/iOS/tvOS 的平台(例如,gnustep,airyx)。这些功能之一是必需的;为了便于开发,默认为appkit
。
请注意,此 crate 依赖于 Objective-C 运行时。与运行时的接口 需要 不安全块;此 crate 为您处理这些不安全交互,并提供了一个安全的包装器,但通过使用此 crate,您理解使用
unsafe
是既定的,并且对于包装控件来说将会相当普遍。这 并不意味着 您不能评估、审查或质疑不安全的使用 - 只要知道它在发生,并且很大一部分不会消失。有关仅存在不安全的议题将被无评论关闭。
如果您想在本地的机器上构建文档,需要以下内容,因为功能标志与cargo doc
的工作方式有关
RUSTDOCFLAGS="--cfg docsrs"cargo+nightly doc--all-features--open
Hello World
use cacao::appkit::{App, AppDelegate};
use cacao::appkit::window::Window;
#[derive(Default)]
struct BasicApp {
window: Window
}
impl AppDelegate for BasicApp {
fn did_finish_launching(&self) {
self.window.set_minimum_content_size(400., 400.);
self.window.set_title("Hello World!");
self.window.show();
}
}
fn main() {
App::new("com.hello.world", BasicApp::default()).run();
}
有关更详细的示例,请查看examples/
文件夹。
如果您对更“厨房水槽”式的示例感兴趣,请查看todos_list,使用
cargo run --example todos_list
初始化
由于AppKit和UIKit程序通常的工作方式,建议您从您的AppDelegate
中的did_finish_launching
方法开始大部分工作。这确保了应用程序有足够的时间进行初始化和完成后台的任何必要维护。
当前支持
以下表格展示了不同功能的支持水平。这个列表并不全面,因为文档更新很困难——因此,建议您查看代码生成的文档以获取更多信息。
请注意,虽然iOS有绿色勾选标记,但某些组件仍然定义得不够清晰(例如,Views/ViewControllers在那里仍然非常初阶)。
非Apple平台可能可以通过模拟或提供AppKit的形式来使用该库中大部分的AppKit支持。
组件 | 描述 | AppKit | iOS | tvOS |
---|---|---|---|---|
App | 初始化 & 事件 | ✅ | ✅ | ❌ |
窗口 | 构建、处理、事件 | ✅ | ✅ | ❌ |
视图 | 构建、样式、事件 | ✅ | ✅ | ❌ |
视图控制器 | 构建、生命周期事件 | ✅ | ✅ | ❌ |
颜色 | 系统颜色、主题 | ✅ | ✅ | ❌ |
列表视图 | 可复用的列表,具有缓存的行 | ✅ | ❌ | ❌ |
按钮 | 样式、事件、工具栏支持 | ✅ | ❌ | ❌ |
标签/文本框 | 文本渲染 & 输入 | ✅ | ❌ | ❌ |
图片/图片视图 | 加载、绘制等 | ✅ | ✅ | ❌ |
工具栏 | 基本原生工具栏 | ✅ | ❌ | ❌ |
分割视图控制器 | 分割视图(Big Sur兼容) | ✅ | ❌ | ❌ |
网页视图 | WKWebView包装器 | ✅ | ❌ | ❌ |
UserDefaults | 持久化小数据 | ✅ | ✅ | ❌ |
自动布局 | 不同屏幕的视图布局 | ✅ | ✅ | ❌ |
可选功能
以下是可以启用或禁用的Cargo功能列表。
appkit
:链接AppKit.framework
。uikit
:链接UIKit.framework
(仅限iOS/tvOS)。cloudkit
:链接CloudKit.framework
并提供一些CloudKit功能的包装器。目前功能尚不完整。color_fallbacks
:为旧系统提供回退颜色,其中不存在systemColor
类型。此功能非常不常见,您可能不需要它。quicklook
:链接QuickLook.framework
并提供生成文件预览图片的方法。user-notifications
:链接UserNotifications.framework
并在macOS和iOS上提供发出通知的功能。注意,此功能需要您的应用程序进行代码签名,并且没有代码签名将无法使用。webview
:链接WebKit.framework
并提供由WKWebView
支持的WebView
控件。由于平台没有 webview 控件,此功能在 tvOS 上不受支持。由于 WKWebView 控件和非 Apple 平台支持不一,此功能可能也仅支持 macOS/iOS。webview-downloading-macos
:通过私有接口启用从WebView
下载文件。这不是 App-Store 安全的功能,因此启用前请留意。此功能在 iOS(用户处理下载的方式非常不同)或 tvOS(那里根本没有任何网络浏览器)上不受支持。
一般注意事项
为什么不扩展现有的 cocoa-rs 库?
这是一个很好的问题。最终,我认为这个库(如果我没有错的话)与 Servo 有一定关联,而我想试验在 Rust 中表示 Cocoa UI 模型的最佳方法。这个库并没有完全忽视他们的工作 - core_foundation
和 core_graphics
在内部使用并重新导出以供通用使用。
为什么我要用 Rust 写,而不是 X 语言?
在我的情况下,我想能够为我的设备(以及我喜欢构建产品的平台)编写原生应用程序,而不必局限于使用 Apple 特定的语言...也不必使用 C/C++ 或 JavaScript(注意:这里是指 工具链,而不是语言 - ES6/Typescript 是可以接受的)。我想这样做是因为我厌倦了在想要将我的应用程序移植到其他生态系统时遇到的大量工作。我认为 Rust 提供了一个(日益增长但重要的)可行的跨平台和生态系统代码共享模型,而不会牺牲性能。
(这是互联网上关于 Electron、Qt 等等的抱怨和狂热的地方 - 我们在这里不费心,因为这些问题在其他地方已经被讨论得很多了)
这个库对于不需要完全投入 Apple 生态系统,但想相对容易地将他们的工作移植到该生态系统的人很有用。我们不期望每个人都突然想要用 Rust 重写他们的 macOS/iOS/tvOS 应用程序。
Objective-C 不再流行了吗?
是的,也不是。
诚然,苹果确实倾向于 Swift,并且有充分的理由(我说这话时是一个不掩饰的 Objective-C 爱好者)。话虽如此,如果没有另外 5+ 年的支持,我会感到惊讶;苹果删除得很快,但移除 Objective-C 运行时会需要大量的时间和努力。也许 SwiftUI 会消灭它,谁知道呢。围绕这些内容的包装应该可以在需要更换底层 UI 后端时使其更容易。
值得注意的是,苹果已经开始发布仅支持 Swift 的框架。对于需要这些框架的情况,应该可以执行一些链接和桥接的组合 - 这将指导如何在某一点上更换底层 UI 后端。
有些人也可能批评 Objective-C 速度慢。对此,我要指出以下内容:
- 您的 UI 引擎可能不是瓶颈。
- Swift 通常更好,因为它修复了 Objective-C 无法捕获的一类错误;大多数情况下,它仍然位于现有的 Cocoa 框架之上(尽管这个声明不会保持不变)。
- Objective-C 中的消息传递比您将编写的代码中的大部分代码都要优化,并且足够快以处理大多数事情。
总结,它可能没问题,您有 Rust 来满足您的性能需求。
为什么不直接包装 UIKit,然后依赖 Catalyst?
我还从未见过一个应用让Catalyst感觉良好。虽然目标很好,但如果到了这种程度,它似乎就是前进的方向(例如,苹果直接杀死AppKit),那么这确实是一个选择。
你不可能在这里包裹所有平台特定的行为...
没错!每个UI控件都包含一个objc
字段,你可以将其用作逃生门——如果控件不支持某项功能,你可以自由地降级到Objective-C运行时自行处理。
你为什么不使用绑定来自动生成这些内容呢?
出于初步探索的目的,我大部分都是手动完成的,因为我想在投入绑定生成之前找到一个适合Rust模型的方法。现在事情已经“良好”地运行,我可能会集中精力关注这个。
这与Swift项目Cacao有关吗?
不。这个问题中提到的项目旨在将Cocoa和UIKit的部分映射到Linux上运行,但已经有一段时间没有活动了(它真的很酷!)。
2020年开源项目命名就像尝试购买一个.com
域名:所有好的都被占用了。幸运的是,多个项目可以共享一个名字...所以这里也会发生这种情况。
这不是在欺骗Rust对象模型吗?
这取决于你怎么看。我个人不是很关心——对于某些类别的产品来说,GUI层是支持硬要求,放弃它也意味着放弃用于辅助功能和更深层OS集成的经过战斗检验的工具。话虽如此,内部有努力尝试让事情尊重Rust对事物应该如何工作的模型。
你可以把它想象成类似于gtk-rs。如果你想支持或尝试一个更纯的模式,可以去看看Druid或其他东西。 :)
许可证
双许可下MIT/MPL-2.0许可证。有关更多信息,请参阅本存储库中的相应文件。Apple、AppKit、UIKit、Cocoa等商标均为Apple公司版权所有。
问题、评论等
依赖关系
~2–11MB
~128K SLoC