Apps
crossbind builds a Vite page and the native code it imports into an app for macOS, Linux, Windows, iOS and Android. The page runs in the system webview; the C++ and Rust run natively in the app's own process, with no Node.js and no browser engine of its own.
Setup
Start from the template:
Or, in an existing Vite project, install the app host and set the runtime environment to app:
vite.config.js registers the plugin as for the browser. C++ goes in src/native, and the page imports its headers as a web page does:
Every call, new and property read returns a promise, as in a web build that runs its module in a worker. An object stays in the app's process while the page holds a handle to it, which the garbage collector releases, and an error keeps its own fields, such as code.
Develop and build
| Command | What it does |
|---|---|
crossbind app dev | Opens this machine's app on Vite's dev server. An edit to the page reloads it; an edit to native code rebuilds the app and opens it again. The page's console shows in the terminal. |
crossbind app build | Writes the app and what installs it: dist/<name>.app and its .dmg on macOS; a folder, its .tar.gz and its .deb on Linux. |
crossbind app build -p linux | The Linux app for x64 and arm64, from a Mac as well. |
crossbind app build -p windows | The Windows app for x64 and arm64, each with its .zip and -setup.exe, from a Mac or a Linux machine as well. |
crossbind app dev -p ios | Opens the app in the iOS Simulator on the dev server. |
crossbind app dev -p ios --device | Opens the app on the iPhone or iPad connected, signed by Xcode for the app's team, a free Personal Team among them. The phone reaches the dev server through its cable. |
crossbind app build -p ios | Writes the app's Xcode project, dist/<name>-ios/. |
crossbind app dev -p android | Installs the app on the attached Android device or emulator and opens it on the dev server. |
crossbind app build -p android | Writes the app's Gradle project and its release .apk, and an .aab with an upload key. |
The template runs each as an npm script: npm run dev, npm run build:windows, npm run dev:android and so on. macOS apps build with Xcode's command line tools, iOS apps with Xcode. Linux, Windows and Android apps build in crossbind's Docker images on this machine, with the default runner or RUNNER=DOCKER_EXEC; a remote or local runner stops them.
What the app does for the page
The page imports the app's own functions from crossbind/app, and the app's C++ reaches most of them through <crossbind/app.h>:
- Files: open and save dialogs on the desktop, message dialogs everywhere, and the app's own data, cache and log folders.
- The shell: open a link in the default browser, open a file in its default app where
app.openPathallows it, show a file in its folder, move one to the trash. - Menus, a tray icon and notifications on the desktop. Their clicks reach the page as events, and so do the events the app's C++ emits.
- Links and one instance:
app.urlSchemesopens the app from its own links, andapp.singleInstancehands a second launch to the app that runs. - Devices: the camera, the microphone and the location reach the page through the web's own APIs, once
app.permissionsgives the reason for each.
The reference lists which platform has which.
Configuration
The app key of crossbind.config.js describes the app. Every key is optional:
| Key | What it does |
|---|---|
name | the name the app shows: its window's title, its menus, the label under its icon; general.name without it |
id | the bundle id on Apple platforms, the application id on Android; dev.crossbind.<name> without it |
icon | a square PNG, at best 1024 × 1024, made into each platform's icon |
window | the desktop window's size and limits, resizable, fullscreen and backgroundColor |
category, copyright | the category macOS and Linux menus list the app under, and the line its About panel shows |
urlSchemes | the schemes whose links open the app |
singleInstance | hands a second launch to the app that runs |
permissions | the reason the app gives for the camera, the microphone and the location |
openPath | where the page's shell.openPath may open files: data, cache and logs, the app's folders, and picked, what a dialog picked; nowhere without it |
updater | where a desktop app finds its updates, and the public key that checks them |
team | the Apple team that signs an iOS app |
Installers, signing and updates
crossbind app build writes what installs a desktop app beside it: a disk image on macOS, a Debian package on Linux, and on Windows a setup program that installs the app for its user, with no administrator's approval.
Signing keys come from the environment alone. A macOS app is signed ad hoc, which opens it on the Mac that built it alone, unless CROSSBIND_APPLE_SIGNING_IDENTITY names a Developer ID; with an App Store Connect API key beside it, the build has Apple notarize the app as well. A Windows app and its setup program are signed with a key file, such as PKCS#12, or a cloud key service, such as Azure Trusted Signing; a hardware token is out of the build's reach. The reference names the variables for macOS and Windows.
A desktop app updates itself; a Linux app installed from its Debian package updates with the package manager instead. crossbind app updater-key prints a key pair: the public key goes in app.updater.publicKey, the private one in CROSSBIND_UPDATER_PRIVATE_KEY where the app is built, and the build signs each update with it. The page decides when to install:
iOS and Android apps update through their stores.
Size
No browser engine ships inside. The sample app is 6.7 MB on an arm64 Mac, 1.8 MB zipped, 6 MB of it Hermes, the JavaScript engine the bindings run in, and it shows its first native result 0.34 s after launch on an M-series Mac. Its Windows executable is 4.6 MB on x64, its iOS app 4.7 MB, and its Android release APK 14.8 MB with both ABIs, of which Google Play delivers one.
Limits
- One window on the desktop, and Vite for the page.
- macOS 11, iOS 15.1 and Android 13 or later: iOS on arm64 alone, Android on arm64-v8a and x86_64 with Android System WebView 116 or later.
- Linux needs a glibc system with WebKitGTK 4.1, release 2.40 or later. Windows needs the WebView2 Runtime, which Windows 11 includes.
- Not everything is measured everywhere yet. Signing with a real Developer ID and notarizing, Windows signing with a cloud key service, building on a Windows machine and several desktop functions on Linux and Windows have not been run; the reference lists what has been measured on each platform.
examples/desktop-app is the template: a page, C++ and a prebuilt library, with a script for every platform. app.md is the reference behind this page.