From harness-claude
Deploys React Native apps using EAS Build, EAS Submit, OTA updates, and CI/CD pipelines for App Store/Google Play submission, multi-environment management, and instant bug fixes.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Deploy React Native apps with EAS Build, EAS Submit, OTA updates, and automated CI/CD pipelines
Deploys Expo apps to iOS App Store, Android Play Store, TestFlight, and web hosting using EAS CLI. Guides builds, submissions, eas.json configs, and CI/CD workflows.
Deploys Expo apps to production via app stores (iOS App Store, Google Play) and OTA updates. Guides builds, submissions, release channels, and optimization.
Deploys iOS and Android apps to App Store and Google Play. Covers code signing, versioning, build configuration, submission process, release management, and CI/CD with GitHub Actions.
Share bugs, ideas, or general feedback.
Deploy React Native apps with EAS Build, EAS Submit, OTA updates, and automated CI/CD pipelines
// eas.json
{
"cli": { "version": ">= 8.0.0" },
"build": {
"development": {
"developmentClient": true,
"distribution": "internal",
"env": { "APP_ENV": "development" },
"ios": { "simulator": true }
},
"preview": {
"distribution": "internal",
"env": { "APP_ENV": "staging" },
"channel": "preview"
},
"production": {
"env": { "APP_ENV": "production" },
"channel": "production",
"autoIncrement": true
}
},
"submit": {
"production": {
"ios": {
"appleId": "developer@company.com",
"ascAppId": "1234567890",
"appleTeamId": "ABCDE12345"
},
"android": {
"serviceAccountKeyPath": "./play-store-key.json",
"track": "internal"
}
}
}
}
app.config.ts.const IS_PROD = process.env.APP_ENV === 'production';
const IS_STAGING = process.env.APP_ENV === 'staging';
export default {
name: IS_PROD ? 'MyApp' : IS_STAGING ? 'MyApp (Staging)' : 'MyApp (Dev)',
slug: 'my-app',
ios: {
bundleIdentifier: IS_PROD ? 'com.company.myapp' : 'com.company.myapp.dev',
},
android: {
package: IS_PROD ? 'com.company.myapp' : 'com.company.myapp.dev',
},
extra: {
apiUrl: IS_PROD
? 'https://api.company.com'
: IS_STAGING
? 'https://api.staging.company.com'
: 'https://api.dev.company.com',
},
};
# Build for production
eas build --platform all --profile production
# Submit to stores after build completes
eas submit --platform ios --profile production
eas submit --platform android --profile production
# Build and auto-submit in one command
eas build --platform all --profile production --auto-submit
npx expo install expo-updates
// app.config.ts
export default {
updates: {
url: 'https://u.expo.dev/your-project-id',
},
runtimeVersion: {
policy: 'appVersion', // or 'sdkVersion', 'fingerprint'
},
};
# Publish an OTA update to the production channel
eas update --branch production --message "Fix checkout button alignment"
# Publish to preview channel
eas update --branch preview --message "Test new onboarding flow"
import * as Updates from 'expo-updates';
async function checkForUpdates() {
if (__DEV__) return; // Updates do not work in development
try {
const update = await Updates.checkForUpdateAsync();
if (update.isAvailable) {
await Updates.fetchUpdateAsync();
// Restart to apply the update
await Updates.reloadAsync();
}
} catch (error) {
console.error('Update check failed:', error);
}
}
// Check on app foreground
useEffect(() => {
const subscription = AppState.addEventListener('change', (state) => {
if (state === 'active') checkForUpdates();
});
return () => subscription.remove();
}, []);
# .github/workflows/build.yml
name: Build and Deploy
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npm test
build:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- run: npm ci
- run: eas build --platform all --profile production --non-interactive --auto-submit
update:
needs: test
if: github.ref == 'refs/heads/main' && !contains(github.event.head_commit.message, '[native]')
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: expo/expo-github-action@v8
with:
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- run: npm ci
- run: eas update --branch production --message "${{ github.event.head_commit.message }}"
autoIncrement in EAS Build for automatic build number bumps. Semantic version the version field in app.config.ts.# Bump version
npm version patch # 1.0.0 -> 1.0.1
npm version minor # 1.0.0 -> 1.1.0
npm version major # 1.0.0 -> 2.0.0
eas build --platform ios --profile preview
# Install via QR code or direct link from EAS dashboard
OTA update limitations: OTA updates can only change JavaScript and assets. Changes to native code (new native modules, permission changes, SDK upgrades) require a new native build through the stores. Use runtimeVersion with fingerprint policy to automatically detect when a native build is needed.
App Store review tips:
Google Play review: Initial review takes hours to days. Use internal testing tracks for team testing, closed testing for beta users, and production for release.
Release strategy:
Common mistakes:
runtimeVersion when native dependencies changehttps://docs.expo.dev/deploy/build-project/