355b14faef
Enable App Store builds without EAS, iOS 18 App Intents plugins, and signing fixes for distribution export. Add mobile invoice PDF preview, compact line items, and more reliable shortcut deep-link handling. Co-authored-by: Cursor <cursoragent@cursor.com>
3.8 KiB
3.8 KiB
Local iOS release (no EAS)
Archive and upload beenvoice to App Store Connect using Xcode on your Mac — no Expo Application Services (EAS) subscription required.
Prerequisites
- macOS with Xcode (same major version you use for development)
- Apple Developer Program membership
- App record in App Store Connect with bundle ID
com.beenvoice.app - Distribution signing set up in Xcode (automatic signing + team is enough for most cases)
- App Store Connect API key (for upload only)
One-time setup
cd beenvoice-app
cp .ios-release.env.example .ios-release.env
Edit .ios-release.env:
| Variable | Where to find it |
|---|---|
APPLE_TEAM_ID |
developer.apple.com/account → Membership → Team ID |
APP_STORE_CONNECT_API_KEY_ID |
App Store Connect → Users and Access → Integrations → Keys |
APP_STORE_CONNECT_API_ISSUER_ID |
Same page (Issuer ID at top) |
APP_STORE_CONNECT_API_KEY_PATH |
Path to downloaded AuthKey_XXXXXX.p8 |
EXPO_PUBLIC_API_URL |
Production API URL baked into the release bundle |
Optional: store the .p8 in ~/.appstoreconnect/private_keys/ (never commit it).
Open the iOS project once in Xcode and confirm Signing & Capabilities succeeds for targets beenvoice and ExpoWidgetsTarget.
Commands
# Archive + export signed IPA to dist/ios-release/export/
bun run ios:release
# Archive + export + upload to App Store Connect (TestFlight)
bun run ios:release:upload
Flags (pass through to the script)
bash scripts/ios-release.sh --archive-only # .xcarchive only
bash scripts/ios-release.sh --export-only --upload # re-upload existing archive
bash scripts/ios-release.sh --no-prebuild # skip expo prebuild
bash scripts/ios-release.sh --no-bump # don't increment build number
With IOS_BUMP_BUILD=1 in .ios-release.env, each run bumps CFBundleVersion via agvtool (recommended for repeated TestFlight uploads).
What the script does
expo prebuild --platform ios(unless--no-prebuild)pod install- Optional build-number bump (
agvtool) xcodebuild archive(Release, generic iOS device)xcodebuild -exportArchive→ App Store IPAxcrun altool --upload-app(with--uploadonly)
Artifacts land in dist/ios-release/ (gitignored).
After upload
- App Store Connect → TestFlight — wait for “Processing” to finish
- Smoke-test on device
- Submit for App Store review when ready
See also APP_STORE_CONNECT.md for metadata, screenshots, and review notes.
Notes
- Dev client:
expo-dev-clientis in the native project today. Store builds still work, but the binary includes the dev client shell. For a slimmer production binary, remove that plugin and re-run prebuild before release (or maintain a separateapp.configvariant). - Manual upload: After
bun run ios:release, drag the IPA into Apple’s Transporter app instead of using--upload. - CI: Run the same script on a Mac runner (GitHub
macos-latest, etc.) with secrets injected as env vars instead of.ios-release.env.
Troubleshooting
| Issue | Fix |
|---|---|
| No signing certificate | Xcode → Settings → Accounts → Download Manual Profiles; or open project and enable automatic signing |
pod install fails |
cd ios && pod repo update && pod install |
| Upload auth error | Verify API key has Developer access; check Key ID, Issuer ID, and .p8 path |
| Duplicate build number | Enable IOS_BUMP_BUILD=1 or bump CURRENT_PROJECT_VERSION in Xcode |
| Widget extension signing | Both beenvoice and ExpoWidgetsTarget need the same team |