Deployment & Distribution
Learn how to prepare, build, and distribute your React Native app to the App Store and Google Play Store using Expo Application Services (EAS).
Overview
Deployment and distribution is the final step in bringing your React Native app to users. This guide covers the entire process from preparing your app for production to publishing on app stores.
Table of Contents
- Pre-deployment Checklist
- EAS Build Configuration
- App Store Preparation
- Building for Production
- App Store Submission
- Google Play Store
- Over-the-Air Updates
- Monitoring & Analytics
- Best Practices
Pre-deployment Checklist
Code Quality
// Ensure all TypeScript errors are resolved
// Run comprehensive tests
npm run test
npm run type-check
npm run lint
// Check for unused dependencies
npx depcheck
// Verify app performance
npm run performance-test
App Configuration
// app.json - Production configuration
{
"expo": {
"name": "Your App Name",
"slug": "your-app-slug",
"version": "1.0.0",
"orientation": "portrait",
"privacy": "public",
"platforms": ["ios", "android"],
"icon": "./assets/images/icon.png",
"splash": {
"image": "./assets/images/splash.png",
"resizeMode": "contain",
"backgroundColor": "#ffffff"
},
"updates": {
"fallbackToCacheTimeout": 0
},
"assetBundlePatterns": ["**/*"],
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.yourcompany.yourapp",
"buildNumber": "1"
},
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
},
"package": "com.yourcompany.yourapp",
"versionCode": 1
}
}
}
Assets & Resources
// Optimize images and assets
const assetOptimization = {
images: {
// Use WebP format when possible
format: "webp",
// Provide multiple resolutions
resolutions: ["@1x", "@2x", "@3x"],
// Compress appropriately
quality: 80,
},
fonts: {
// Include only used font weights
weights: ["400", "600", "700"],
// Use system fonts when possible
fallbacks: ["system"],
},
}
EAS Build Configuration
Installing EAS CLI
# Install EAS CLI globally
npm install -g @expo/eas-cli
# Login to your Expo account
eas login
# Initialize EAS in your project
eas build:configure
EAS Configuration
// eas.json
{
"cli": {
"version": ">= 5.4.0"
},
"build": {
"development": {
"developmentClient": true,
"distribution": "internal"
},
"preview": {
"distribution": "internal",
"ios": {
"simulator": true
}
},
"production": {
"autoIncrement": true,
"env": {
"NODE_ENV": "production"
}
}
},
"submit": {
"production": {
"ios": {
"appleId": "your-apple-id@example.com",
"ascAppId": "1234567890",
"appleTeamId": "XXXXXXXXXX"
},
"android": {
"serviceAccountKeyPath": "./google-service-account.json",
"track": "production"
}
}
}
}
Environment Variables
// Managing environment variables
// .env.production
API_URL=https://api.yourapp.com
ANALYTICS_KEY=prod_analytics_key
SENTRY_DSN=https://sentry.dsn
// Using environment variables
import Constants from 'expo-constants';
const config = {
apiUrl: Constants.expoConfig?.extra?.apiUrl,
analyticsKey: Constants.expoConfig?.extra?.analyticsKey,
};
App Store Preparation
iOS App Store Connect
// iOS specific configurations
const iosConfig = {
bundleIdentifier: "com.yourcompany.yourapp",
teamId: "XXXXXXXXXX",
// App Store Connect information
appStoreConnect: {
appId: "1234567890",
categories: ["Productivity", "Business"],
contentRating: "4+",
description: "Your app description",
keywords: "productivity, business, mobile",
supportUrl: "https://yourapp.com/support",
privacyUrl: "https://yourapp.com/privacy",
},
}
Screenshots & Metadata
// Screenshot requirements
const screenshotRequirements = {
iPhoneSE: "1242 x 2208",
iPhone8Plus: "1242 x 2208",
iPhone11Pro: "1125 x 2436",
iPhone12ProMax: "1284 x 2778",
iPadPro: "2048 x 2732",
// Android
phone: "1080 x 1920",
sevenInchTablet: "1200 x 1920",
tenInchTablet: "1600 x 2560",
}
Building for Production
iOS Build
# Build for iOS App Store
eas build --platform ios --profile production
# Build for TestFlight
eas build --platform ios --profile preview
# Check build status
eas build:list
Android Build
# Build for Google Play Store
eas build --platform android --profile production
# Build APK for testing
eas build --platform android --profile preview --format apk
# Build AAB (recommended for Play Store)
eas build --platform android --profile production --format aab
Build Optimization
// Metro bundler optimization
// metro.config.js
module.exports = {
transformer: {
minifierConfig: {
mangle: {
keep_fnames: true,
},
},
},
resolver: {
alias: {
"@": "./src",
},
},
}
// Hermes engine optimization (Android)
const androidConfig = {
enableHermes: true,
proguardMinifyEnabled: true,
shrinkResources: true,
}
App Store Submission
iOS Submission
# Submit to App Store Connect
eas submit --platform ios --profile production
# Or submit manually with Transporter app
# Download .ipa from EAS and upload via Transporter
App Store Review Guidelines
// Common rejection reasons to avoid
const avoidRejections = {
privacy: {
// Include privacy policy
privacyPolicyUrl: "https://yourapp.com/privacy",
// Request permissions appropriately
permissionDescriptions: {
camera: "Used to scan QR codes",
location: "Used to find nearby stores",
},
},
functionality: {
// Ensure app works offline if applicable
offlineSupport: true,
// No placeholder content
realContent: true,
// Proper error handling
errorHandling: true,
},
}
Google Play Store
Play Console Setup
// Android signing configuration
const androidSigning = {
// EAS handles signing automatically
// Or configure manual signing
signingConfig: {
keyAlias: "your-key-alias",
keyPassword: "your-key-password",
storeFile: "./keystore.jks",
storePassword: "your-store-password",
},
}
Play Store Submission
# Submit to Google Play
eas submit --platform android --profile production
# Upload AAB manually via Play Console
# Or use Google Play CLI
Play Store Optimization
// App Bundle optimization
const bundleConfig = {
// Enable App Bundle
bundleFormat: "aab",
// Dynamic delivery
dynamicFeatures: {
camera: {
onDemand: true,
deliveryType: "on_demand",
},
},
// Asset packs
assetPacks: {
images: {
deliveryType: "install_time",
},
},
}
Over-the-Air Updates
EAS Update Setup
# Install EAS Update
expo install expo-updates
# Configure updates
eas update:configure
# Publish an update
eas update --branch production --message "Bug fixes and improvements"
Update Configuration
// app.json - Update configuration
{
"expo": {
"updates": {
"url": "https://u.expo.dev/your-project-id",
"requestHeaders": {
"expo-channel-name": "production"
}
},
"runtimeVersion": {
"policy": "sdkVersion"
}
}
}
// Check for updates in app
import * as Updates from 'expo-updates';
const checkForUpdates = async () => {
try {
const update = await Updates.checkForUpdateAsync();
if (update.isAvailable) {
await Updates.fetchUpdateAsync();
await Updates.reloadAsync();
}
} catch (error) {
console.log('Error checking for updates:', error);
}
};
Monitoring & Analytics
Crash Reporting
// Sentry integration
import * as Sentry from "@sentry/react-native"
Sentry.init({
dsn: "your-sentry-dsn",
environment: __DEV__ ? "development" : "production",
})
// Crashlytics (Firebase)
import crashlytics from "@react-native-firebase/crashlytics"
crashlytics().recordError(new Error("Something went wrong"))
Analytics Setup
// Firebase Analytics
import analytics from "@react-native-firebase/analytics"
const trackEvent = async (eventName: string, parameters: object) => {
await analytics().logEvent(eventName, parameters)
}
// Custom analytics
const trackUserAction = (action: string, screen: string) => {
analytics().logEvent("user_action", {
action,
screen,
timestamp: Date.now(),
})
}
Performance Monitoring
// React Native Performance
import Perf from "react-native-performance"
const performanceMonitoring = {
// Track screen transitions
trackNavigation: (screen: string) => {
Perf.mark(`navigation_to_${screen}`)
},
// Monitor API calls
trackApiCall: (endpoint: string, duration: number) => {
analytics().logEvent("api_call", {
endpoint,
duration,
success: duration < 5000,
})
},
}
Best Practices
Versioning Strategy
// Semantic versioning
const versionStrategy = {
major: "Breaking changes",
minor: "New features",
patch: "Bug fixes",
// Example: 1.2.3
// 1 = Major version
// 2 = Minor version
// 3 = Patch version
}
// Automated versioning
const incrementVersion = (type: "major" | "minor" | "patch") => {
// Use tools like semantic-release or standard-version
// Or EAS autoIncrement feature
}
Release Management
// Release checklist
const releaseChecklist = {
preRelease: [
"Run full test suite",
"Update version numbers",
"Update changelog",
"Test on physical devices",
"Performance testing",
"Security review",
],
release: [
"Build production versions",
"Submit to app stores",
"Update marketing materials",
"Prepare release notes",
"Monitor for issues",
],
postRelease: ["Monitor crash reports", "Track user feedback", "Plan hotfixes if needed", "Analyze adoption metrics"],
}
Rollback Strategy
// Emergency rollback plan
const rollbackStrategy = {
// Over-the-air updates
hotfix: async () => {
await eas.update.publish({
branch: "production",
message: "Emergency rollback",
})
},
// App store rollback
appStore: {
ios: "Use App Store Connect to rollback",
android: "Release previous version with higher version code",
},
// Feature flags for gradual rollout
featureFlags: {
newFeature: {
enabled: false,
percentage: 0,
},
},
}
Common Issues & Solutions
Build Failures
// Common build issues and solutions
const troubleshooting = {
"Metro bundler timeout": {
solution: "Increase metro timeout in metro.config.js",
config: { resetCache: true },
},
"iOS provisioning profile": {
solution: "Update certificates in Apple Developer Portal",
command: "eas credentials",
},
"Android signing": {
solution: "Verify keystore configuration",
check: "eas credentials:configure",
},
}
Store Rejection Solutions
// Common rejection fixes
const rejectionFixes = {
"Missing privacy policy": {
fix: "Add privacy policy URL to app configuration",
location: "app.json or App Store Connect",
},
"Incomplete information": {
fix: "Provide detailed app description and keywords",
requirement: "Minimum 10 words description",
},
"Inappropriate content": {
fix: "Review content guidelines and age rating",
reference: "App Store Review Guidelines",
},
}
Next Steps
Once your app is successfully deployed:
- Performance Optimization - Monitor and optimize production performance
- Advanced Topics - Explore advanced deployment strategies
- Testing Strategies - Implement comprehensive testing for releases