# Mobile Build & Deployment Guide - Maternal Organization App ## Build Environment Setup ### Prerequisites ```bash # Required tools node >= 18.0.0 npm >= 9.0.0 react-native-cli >= 2.0.1 expo-cli >= 6.0.0 cocoapods >= 1.12.0 (iOS) java 11 (Android) android-studio (Android) xcode >= 14.0 (iOS) ``` ### Project Initialization ```bash # Create project with Expo npx create-expo-app maternal-app --template # Install core dependencies cd maternal-app npm install react-native-reanimated react-native-gesture-handler npm install react-native-safe-area-context react-native-screens npm install @react-navigation/native @react-navigation/bottom-tabs ``` --- ## iOS Configuration ### Bundle Identifier & Provisioning ```xml CFBundleIdentifier com.maternalapp.ios CFBundleDisplayName Maternal CFBundleShortVersionString 1.0.0 CFBundleVersion 1 ``` ### App Capabilities ```xml aps-environment production com.apple.developer.healthkit com.apple.developer.healthkit.background-delivery com.apple.security.application-groups group.com.maternalapp.shared ``` ### Permissions ```xml NSCameraUsageDescription Take photos of your child for memories and milestone tracking NSMicrophoneUsageDescription Enable voice input for hands-free activity logging NSPhotoLibraryUsageDescription Select photos for your child's profile and milestones NSSpeechRecognitionUsageDescription Convert your voice to text for quick logging NSHealthShareUsageDescription Read health data to track your child's growth NSHealthUpdateUsageDescription Save growth measurements to Health app ``` ### Code Signing Configuration ```ruby # ios/fastlane/Fastfile platform :ios do desc "Build and deploy to TestFlight" lane :beta do increment_build_number match( type: "appstore", app_identifier: "com.maternalapp.ios", git_url: "git@github.com:maternal-app/certificates.git" ) gym( scheme: "MaternalApp", configuration: "Release", export_method: "app-store", output_directory: "./build", output_name: "MaternalApp.ipa" ) pilot( ipa: "./build/MaternalApp.ipa", skip_waiting_for_build_processing: true, changelog: "Bug fixes and performance improvements" ) end end ``` --- ## Android Configuration ### Package Name & Versioning ```gradle // android/app/build.gradle android { compileSdkVersion 34 buildToolsVersion "34.0.0" defaultConfig { applicationId "com.maternalapp.android" minSdkVersion 23 // Android 6.0 targetSdkVersion 34 versionCode 1 versionName "1.0.0" multiDexEnabled true } signingConfigs { release { storeFile file(MATERNAL_RELEASE_STORE_FILE) storePassword MATERNAL_RELEASE_STORE_PASSWORD keyAlias MATERNAL_RELEASE_KEY_ALIAS keyPassword MATERNAL_RELEASE_KEY_PASSWORD } } buildTypes { release { signingConfig signingConfigs.release minifyEnabled true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } } ``` ### Permissions ```xml ``` ### ProGuard Rules ```pro # android/app/proguard-rules.pro -keep class com.maternalapp.** { *; } -keep class com.facebook.react.** { *; } -keep class com.swmansion.** { *; } # React Native -keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip -keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters # Firebase -keep class com.google.firebase.** { *; } -keep class com.google.android.gms.** { *; } ``` --- ## Environment-Specific Builds ### Build Configurations ```javascript // app.config.js export default ({ config }) => { const buildType = process.env.BUILD_TYPE || 'development'; const configs = { development: { name: 'Maternal (Dev)', bundleIdentifier: 'com.maternalapp.dev', apiUrl: 'https://dev-api.maternalapp.com', icon: './assets/icon-dev.png', }, staging: { name: 'Maternal (Staging)', bundleIdentifier: 'com.maternalapp.staging', apiUrl: 'https://staging-api.maternalapp.com', icon: './assets/icon-staging.png', }, production: { name: 'Maternal', bundleIdentifier: 'com.maternalapp.ios', apiUrl: 'https://api.maternalapp.com', icon: './assets/icon.png', }, }; return { ...config, ...configs[buildType], ios: { ...config.ios, bundleIdentifier: configs[buildType].bundleIdentifier, buildNumber: '1', }, android: { ...config.android, package: configs[buildType].bundleIdentifier.replace('ios', 'android'), versionCode: 1, }, }; }; ``` ### Environment Variables ```bash # .env.production API_URL=https://api.maternalapp.com SENTRY_DSN=https://prod-sentry.maternalapp.com ANALYTICS_ENABLED=true CRASH_REPORTING=true # .env.staging API_URL=https://staging-api.maternalapp.com SENTRY_DSN=https://staging-sentry.maternalapp.com ANALYTICS_ENABLED=true CRASH_REPORTING=true # .env.development API_URL=http://localhost:3000 SENTRY_DSN= ANALYTICS_ENABLED=false CRASH_REPORTING=false ``` --- ## CI/CD Pipeline ### GitHub Actions Workflow ```yaml # .github/workflows/mobile-deploy.yml name: Mobile Build & Deploy on: push: branches: [main, staging] tags: ['v*'] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-node@v3 with: node-version: '18' - run: npm ci - run: npm test - run: npm run lint build-ios: needs: test runs-on: macos-latest if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') steps: - uses: actions/checkout@v3 - name: Setup Node uses: actions/setup-node@v3 with: node-version: '18' - name: Install dependencies run: | npm ci cd ios && pod install - name: Setup certificates env: CERTIFICATE_BASE64: ${{ secrets.IOS_CERTIFICATE_BASE64 }} PROVISION_PROFILE_BASE64: ${{ secrets.IOS_PROVISION_PROFILE_BASE64 }} KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }} run: | # Create keychain security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain security default-keychain -s build.keychain security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain # Import certificate echo "$CERTIFICATE_BASE64" | base64 --decode > certificate.p12 security import certificate.p12 -k build.keychain -P "${{ secrets.CERTIFICATE_PASSWORD }}" -T /usr/bin/codesign # Import provisioning profile echo "$PROVISION_PROFILE_BASE64" | base64 --decode > profile.mobileprovision mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles cp profile.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/ - name: Build IPA run: | cd ios xcodebuild -workspace MaternalApp.xcworkspace \ -scheme MaternalApp \ -configuration Release \ -archivePath $PWD/build/MaternalApp.xcarchive \ archive xcodebuild -exportArchive \ -archivePath $PWD/build/MaternalApp.xcarchive \ -exportPath $PWD/build \ -exportOptionsPlist ExportOptions.plist - name: Upload to TestFlight env: APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }} run: | xcrun altool --upload-app \ --type ios \ --file ios/build/MaternalApp.ipa \ --apiKey "${{ secrets.API_KEY_ID }}" \ --apiIssuer "${{ secrets.API_ISSUER_ID }}" build-android: needs: test runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') steps: - uses: actions/checkout@v3 - name: Setup Node uses: actions/setup-node@v3 with: node-version: '18' - name: Setup Java uses: actions/setup-java@v3 with: distribution: 'temurin' java-version: '11' - name: Install dependencies run: npm ci - name: Setup keystore env: KEYSTORE_BASE64: ${{ secrets.ANDROID_KEYSTORE_BASE64 }} run: | echo "$KEYSTORE_BASE64" | base64 --decode > android/app/release.keystore echo "MATERNAL_RELEASE_STORE_FILE=release.keystore" >> android/gradle.properties echo "MATERNAL_RELEASE_KEY_ALIAS=${{ secrets.ANDROID_KEY_ALIAS }}" >> android/gradle.properties echo "MATERNAL_RELEASE_STORE_PASSWORD=${{ secrets.ANDROID_STORE_PASSWORD }}" >> android/gradle.properties echo "MATERNAL_RELEASE_KEY_PASSWORD=${{ secrets.ANDROID_KEY_PASSWORD }}" >> android/gradle.properties - name: Build APK run: | cd android ./gradlew assembleRelease - name: Build AAB run: | cd android ./gradlew bundleRelease - name: Upload to Play Store uses: r0adkll/upload-google-play@v1 with: serviceAccountJsonPlainText: ${{ secrets.PLAY_SERVICE_ACCOUNT_JSON }} packageName: com.maternalapp.android releaseFiles: android/app/build/outputs/bundle/release/app-release.aab track: internal status: draft ``` --- ## TestFlight Configuration ### App Store Connect Setup ```javascript // ios/fastlane/metadata/en-US/description.txt Maternal is your AI-powered parenting companion, designed to reduce mental load and bring confidence to your parenting journey. Key Features: • Smart activity tracking with voice input • AI assistant available 24/7 for parenting questions • Real-time family synchronization • Sleep predictions based on your baby's patterns • Growth tracking with WHO percentiles // ios/fastlane/metadata/en-US/keywords.txt parenting,baby tracker,sleep tracking,feeding log,AI assistant,family app,childcare ``` ### Beta Testing Groups ```yaml # TestFlight Groups internal_testing: name: "Internal Team" members: 10 builds: all beta_families: name: "Beta Families" members: 50 builds: stable feedback: enabled early_access: name: "Early Access" members: 500 builds: release_candidate ``` --- ## Google Play Console Configuration ### Store Listing ```yaml # Play Console Setup app_details: title: "Maternal - AI Parenting Assistant" short_description: "Smart parenting companion with AI support" full_description: | Complete description... category: "Parenting" content_rating: "Everyone" graphics: icon: 512x512px feature_graphic: 1024x500px screenshots: phone: [6 images minimum] tablet: [optional] ``` ### Release Tracks ```yaml internal_testing: testers: "internal-testers@maternalapp.com" release_frequency: "daily" closed_testing: testers: 100 release_frequency: "weekly" open_testing: countries: ["US", "CA", "GB", "AU"] release_frequency: "bi-weekly" production: rollout_percentage: 10 # Start with 10% staged_rollout: true ``` --- ## Over-the-Air Updates ### CodePush Setup ```bash # Install CodePush npm install react-native-code-push # iOS setup cd ios && pod install # Register app with CodePush code-push app add Maternal-iOS ios react-native code-push app add Maternal-Android android react-native ``` ### Update Configuration ```javascript // App.js import CodePush from 'react-native-code-push'; const codePushOptions = { checkFrequency: CodePush.CheckFrequency.ON_APP_RESUME, installMode: CodePush.InstallMode.ON_NEXT_RESTART, mandatoryInstallMode: CodePush.InstallMode.IMMEDIATE, updateDialog: { title: 'Update Available', mandatoryUpdateMessage: 'An important update is available.', optionalUpdateMessage: 'An update is available. Would you like to install it?', }, }; export default CodePush(codePushOptions)(App); ``` ### Deployment Commands ```bash # Deploy update to staging code-push release-react Maternal-iOS ios -d Staging code-push release-react Maternal-Android android -d Staging # Promote to production code-push promote Maternal-iOS Staging Production -r 10% code-push promote Maternal-Android Staging Production -r 10% ``` --- ## Performance Monitoring ### Build Size Optimization ```javascript // metro.config.js module.exports = { transformer: { minifierConfig: { keep_fnames: true, mangle: { keep_fnames: true, }, }, }, }; ``` ### Bundle Analysis ```bash # Analyze bundle size npx react-native-bundle-visualizer # iOS specific npx react-native bundle --platform ios --dev false --entry-file index.js --bundle-output ios/main.jsbundle --assets-dest ios # Android specific cd android && ./gradlew bundleRelease --scan ``` --- ## Pre-Launch Checklist ### iOS Submission - [ ] TestFlight build approved - [ ] App Store screenshots (6.5", 5.5") - [ ] App preview video (optional) - [ ] Privacy policy URL - [ ] Support URL - [ ] Marketing URL - [ ] Age rating questionnaire - [ ] Export compliance - [ ] App Review notes ### Android Submission - [ ] Signed AAB uploaded - [ ] Store listing complete - [ ] Content rating questionnaire - [ ] Target audience declaration - [ ] Data safety form - [ ] Privacy policy URL - [ ] App category selected - [ ] Closed testing feedback addressed ### General Requirements - [ ] COPPA compliance verified - [ ] GDPR compliance documented - [ ] Terms of service updated - [ ] Support system ready - [ ] Analytics tracking verified - [ ] Crash reporting active - [ ] Performance benchmarks met - [ ] Accessibility tested