Tauri is (rightly) praised as an alternative to Electron. Many talk about it, but without possibly testing the tool, especially not whether you can get a Tauri app published as a macOS app in the Mac App Store (MAS). Are there any stumbling blocks and, if so, which ones?
The Final Product
I successfully published the below app and will share my experience below and in more depth in future articles.
Purpose of this app
Of course, this app is not very useful, after all, you can also import csv files with Microsoft Excel. But I have been using these tasks for a long time to test new programming languages and frameworks. And for the following reasons:
How well do the libraries (here: rust) work and do they also work without a local installation of Microsoft Excel?
Can these libraries also map extended functionalities? A good test for Excel is the ability to recognise number formats and whether you can change the properties (metadata) of the Excel file.
Performance of external libraries.
For the Mac App Store, it is also important whether external libraries cause problems for approval by Apple.
How can we treat light and dark modes? An easy task in swift, but how well does it work with other programming tools?
And last but not least: since apps in the Mac App Store must run in a sandbox: are there effects that have to be taken into account? Since converters have to manage source and target files, this is also a good test.
Why not just use Electron?
Electron is a mature solution, and many well-known productivity tools use it. But the problems are also known: very large binaries, and high memory consumption. Tauri promises a significant improvement here and first of all: it does not disappoint. The uncompressed universal binary (x86 and silicon) from csv2excel needs only 9 megabytes, and the built-in help with its images takes up a large part of the consumption.
Developing the App
csv2excel uses vue3 for the frontend, together with primevue as the theme engine. The HTML help is generated via VitePress as a static site generator tool (still alpha, but working well enough). Pinia is used as a store for the metadata.
Though the conversion of a csv file into an excel file could have been done in pure nodeJS that wasn’t the purpose of this exercise. csv2excel uses pure rust for this.
Caveats with Tauri.app
There weren’t many, everything was fairly well documented. It is quite easy to “report” defined functions in Rust to TypeScript and from there they can be “invoked” and data can be exchanged bidirectionally. This data exchange takes place via JSON and is nothing more than serializing and deserializing data between the front and back ends.
Light / Dark mode
On the one hand, the HTML must be “adjusted” between light and dark modes. Of course, this is easy to do by controlling these changes via CSS. But switching between dark and light mode is more than that because the actual window (in which the HTML view is displayed) should also change. Tauri does an excellent job here if you select the “auto” setting and the app automatically adapts to the macOS setting. There are also corresponding events that can be called up to then adapt the HTML view accordingly.
However, if you want to leave it up to the user to customize the theme in the app, i.e. detached from the system-wide settings, you will not only encounter in Tauri a few challenges. In the current release 1.2 of Tauri, you are not able to change dynamically your theme. However, there seems to be a trick (which works in macOS only):
Once you create a new window you can define if it should open either in light or in dark mode, with the nice “bug?” that the new mode will be applied to the whole app (including the calling window). Hence, I am doing something very(!) ugly: I do open a new very small window in the desired mode and after catching the event that it was successfully created, I am closing that window instantly. This works fine on macOS (but not in Microsoft Windows for instance).
However, I was pretty sure that the Mac App Store would reject my insane idea. I was probably lucky and didn’t notice it, or it’s not forbidden :-). The problem is known to Tauri, but a solution probably requires changes in frameworks that Tauri uses itself.
Approval Process Mac App Store
Like many, I have a mixed relationship with the Mac App Store, but one thing Apple does well is point out issues to developers that they probably haven’t considered.
First (awkward) attempt
Unfortunately, I completely ignored the most important rule that you have to test your signed and notarized application before publishing it (since the app is now sandboxed). The app was rightly rejected for the first time because it only displayed a white screen. Awkward. The entitlement to allow “client” communication on the network must be set. Only after this update did the examiners finally have something to test :-)
In this first attempt, my app logo was also criticized. Although I had the theoretical rights since it was created with canva.com, it was rejected because it contained the Excel logo. So a little thing that just violated the Apple guidelines.
Apple doesn’t like this icon design
Now Apple detected the following challenge:
When relaunching the app, the selected locations are still shown, however, the app no longer has access to them; we advise using the bookmarks entitlement.
And again, of course, they were right, and again — shame on me — I had not tested the behaviour after relaunching the app.
This one is tricky though.
Originally, the idea was that all fields should be kept in local storage, and you don’t always have to fill them out again. This also included the file paths. With the sandbox, however, the end user must of course agree if he wants to give an app permission to access folders. If paths are now saved so that they are already displayed when the app is opened again, these permissions are not checked again (this is only possible by opening the dialogues again, or you use a specific macOS technology: the security-scoped bookmarks). My app didn’t crash, but it showed that there was a problem at the operating system level and the conversion could not be completed. Not pretty, in fact.
You can read more about SSBs here:
tl;dr (summary of the above article)
To put it into simple words, if a user grants you access to a specific directory/file, you can preserve the user intent and access the same directory/file in the future as well. (With that SSB)
Unfortunately this is kind of a show-stopper, at least for the design I had in mind. But on the other hand, does it really make sense to bookmark the paths of a source and destination file in a converter? Probably not, and it is exactly this kind of caveat I wanted to test. So I simply had to change my design and avoid storing the file paths in local storage.
Third and successful attempt
After the appropriate corrections, the app was promptly waved through.
In summary, I can say that the whole process was quite easy. I would have expected a lot more problems, in particular, that the layout of my app would not quite meet Apple’s high standards. And with pinia and the use of local storage, I would have expected limitations.
To be honest, I didn’t have the security-scoped bookmarks on my radar at all. Correcting that would be a trifle in Swift, in Electron there are at least solutions, in Tauri unfortunately not yet. Then there is nothing else you can do but rethink and adapt your logic.
It is very pleasing, however, that nothing was criticized about the JS and Rust code and nothing about the Tauri “framework” as such.
Overall it was a very enjoyable process. It has been a few years since my last Swift applications and they are no longer in the store. Back then, the approval process almost always took at least a week. This time I started on Thursday evening (CET) and the app was already waived through on Saturday afternoon (CET).
It is important to mention that the security-scoped bookmarks are of course not a problem if you distribute your macOS app via other channels. This is the basic problem when using the Mac App Store: due to the strict sandboxing and Apple’s various (security) requirements, you may have to make adjustments to your program here and there. However, most problems can be solved e.g. in Swift, but when using other technologies one can only hope that the API is already offering solutions.
Overall, I think that Tauri has already done an excellent job and I see a lot of potential for the future.