Build the iOS app yourself with Xcode
The iOS app is the same Tauri 2 project as the desktop launcher, built for iPhone and iPad. This page is for contributors and for players who want to build the IPA themselves instead of taking ours. If you only want to play, install the official app – see iPhone/iPad: install with AltStore/SideStore.
- You need a Mac with Xcode. The Xcode project can only be generated on macOS, so it is not in the repository – a script creates it.
- Playing Minecraft needs the game engine and JIT, exactly like with the official app. The engine is added to the finished app in a separate step (see Build the IPA). An app you start directly from Xcode has no engine: everything else works, but games don't start.
- Apps signed with a free Apple ID stop opening after 7 days and must be re-signed (refreshed). A free Apple ID can have only 3 sideloaded apps at the same time.
- Only real devices (arm64) are built – there is no build for the iOS Simulator.
The commands on this page are the ones the CI runs (.github/workflows/ci.yml job launcher-ios,
release.yml jobs iOS and iOS engine, .github/workflows/ios-engine.yml). The CI never signs the app – it
builds an unsigned IPA, and AltStore/SideStore sign it with the user's Apple ID when installing.
What is where
| Path | What it is |
|---|---|
scripts/ios-project.sh | Creates the Xcode project in src-tauri/gen/apple (tauri ios init) and adds icons and Info.plist keys |
scripts/ios-unsigned-ipa.sh | Builds the Rust library, then an Xcode archive without code signing, zipped as IPA |
scripts/ios/build-engine.sh | Builds the game engine (Amethyst-iOS at a pinned commit, CMake, MobileGlues, Java part) |
scripts/ios/package-ipa.sh | Puts the engine into the app and signs it with ldid and the entitlements |
src-tauri/tauri.ios.conf.json | iOS overrides of the Tauri config (iOS 15, no desktop updater) |
src-tauri/Info.ios.plist | Camera text (QR code of the PC remote) and background fetch for notifications |
src-tauri/plugins/tauri-plugin-trs-game/ios/ | Swift part, engine sources, trs-game.entitlements |
Requirements
| Tool | Version / note |
|---|---|
| macOS with Xcode | with the iPhoneOS SDK. The repository doesn't pin an Xcode version; the CI uses the default Xcode of GitHub's macos-latest runner (app) and macos-15 (engine) |
| Homebrew | for xcodegen (the script installs it if missing), ldid and cmake |
| Node.js and pnpm | Node 22, pnpm as pinned in package.json (corepack enable) |
| Rust | stable via rustup, target aarch64-apple-ios |
| JDK 8 | only for the engine (CI: Zulu 8). It must be a JDK 8 – build-engine.sh checks that |
git, python3, zip | used by the scripts |
The app needs iOS 15 (minimumSystemVersion in tauri.ios.conf.json). The CI sets
IPHONEOS_DEPLOYMENT_TARGET=15.0 for the app, because the Swift packages of the plugins use APIs from iOS 14 on; the
engine itself is built for 14.0.
Build the IPA
Get the code and the tools
git clone https://github.com/theredstonee/TRS-Launcher.git
cd TRS-Launcher
pnpm install
rustup target add aarch64-apple-ios
brew install ldid cmake
Build the frontend
pnpm generate
Create the Xcode project
bash scripts/ios-project.sh
It runs pnpm tauri ios init --ci if src-tauri/gen/apple doesn't exist yet, copies the camera text and the
background task from src-tauri/Info.ios.plist into the app's Info.plist and puts the app icons (plus the event icons
as alternative icons) into the asset catalog.
Build the app without signing
export IPHONEOS_DEPLOYMENT_TARGET=15.0
bash scripts/ios-unsigned-ipa.sh release build/TRS-Launcher-app.ipa
What happens inside:
cargo build --lib --target aarch64-apple-ios --release --features tauri/custom-protocolwithTAURI_CONFIGset to the content oftauri.ios.conf.json. Thecustom-protocolfeature embeds the interface – without it the app looks for a dev server onlocalhost:3000and closes again right away.- The library
libtrs_launcher_lib.ais copied tosrc-tauri/gen/apple/Externals/arm64/release/libapp.a. scripts/ios/disable-rust-phase.pyswitches off the Xcode build phase "Build Rust Code" (tauri ios xcode-script) – it only works inside a runningtauri ios build, and the library is already there.xcodebuild … archivewithCODE_SIGNING_ALLOWED=NO, then the.appis zipped asPayload/into the IPA.
Use debug instead of release for a debug build (the library then goes to Externals/arm64/debug/). For CurseForge,
set CURSEFORGE_API_KEY or put the key into ~/.tauri/curseforge-api-key – it's optional, without it CurseForge is
hidden.
Build the game engine
JAVA8_HOME=$(/usr/libexec/java_home -v 1.8) bash scripts/ios/build-engine.sh build/engine-ios
The script fetches Amethyst-iOS at the pinned commit
9212a1894865e7ac0466029e25ddb0d895544c76, checks the vendored files against it, builds the native engine and
MobileGlues with CMake and the Java part with the JDK 8. The result is a folder with Frameworks/, libs/,
resources/, LICENSES/ and engine.json. The Java runtimes are not part of it – the app downloads them on the
first game start.
Put the engine into the app
bash scripts/ios/package-ipa.sh build/TRS-Launcher-app.ipa build/engine-ios build/TRS-Launcher.ipa
This copies the engine into the app, adds the Info.plist keys for the Files app, landscape mode, mouse and game
controllers, and signs everything with ldid – the app with the entitlements from
src-tauri/plugins/tauri-plugin-trs-game/ios/trs-game.entitlements (get-task-allow for JIT, the increased memory
limit and extended virtual addressing). Another file can be passed with TRS_IOS_ENTITLEMENTS.
Install it
Copy build/TRS-Launcher.ipa to your iPhone or iPad and install it in AltStore or SideStore with My Apps → +. They
sign it with your Apple ID, like the official app. Other tools that sign an IPA with your Apple ID should work too, but
we haven't tested them. Then enable JIT to play.
Run it from Xcode with your own Apple ID
You can also start the app straight from Xcode on a connected iPhone and sign it with your own team (a free Apple ID works as "Personal Team"). This is handy for working on the interface. Two things to know:
- The app has no game engine this way – starting an instance reports that the engine is missing. Sign-in, social, wardrobe, modpacks and everything else work.
- The CI never signs with a team, so we haven't tested this path.
Build the Rust library for Debug
Do the steps up to Create the Xcode project, then:
export IPHONEOS_DEPLOYMENT_TARGET=15.0
bash scripts/ios-unsigned-ipa.sh debug build/TRS-Launcher-debug.ipa
This leaves the library in src-tauri/gen/apple/Externals/arm64/debug/libapp.a and switches off the Rust build phase in
the project, so Xcode can build the app on its own.
Open the project
open src-tauri/gen/apple/*.xcodeproj
Choose the scheme that ends in _iOS and your iPhone as the destination.
Set your team and bundle ID
In the app target under Signing & Capabilities, pick your Team and change the Bundle Identifier to one of
your own (for example io.github.yourname.trslauncher) – Apple only lets one team use a bundle ID.
Run
Press Run. On iOS 16 and newer, the iPhone asks for Developer Mode first (Settings → Privacy & Security → Developer Mode). With a free Apple ID you may also have to trust your developer profile under Settings → General → VPN & Device Management.
src-tauri/gen/apple and create it
again.Make it your own app
- Bundle ID: AltStore/SideStore sign the IPA with your Apple ID, so you don't have to change anything for that. For Xcode, change the bundle ID there (see above).
- Don't change
identifierinsrc-tauri/tauri.conf.json. It is shared with Android, where the Kotlin package and the Rust code depend on it – the Android build then stops (see Build the Android app yourself). An iOS-onlyidentifierintauri.ios.conf.jsonmight work, but we haven't tested it. - Keep the background task ID
dev.theredstonee.trslauncher.push-pollas it is: it appears both insrc-tauri/Info.ios.plistand in the push plugin's Swift code, and iOS only runs tasks listed in the Info.plist.
What still works in your own build, according to the code:
- Microsoft sign-in uses the device-code sign-in (you type a code on Microsoft's page) – it doesn't depend on the bundle ID.
- TRS services (friends, chat, capes, TRS API) talk to the same API; there is no check of the app or its signature.
- Links like
trs-launcher://pack/<code>use the same scheme in every build. - Updates: your build isn't connected to our AltStore/SideStore source. Update it by building and installing again.
If something breaks in your own build, please report it.
Run the checks
The same checks as the CI:
pnpm generate
cd src-tauri
IPHONEOS_DEPLOYMENT_TARGET=15.0 cargo clippy --workspace --target aarch64-apple-ios -- -D warnings
# game plugin for iOS, Rust and its Swift package (job "iOS engine"):
IPHONEOS_DEPLOYMENT_TARGET=14.0 cargo build -p tauri-plugin-trs-game --target aarch64-apple-ios
Troubleshooting
"Build-Phase tauri ios xcode-script nicht gefunden"
scripts/ios-unsigned-ipa.sh switches off that build phase the first time it runs – a second run doesn't find it any
more and stops with this message. The CI always starts with a fresh project. Locally, delete the generated project and
create it again:
rm -rf src-tauri/gen/apple
bash scripts/ios-project.sh
Errors about the deployment target or iOS 14 APIs
Set IPHONEOS_DEPLOYMENT_TARGET=15.0 before building the app (14.0 for the engine plugin check) – the Swift packages
need at least iOS 14.
The app closes right after opening
If you built the Rust library by hand, you probably left out --features tauri/custom-protocol – then the app waits
for a dev server on localhost:3000. Use scripts/ios-unsigned-ipa.sh, which always sets it.
"JDK 8 fehlt (JAVA8_HOME setzen)" or "JAVA8_HOME ist kein JDK 8"
The engine's Java part needs exactly a JDK 8. Install one and point JAVA8_HOME to it.
"ldid fehlt (brew install ldid)"
package-ipa.sh signs with ldid: brew install ldid.
"vendored Datei weicht von Upstream ab"
A file under ios/Engine/vendor/amethyst-ios differs from the pinned Amethyst-iOS commit. Only the patched files
listed in that folder's UPSTREAM.md may differ – undo your change or update the list.
The game closes right after starting
Almost always JIT is not on. See Enable JIT. The engine log is in
the Files app under On My iPhone → TRS Launcher (trs-engine.log).
Minecraft 26.3 doesn't start
26.3 is not supported on iOS yet (the engine has no SDL3 support there). Use 26.2 or older.
"Unable to verify app" after a week
The 7 days of the free Apple ID are over. Refresh the app in AltStore/SideStore, or run it from Xcode again.
License and name
TRS Launcher is free software under the GNU General Public License v3.0 (LICENSE, copyright notices in NOTICE).
You may build, change and share the app. If you share an IPA, the GPL requires that you share it under the same license
and make the complete source code of exactly that build available, including your changes. The iOS engine is based
on Amethyst-iOS (GPL-3.0) and ships more third-party parts; their license texts are copied into the app
(licenses/engine) and listed in NOTICE – keep them.
The repository has no separate trademark rules. Still: if you hand out your own build, give it its own name and bundle ID so nobody mistakes it for the official TRS Launcher, and point people to your source code – not to our support.
Next steps
Build the Android app yourself
Build the TRS Launcher APK from source: Android SDK and NDK, Rust targets, debug and release builds, your own signing key and your own app ID.
TRS Server Rules
Plugin and server mod that locks, forces or limits TRS Client features on your server: platforms, config reference, protocol and all module IDs.