Skip to content

Wireless deploy to iPhone

This app uses a custom dev client (native modules: audio, video, reanimated), so it does not run in Expo Go. You install the dev client on the phone once, then iterate over Wi-Fi with no rebuilds for JavaScript changes.

The short version is pnpm launch wifi. It runs the preflight checks and starts both servers. This page is the detail behind it: signing, iPad, and TestFlight account problems. For the other launch modes (simulator, Accessibility Inspector, Android, TestFlight) and the full Wi-Fi troubleshooting table, see Launching the app.

Run these from the repo root. deploy:iphone, ios:device, and dev:backend:lan are root scripts, because they span the backend and the app. Running one from apps/mobile/ fails with ERR_PNPM_RECURSIVE_EXEC_FIRST_FAIL: Command "deploy:iphone" not found. From a subdirectory, use pnpm -w <script> instead.

Prerequisites (once)

pnpm install   # installs concurrently, used by the deploy script

Building to a physical device also needs an Apple Team set for signing. If the first build prompts for it, open apps/mobile/ios/SeniorHealthApp.xcworkspace in Xcode, select the SeniorHealthApp target, and set your Team under Signing & Capabilities.

One-time: install the dev client on the iPhone

  1. Connect the iPhone by USB, unlock it, and tap Trust if prompted.
  2. Build and install the native dev client:
pnpm ios:device

Select your iPhone when prompted. The first build takes several minutes (ios/ and Pods/ are already generated, so it is a warm build).

  1. Optional, recommended: enable wireless installs for the future. In Xcode open Window → Devices and Simulators, select your iPhone, and check Connect via network. After this you can rebuild without the cable.

Everyday wireless flow

  1. Put the Mac and iPhone on the same Wi-Fi network.
  2. Start everything with one command:
pnpm deploy:iphone

This prints your Mac's LAN IP, then starts the backend on 0.0.0.0:8000 (reachable by the phone) and the Expo dev-client Metro server bound to the LAN, with a QR code.

  1. Open the installed Senior Health App dev client on the phone. It connects to Metro automatically; scan the QR if it does not. The app derives the backend address from the Metro URL, so no manual configuration is needed.
  2. Edit and save a file. The change hot reloads over Wi-Fi. No rebuild.

Stop the servers with Ctrl+C.

When to rebuild natively

Run pnpm ios:device again only when the native layer changes: adding or updating a native module, changing app.config.ts plugins or permissions, or updating app icons and splash. Pure JavaScript, TypeScript, and asset changes never need a rebuild; they hot reload.

All of these live in the root package.json, so run them from the repo root (or prefix with pnpm -w from anywhere).

Command What it does
pnpm launch wifi deploy:iphone with the preflight checks in front of it
pnpm deploy:iphone Backend (0.0.0.0) + LAN dev-client Metro, prints IP
pnpm ios:device One-time native build and install to a connected iPhone
pnpm dev:backend:lan Backend only, bound to 0.0.0.0 so the phone can reach it

If the phone will not connect, work through the troubleshooting table in Launching the app. The usual causes are the macOS firewall, a VPN on the Mac, or a guest Wi-Fi network that isolates clients from each other.

TestFlight, including iPad

Ship a build to TestFlight from apps/mobile/ (running EAS from the repo root fails during the Bundle JavaScript phase):

cd apps/mobile
eas build --profile production --platform ios   # auto-submits are off; then:
eas submit --platform ios --latest              # assigns the "Tester" group

Every build is universal. app.config.ts sets supportsTablet: true (with requireFullScreen: true, so the iPad shows the phone layout full screen), and the generated project carries TARGETED_DEVICE_FAMILY = "1,2". There is no iPhone-only build to fix; an iPad on iPadOS 16.4 or later can always install the current build.

"This app isn't available for your Apple Account" on iPad

That message is about the account, not the device. A TestFlight invite binds to the Apple Account that redeems it, not to the email address it was sent to, so a build that installs fine on the iPhone can still be "not available" on an iPad signed into a different account. In order:

  1. On the iPad, open TestFlight and tap the account avatar. It must show the same Apple Account that accepted the tester invite. If it does not, either sign that account in, or add the iPad's account as a tester in App Store Connect (group "Tester") and open the new invite on the iPad.
  2. Accept the invite on the iPad itself: open the invite email's View in TestFlight link there, or enter the redeem code in the TestFlight app.
  3. Builds expire after 90 days. If the newest build has expired, push a fresh one with the two commands above; eas.json assigns the "Tester" group on submit, so testers see it without any App Store Connect clicking.
  4. Check the iPad runs iPadOS 16.4 or later, the minimum for this app. Older iPads cannot install it and nothing in the project can lower that floor.