Selling Rust apps in the Mac App Store

Hello,

On my Mac, I've written in Rust quite a few utilities, but until now, they were for my personal use only, and run in the Terminal exclusively. Over the years, these utilities have gotten quite elaborate, and now, I would like to sell some of them in the Mac App Store, because I think other people might be interested in buying them, and because I am poor.

So, I would like to convert my Terminal apps to commercial GUI apps, in such a way that they would be accepted in the Mac App Store. What would be the best way to do this? Among Rust GUI frameworks, "Gtk-rs" looks the most promising, but would Apple actually accept "Gtk-rs" apps in its store? If not, I guess the other solution would be to build the front-end in Swift, and to use my existing Rust code only as back-end, but this looks dawnting for me: I would have to learn the Swift language, and the XCode tooling, from the ground up, at which point I might just as well rewrite everything in Swift, instead of trying to bridge the two languages.

Thank you in advance for your advice or your experience!

Maybe some cocoa bindings would do the job.
Take a look here:


https://kylewlacy.github.io/posts/cocoa-apps-in-rust-eventually/

Are they mac only utilities?

I'm afraid there are no good options for GUIs in rust.

Another option that is often overlooked is wxWidgets. At least there it will be cross platform with platform native widgets. Or QT where it is easier to make it look pretty and keep it cross platform. That way if or when you need to move to another platform the path is straightforward.

As for bridging. Depending on the API surface the method I usually employ to avoid writing a whole lot of annoying bridging code is to serialize objects from one side to the other. Json is always well supported, if better performance is required something like flatbuffers could be used.

For Mac GUI Cocoa is essential. Other toolkits will be second-class and feel foreign.

Cocoa prefers Swift and Objective-C. If you try very hard to avoid them, it's technically possible to use Cocoa straight from Rust:

but it will be pretty painful, because Cocoa's function naming, OO model, and memory management are all alien from Rust's perspective.

If you don't want to make first-class GUI, but just quickly get anything on screen, WebView may be the quickest way:

1 Like

Your best option probably is to write a thin UI layer in Swift or Objective C, and then have an API to the Rust backend. All three languages have great interoperability with C, so you can use that as the interface layer.

Thank you all for your informative answers! I think I will follow the majority's vote, and use Swift for the front-end and Rust for the back-end. I was worried about exchanging complex data between the two languages, but Sergej's suggestion of using a binary serialization format, equivalent to JSON, as go-between makes perfect sense to me. I should've thought about it myself. After some research, MessagePack looks like an efficient format of this kind: it's supported by the "serde" crate in Rust, which I am quite familiar with, and I found a MessagePack implementation written in Swift. But if you have other suggestions or ressources for bridging Rust and Swift, I am all ears!

You could isolate most of the actual work as a Rust process that the GUI app starts as a separate process and gets the result back. This is now for example ripgrep is integrated into Electron/VSCode.

And yes, app store accepts any framework apps as long as it passes their automated cert testing tools.

PS: We really need something like Ruby Shoes for quick GUI apps with Rust code, cross-platform.

1 Like

If your utilities aren't macOS-only you should definitely go for QT. If you only need to deploy on macOS, then stick to your choice of writing the UI in Xcode with Swift and use your Rust code as back-end.

An example of this kind of thing working well in practice - the Language Server Protocol (used by VS Code and other IDEs to talk to language servers written in any language) is actually built on top of the JSON-RPC spec. So whenever you're using, for example, the RLS, your editor is actually sending JSON messages to another library/process and back.

If something like that can be performant enough to react to your keypresses in an editor, it's probably good for most cases :slight_smile:

Shipping multiple binaries in a MAS app is pretty complicated due to code signing and sandbox requirements. The best way to do that is an XPC service that uses a complicated message passing system, which can be killed at any moment by the system.

You can't compare that to Electron or VS Code, as these aren't distributed through the Mac App Store (and also, couldn't).

I will create a library in Rust that can be called from C, as Anlumo suggested, with a bunch of functions looking like this:

#[no_mangle]
pub extern "C" fn first_rust_function()
{ }

#[no_mangle]
pub extern "C" fn second_rust_function()
{ }

Calling a library seems more robust to me than launching a distributable binary. Also, I think that a distributable binary would be extremely prone to commercial theft (I am creating a paid product, after all).

Code signing and sandbox requirements are the same for Objective-C/Swift frameworks as for other frameworks. You don't even need RPC in case you just link rust libraries with C code.

I never said that VSC is shipped in Mac App store -- it's just one model of how to integrate Rust. I should research but I do think there are some Electron apps shipping in the app store, btw.

The problem is that you have to sign every executable you ship. If you create a separate executable for your rust code, you have to sign it manually (since Xcode can't help you there). This is possible, but even harder than getting Xcode to properly sign your binaries (which I've already wasted countless hours on).