chore(mobile): upgrade to Expo SDK 56

Bump expo, react, react-native, and all expo-* / react-native-* peers to
the SDK 56 line via expo install --fix, adding expo-splash-screen and
expo-system-ui for config plugins the SDK split out of core. Bump
@bacons/apple-targets, react-native-view-shot, and other native modules
to versions compatible with React Native 0.85 and the new architecture.

Remove @react-navigation/* direct dependencies and route their hooks
through expo-router, which is no longer compatible with react-navigation
as of SDK 56. Fix RN 0.85's removed StyleSheet.absoluteFillObject (use
absoluteFill) and react-native-view-shot 5.x's ViewShotRef type across
call sites. Downgrade eslint-plugin-react-hooks v7's new React Compiler
era rules to warnings pending a dedicated refactor, and repair Jest
fallout from the jest-expo/reanimated/worklets/expo-media-library bumps.

Regenerate the committed ios/ and android/ native projects with
`expo prebuild --clean` (required for @bacons/apple-targets 5.x) against
the production release channel, and document that requirement.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jjbruntonandClaude Fable 5 committed 2026-08-31 11:11:37 +01:00
1 parent 8bf93f372b
commit 6bc4e31719
92 files changed
+29132 -35557

No files matched your search

+255 -252
View File
@@ -1,28 +1,28 @@
# Releasing Sauci Mobile App
This guide covers local release builds for Android and iOS.
JavaScript-only changes can also ship over the air between store releases. See
[Mobile over-the-air updates](mobile-ota.md). Anything that changes native code
still requires a store build with a bumped `expo.version`, because the OTA
# Releasing Sauci Mobile App
This guide covers local release builds for Android and iOS.
JavaScript-only changes can also ship over the air between store releases. See
[Mobile over-the-air updates](mobile-ota.md). Anything that changes native code
still requires a store build with a bumped `expo.version`, because the OTA
explicit runtime version is synchronized with the app version.
## Prerequisites
- **Java JDK 17** - Required for Android Gradle builds
- **Android Studio** - For SDK and build tools (including Android SDK/NDK)
- **Xcode** - For iOS builds (macOS only)
- **EAS CLI** - `npm install -g eas-cli`
- **Expo account** - Run `eas login` to authenticate
---
## EAS Build Local (Recommended)
The `--local` flag runs the EAS build process on your machine instead of Expo's cloud servers. This automatically handles signing credentials and produces the same output as cloud builds.
### Quick Start
## Prerequisites
- **Java JDK 17** - Required for Android Gradle builds
- **Android Studio** - For SDK and build tools (including Android SDK/NDK)
- **Xcode** - For iOS builds (macOS only)
- **EAS CLI** - `npm install -g eas-cli`
- **Expo account** - Run `eas login` to authenticate
---
## EAS Build Local (Recommended)
The `--local` flag runs the EAS build process on your machine instead of Expo's cloud servers. This automatically handles signing credentials and produces the same output as cloud builds.
### Quick Start
```bash
cd apps/mobile
@@ -100,155 +100,158 @@ Android release manifests must not contain `READ_MEDIA_IMAGES` or
broad read access. After any Expo, media-library, image-picker, or native Android
change, run `:app:processReleaseMainManifest` and inspect the merged release
manifest before building an artifact for Google Play.
### Building an APK (for Testing)
The production profile creates an AAB (Android App Bundle), which can't be directly installed on devices. To build an APK for testing:
```bash
# Use the preview profile (configured for APK output)
eas build --platform android --profile preview --local
```
Or add a custom profile to `eas.json`:
```json
{
"build": {
"local-apk": {
"android": {
"buildType": "apk"
}
}
}
}
```
Then run:
```bash
eas build --platform android --profile local-apk --local
```
### Installing the APK
```bash
# Via ADB (device connected via USB)
adb install ./build-*.apk
# Or drag-and-drop onto Android Emulator
```
### Build Profiles
| Profile | Output | Use Case |
|---------|--------|----------|
| `production` | .aab | Play Store / App Store submission |
| `preview` | .apk | Internal testing, device installation |
| `development` | .apk | Dev client with hot reload |
### Environment Variables
Useful for debugging build issues:
| Variable | Purpose |
|----------|---------|
| `EAS_LOCAL_BUILD_SKIP_CLEANUP=1` | Keep build directory after completion |
| `EAS_LOCAL_BUILD_WORKINGDIR=/path` | Custom build directory (default: /tmp) |
| `EAS_LOCAL_BUILD_ARTIFACTS_DIR=/path` | Output directory for build artifacts |
Example with debugging enabled:
```bash
EAS_LOCAL_BUILD_SKIP_CLEANUP=1 \
EAS_LOCAL_BUILD_WORKINGDIR=~/eas-builds \
eas build --platform android --profile production --local
```
### Limitations of Local Builds
- **Single platform only** - Can't use `--platform all`
- **Software versions ignored** - `node`, `yarn`, `ndk`, `image` fields in eas.json are ignored
- **No caching** - Each build starts fresh
- **Secret env vars not available** - Set them in your local environment instead
- **macOS/Linux only** - Windows requires WSL (unsupported)
### Troubleshooting Local Builds
**Java version mismatch:**
```bash
# Check Java version (should be 17)
java -version
# On macOS, switch Java version
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
```
**Gradle daemon issues:**
```bash
cd android && ./gradlew --stop && cd ..
```
### Building an APK (for Testing)
The production profile creates an AAB (Android App Bundle), which can't be directly installed on devices. To build an APK for testing:
```bash
# Use the preview profile (configured for APK output)
eas build --platform android --profile preview --local
```
Or add a custom profile to `eas.json`:
```json
{
"build": {
"local-apk": {
"android": {
"buildType": "apk"
}
}
}
}
```
Then run:
```bash
eas build --platform android --profile local-apk --local
```
### Installing the APK
```bash
# Via ADB (device connected via USB)
adb install ./build-*.apk
# Or drag-and-drop onto Android Emulator
```
### Build Profiles
| Profile | Output | Use Case |
|---------|--------|----------|
| `production` | .aab | Play Store / App Store submission |
| `preview` | .apk | Internal testing, device installation |
| `development` | .apk | Dev client with hot reload |
### Environment Variables
Useful for debugging build issues:
| Variable | Purpose |
|----------|---------|
| `EAS_LOCAL_BUILD_SKIP_CLEANUP=1` | Keep build directory after completion |
| `EAS_LOCAL_BUILD_WORKINGDIR=/path` | Custom build directory (default: /tmp) |
| `EAS_LOCAL_BUILD_ARTIFACTS_DIR=/path` | Output directory for build artifacts |
Example with debugging enabled:
```bash
EAS_LOCAL_BUILD_SKIP_CLEANUP=1 \
EAS_LOCAL_BUILD_WORKINGDIR=~/eas-builds \
eas build --platform android --profile production --local
```
### Limitations of Local Builds
- **Single platform only** - Can't use `--platform all`
- **Software versions ignored** - `node`, `yarn`, `ndk`, `image` fields in eas.json are ignored
- **No caching** - Each build starts fresh
- **Secret env vars not available** - Set them in your local environment instead
- **macOS/Linux only** - Windows requires WSL (unsupported)
### Troubleshooting Local Builds
**Java version mismatch:**
```bash
# Check Java version (should be 17)
java -version
# On macOS, switch Java version
export JAVA_HOME=$(/usr/libexec/java_home -v 17)
```
**Gradle daemon issues:**
```bash
cd android && ./gradlew --stop && cd ..
```
**Native regeneration after dependency changes:**
Treat `expo prebuild` as a source change, not a release step. Run it separately
only when native dependencies intentionally changed, review the full native diff,
verify it, and commit it before starting the release from a clean worktree.
**Out of memory:**
```bash
# Increase Gradle memory
echo "org.gradle.jvmargs=-Xmx4g" >> android/gradle.properties
```
---
## Manual Android Release Build
### Step 1: Get the Production Keystore
The production keystore is stored in EAS. Download it:
```bash
cd apps/mobile
eas credentials --platform android
```
Select:
1. `production`
2. `Keystore`
3. `Download Keystore`
Save the keystore file and note the **password** and **alias** shown.
### Step 2: Configure Signing
Ensure `android/gradle.properties` has the keystore configuration:
```properties
MYAPP_UPLOAD_STORE_FILE=sauci-release.keystore
MYAPP_UPLOAD_KEY_ALIAS=<alias from EAS>
MYAPP_UPLOAD_STORE_PASSWORD=<password from EAS>
MYAPP_UPLOAD_KEY_PASSWORD=<password from EAS>
```
**Important:** Never commit these credentials to git.
verify it, and commit it before starting the release from a clean worktree. Use
`expo prebuild --clean` (see `docs/mobile-ota.md`); as of `@bacons/apple-targets`
5.x, a non-clean prebuild against an already-generated iOS project fails while
updating the widget's Xcode target.
**Out of memory:**
```bash
# Increase Gradle memory
echo "org.gradle.jvmargs=-Xmx4g" >> android/gradle.properties
```
---
## Manual Android Release Build
### Step 1: Get the Production Keystore
The production keystore is stored in EAS. Download it:
```bash
cd apps/mobile
eas credentials --platform android
```
Select:
1. `production`
2. `Keystore`
3. `Download Keystore`
Save the keystore file and note the **password** and **alias** shown.
### Step 2: Configure Signing
Ensure `android/gradle.properties` has the keystore configuration:
```properties
MYAPP_UPLOAD_STORE_FILE=sauci-release.keystore
MYAPP_UPLOAD_KEY_ALIAS=<alias from EAS>
MYAPP_UPLOAD_STORE_PASSWORD=<password from EAS>
MYAPP_UPLOAD_KEY_PASSWORD=<password from EAS>
```
**Important:** Never commit these credentials to git.
### Step 3: Confirm tracked native sources
The committed `android/` project is the release source. If native dependencies
changed, regenerate and review that project as a separate change before release.
### Step 4: Build the Release Bundle
```bash
cd android
./gradlew bundleRelease
```
The AAB file will be at:
```
android/app/build/outputs/bundle/release/app-release.aab
```
### Step 4: Build the Release Bundle
```bash
cd android
./gradlew bundleRelease
```
The AAB file will be at:
```
android/app/build/outputs/bundle/release/app-release.aab
```
### Step 5: Upload to Play Store
Apply the upload execution policy above before opening or changing the release.
@@ -264,65 +267,65 @@ original request expressly includes the rollout.
Do not send the draft for review or start a rollout unless the original request
expressly includes that action.
### Verifying Keystore Fingerprint
To verify you're using the correct keystore:
```bash
keytool -list -v -keystore android/sauci-release.keystore -storepass <password>
```
### Verifying Keystore Fingerprint
To verify you're using the correct keystore:
```bash
keytool -list -v -keystore android/sauci-release.keystore -storepass <password>
```
Expected EAS production upload-key SHA1: `F0:60:26:C7:54:B0:46:F2:80:FE:AC:43:8A:69:10:BD:9A:62:B4:59`
---
## iOS Release Build
---
## iOS Release Build
### Step 1: Confirm tracked native sources
The committed `ios/` project is the release source. If native dependencies
changed, regenerate and review that project as a separate change before release.
### Step 2: Install Pods
```bash
cd ios
pod install
cd ..
```
### Step 3: Build Archive in Xcode
1. Open `ios/Sauci.xcworkspace` in Xcode
2. Select **Any iOS Device (arm64)** as the build target
3. Go to **Product** → **Archive**
4. Wait for the build to complete
### Step 2: Install Pods
```bash
cd ios
pod install
cd ..
```
### Step 3: Build Archive in Xcode
1. Open `ios/Sauci.xcworkspace` in Xcode
2. Select **Any iOS Device (arm64)** as the build target
3. Go to **Product** → **Archive**
4. Wait for the build to complete
### Step 4: Upload to App Store
Apply the upload execution policy above before using Xcode Organizer. Report any
verified automatic TestFlight distribution before uploading.
1. In Xcode Organizer (Window → Organizer), select the archive
2. Click **Distribute App**
3. Select **App Store Connect** → **Upload**
4. Follow the prompts to upload
2. Click **Distribute App**
3. Select **App Store Connect** → **Upload**
4. Follow the prompts to upload
### Step 5: Submit in App Store Connect
Submitting for App Review is not authorized by an upload request unless the
original request expressly includes App Review submission.
1. Go to [App Store Connect](https://appstoreconnect.apple.com)
2. Select **Sauci**
3. Create a new version or select the uploaded build
4. Fill in release notes and submit for review
---
## Version Management
2. Select **Sauci**
3. Create a new version or select the uploaded build
4. Fill in release notes and submit for review
---
## Version Management
Version is managed locally by EAS with `appVersionSource: "local"` in
`apps/mobile/eas.json`. Production builds auto-increment the platform build
number and synchronize the tracked native version file. For a public-version
@@ -334,48 +337,48 @@ checked-in iOS and Android public/runtime values together.
node .codex/skills/generate-release/scripts/set_version.mjs --version 1.0.7
node .codex/skills/generate-release/scripts/set_version.mjs --check
```
To inspect or deliberately set versions:
```bash
# Check current version
eas build:version:get
# Set version manually
eas build:version:set --platform android --version 1.0.1
eas build:version:set --platform ios --version 1.0.1
```
```bash
# Check current version
eas build:version:get
# Set version manually
eas build:version:set --platform android --version 1.0.1
eas build:version:set --platform ios --version 1.0.1
```
The user-facing version remains in `app.json`:
```json
{
"expo": {
"version": "1.0.1"
}
}
```
And for Android, update `android/app/build.gradle`:
```gradle
versionCode 2
versionName "1.0.1"
```
---
## Troubleshooting
### Wrong Keystore Error
If Play Store rejects with "signed with wrong key":
1. Run `eas credentials --platform android`
2. Download the correct keystore
3. Verify fingerprint matches expected SHA1
4. Replace your local keystore file
```json
{
"expo": {
"version": "1.0.1"
}
}
```
And for Android, update `android/app/build.gradle`:
```gradle
versionCode 2
versionName "1.0.1"
```
---
## Troubleshooting
### Wrong Keystore Error
If Play Store rejects with "signed with wrong key":
1. Run `eas credentials --platform android`
2. Download the correct keystore
3. Verify fingerprint matches expected SHA1
4. Replace your local keystore file
### Build Failures After Dependency Changes
```bash
@@ -386,8 +389,8 @@ cd android && ./gradlew bundleRelease
If native regeneration is genuinely required, do it as a separate reviewed and
committed source change before running the release build.
### iOS Signing Issues
Ensure your Apple Developer certificates and provisioning profiles are up to date in Xcode:
- **Xcode** → **Settings** → **Accounts** → Download Manual Profiles
### iOS Signing Issues
Ensure your Apple Developer certificates and provisioning profiles are up to date in Xcode:
- **Xcode** → **Settings** → **Accounts** → Download Manual Profiles