Guides
Distribution
Get a build onto testers' devices with a link they can tap — and register the release and upload its symbols in the same step, so crashes from that build are readable from the moment it's installed.
Over-the-air install links
When you upload an .ipa, Pharen returns an install link — an itms-services URL that installs the app over the air. Open it in Safari on the iPhone and the app installs directly, no App Store, no cable:
itms-services://?action=download-manifest&url=https://install.pharen.ai/install/<opaque>/manifest.plistInstall links live at an unguessable path — they're shareable and bookmarkable, but not enumerable, so one tenant's builds can't be discovered from another's. The link is what you send a tester; installing needs no login.
The build itself is never parked at a public address. When a tester opens the link, Pharen mints a short-lived signed URL for that one download and renders the manifest around it on the spot — so an install link that leaks doesn't hand anyone a permanent copy of your unreleased binary.
The whole release in one command
The canonical release lane is a single shell script. From your app directory:
PHAREN_AUTH_TOKEN=… bash release/release-lane.shIt runs the entire chain and prints the install link at the end:
- archive the app and export an IPA;
symbols upload— upload every dSYM the archive produced, so the release's crashes symbolicate. This runs first, so no later failure can skip it;releases create --commit— register the release with the commit it was built from;builds upload— upload the IPA and mint the OTA install link.
A build is one commit, so the lane refuses a working tree with uncommitted or untracked changes (ignored files don't count): such a file can reach the archive, and then no commit is the build's source. It checks again after generating the project and after the archive, and stops before registering or distributing if the tree changed while it ran. If your CI writes files it doesn't ignore, set PHAREN_ALLOW_DIRTY=1: the lane builds and distributes as usual but registers no commit. Outside a git checkout (with PHAREN_BUILD_NUMBER set) there is no commit to record, and the lane says so.
Nothing app-specific is baked into the script: version, build number, and bundle id are read from the archived Info.plist (so uploaded metadata can never drift from what was built), and your org/app come from a committed .pharen.yml. The one secret is PHAREN_AUTH_TOKEN, supplied in the environment — never written to disk.
Getting the lane into your repo
pharen init ios writes the lane (and a .pharen.yml) into your project — no network calls, no prompts:
pharen init ios --org your-org --app your-app-idIt writes .pharen.yml at the repo root and copies release/release-lane.sh plus release/exportOptions.plist into your app, filling in your Apple team id when it can find one. The release lane and init use the pharen CLI, provided with your credentials when your application is approved. See the CLI reference.
TestFlight, the App Store, and environments
The environment is derived on the server from the ingest key baked into the build — a build's ring is decided when it's built and can't be spoofed at runtime. Debug builds carry a test key, Release builds (TestFlight and the App Store alike) carry the live one, and an ad-hoc install link carries staging. The full mapping — every channel, what it means for your metrics, and the guard that catches a wrong key in a store build — has its own page: Environments & build channels.