Build for Apple platforms
Checked against 0015716 on 2026-11-10. The files it covers are unchanged since.
One SwiftUI host in hosts/apple runs a niso page on every Apple platform:
iOS and iPadOS, macOS, tvOS, visionOS and watchOS, with CarPlay inside the iOS
app. One script, hosts/apple/build.sh,
builds it for any of them: it compiles niso for the platform’s Rust target,
builds the example pages, compiles the Swift host against the platform’s SDK,
and leaves an ad-hoc signed Niso.app.
What you need
Section titled “What you need”- macOS with Xcode, and the simulator runtime for each platform you want to run on.
- Rust from rustup. The script adds the
aarch64-apple-*target it needs when it’s missing, so there’s no target to install by hand. - Node and pnpm, which build the example pages (
examples/build.mjs). - The QuickJS-ng submodule:
git submodule update --init.
--platform picks the platform; without it the script builds for the iOS
Simulator. The page is an example name from examples/ (default counter).
--no-launch only builds; the script promises it “touches no simulator”.
hosts/apple/build.sh --platform ios-sim --no-launch counterThe script prints the app’s path last: target/ios/Niso.app, with its widget
extension (home screen widgets and the Live Activity) in
PlugIns/NisoWidgets.appex.
iPadOS runs the iOS app; there’s no separate build. Build for ios-sim as on
the iOS tab and launch it on an iPad simulator by naming one in
NISO_SIMULATOR (below). The app opens in a resizable window, and only one:
UIApplicationSupportsMultipleScenes is false, so a second window can’t
fight the first over the page.
hosts/apple/build.sh --platform macos --no-launch counterThe app is target/apple/macos/Niso.app. It’s SwiftUI on AppKit, not Mac
Catalyst, so its controls are Mac controls. --icon PNG gives a Mac app its
icon.
hosts/apple/build.sh --platform tvos-sim --no-launch counterThe app is target/apple/tvos-sim/Niso.app. The Siri Remote reaches the
page as keys: arrows, Enter, Escape and MediaPlayPause.
hosts/apple/build.sh --platform visionos-sim --no-launch counterThe app is target/apple/visionos-sim/Niso.app. Looking at a point and
pinching is a pointer down and up there.
hosts/apple/build.sh --platform watchos-sim --no-launch counterThe app is target/apple/watchos-sim/Niso.app. Taps reach the page, and
the Digital Crown scrolls it.
The first build for a platform compiles niso for that platform’s Rust target
into a build directory of its own under target/, so each platform costs a
full release build of niso in time and disk. NISO_LIBDIR points the script
at a prebuilt libniso_app.a and an include/ of its headers instead of
running cargo.
Without --no-launch, the script also installs and launches the app:
- Simulators (
ios-sim,tvos-sim,visionos-sim,watchos-sim): on the simulatorNISO_SIMULATORnames, by device name or UDID, booting it if needed. A name resolves on the newest runtime that has it. iOS defaults to the iPhone 17; the other platforms have no default, so setNISO_SIMULATORfor them (simulator.sh).xcrun simctl list devices availablelists the names your Xcode has. - macOS: it opens the app.
- Devices (
ios,tvos,visionos,watchos): it only builds. Installing on a device needs provisioning, which the script doesn’t do.
hosts/apple/build.sh counter # the iOS Simulator's iPhone 17NISO_SIMULATOR="iPad Air 13-inch (M4)" hosts/apple/build.sh counterNISO_SIMULATOR="Apple TV 4K (4th generation)" hosts/apple/build.sh --platform tvos-sim counterhosts/apple/build.sh --platform macos counterArguments the script doesn’t take, or everything after --, go to the app:
-niso-tap X,Y taps at a point (in CSS pixels) after launch. A
simulator app’s output goes to stdout.txt and stderr.txt beside the app.
Your own page
Section titled “Your own page”Instead of an example, the app can carry an HTML page or an app library:
| Option | What the app runs |
|---|---|
EXAMPLE |
examples/dist/EXAMPLE.js, built from examples/EXAMPLE/ |
--page DIR |
DIR/index.html; DIR is copied into the app and served at the app’s origin, https://<bundle id>.app.niso/ |
--page FILE |
that one HTML file, copied alone |
--page FILE --root DIR |
FILE, with DIR as the root its scripts, stylesheets and modules load from |
--app LIB |
a static library for the platform that exports niso_app_main (Native apps) |
--name and --bundle-id set the app’s name and identifier (default Niso
and dev.niso.host), and --out DIR where it goes. --debug builds a host that
takes -niso-page FILE -niso-root DIR at launch, to run a page from anywhere on
disk. NISO_ENGINE=porffor compiles the example’s script into the app ahead
of time with Porffor instead of running it on QuickJS (see
JavaScript).
CarPlay
Section titled “CarPlay”CarPlay is part of the iOS app, as an audio app. It shows a list template
built from the page’s carplay.list surface, and the system’s Now Playing
screen for the page’s media session; examples/radio declares its stations
this way. It has been verified in the app only, by
tests/carplay/check.sh:
with Xcode 27.2 the simulator’s CarPlay window was unavailable, so no CarPlay
screen has shown these templates yet. See Surfaces and
the Apple host notes.
What differs per platform
Section titled “What differs per platform”Every platform draws buttons, switches, pickers and text fields with its own controls. tvOS has no spatial navigation or focus ring yet, watchOS has fixed colors on black and one text size, and visionOS has no ornaments. The Apple host notes have the full table of input, controls and limits per platform, and Apple platforms covers what only Apple’s platforms have.