Rust调用Object-C的API
使用Tauri开发了一个Mac系统使用的快捷工具,其中有一个功能,需要得到当前处于最前台的软件的名称。
实在没有找到包含此功能的Rust库,自己使用 Applescript 这个苹果系统的脚本实现了这个功能,但执行很慢,需要300毫秒左右,延迟感人。
没办法,必须调用 Mac 系统开发Api了,也就是调用 Mac 原生的 Object-C 的 API。
需要调用的那个Api的文档: developer.apple.com/documentati… 。
需要下面几步:
执行这段代码,最终只需要话费 4 毫秒左右,我又被深深感动了。
需要使用cargo安装的依赖:
use std::{os::raw::c_char, ffi::CStr};
use objc::{class, sel, sel_impl, msg_send, runtime::Object};
use percent_encoding::percent_decode;
// 表示引入Mac的AppKit这个模块,因为要使用这个模块下的对象
#[link(name = "AppKit", kind = "framework")]
extern "C" {}
fn main() {
// unsafe 代码块,表示开发者知道里面的代码不安全
// 因为要和另一门语言交互,rust必须要确认开发者知道这是不安全的操作
unsafe {
// 获取Mac系统的 AppKit 这个模块下的 NSWorkspace 这个对象
let ns_workspace_class = class!(NSWorkspace);
// 调用 NSWorkspace 的 sharedWorkspace 方法,拿到 sharedWorkspace
let shared_workspace: *mut Object = msg_send![ns_workspace_class, sharedWorkspace];
// 调用 sharedWorkspace 的 frontmostApplication 方法,拿到 frontmostApplication
// 也就是当前处于前台的 app 对象
let app: *mut Object = msg_send![shared_workspace, frontmostApplication];
// 这里可以调用 app 上面的 hide 方法,把这个软件隐藏,相当于系统快捷键 command + h
// let _result: *mut Object = msg_send![app, hide];
// 拿到 app 的软件放置的磁盘位置的 NSURL 对象
let bundle_url: *mut Object = msg_send![app, bundleURL];
// 把 NSURL 转为 NSString,因为 NSURL 继承于 NSObject 这个几类,所以可以使用 description 这个方法
let description_string: *mut Object = msg_send![bundle_url, description];
// 后续操作,是把 object-c 中的 NSString 转为 Rust 的 String 字符串,以便能在 rust 使用
let description: *mut c_char = msg_send![description_string, UTF8String];
let c_str: &CStr = CStr::from_ptr(description);
let str_slice = c_str.to_string_lossy().into_owned();
// str_slice 就是结果,但值是url的格式,里面的空格、特殊符号等是 url 格式:
// file:///Applications/Visual%20Studio%20Code.app/
// 下面把 url 格式的字符串解码
let iter = percent_decode(str_slice.as_bytes());
let decoded = iter.decode_utf8().unwrap();
let decoded = decoded.to_string();
println!("{}", decoded);
// 打印结果:
// file:///Applications/Visual Studio Code.app/
复制代码