590 lines
15 KiB
Markdown
590 lines
15 KiB
Markdown
# 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
|
|
<!-- ios/MaternalApp/Info.plist -->
|
|
<key>CFBundleIdentifier</key>
|
|
<string>com.maternalapp.ios</string>
|
|
<key>CFBundleDisplayName</key>
|
|
<string>Maternal</string>
|
|
<key>CFBundleShortVersionString</key>
|
|
<string>1.0.0</string>
|
|
<key>CFBundleVersion</key>
|
|
<string>1</string>
|
|
```
|
|
|
|
### App Capabilities
|
|
```xml
|
|
<!-- ios/MaternalApp/MaternalApp.entitlements -->
|
|
<?xml version="1.0" encoding="UTF-8"?>
|
|
<plist version="1.0">
|
|
<dict>
|
|
<key>aps-environment</key>
|
|
<string>production</string>
|
|
<key>com.apple.developer.healthkit</key>
|
|
<true/>
|
|
<key>com.apple.developer.healthkit.background-delivery</key>
|
|
<true/>
|
|
<key>com.apple.security.application-groups</key>
|
|
<array>
|
|
<string>group.com.maternalapp.shared</string>
|
|
</array>
|
|
</dict>
|
|
</plist>
|
|
```
|
|
|
|
### Permissions
|
|
```xml
|
|
<!-- ios/MaternalApp/Info.plist -->
|
|
<key>NSCameraUsageDescription</key>
|
|
<string>Take photos of your child for memories and milestone tracking</string>
|
|
<key>NSMicrophoneUsageDescription</key>
|
|
<string>Enable voice input for hands-free activity logging</string>
|
|
<key>NSPhotoLibraryUsageDescription</key>
|
|
<string>Select photos for your child's profile and milestones</string>
|
|
<key>NSSpeechRecognitionUsageDescription</key>
|
|
<string>Convert your voice to text for quick logging</string>
|
|
<key>NSHealthShareUsageDescription</key>
|
|
<string>Read health data to track your child's growth</string>
|
|
<key>NSHealthUpdateUsageDescription</key>
|
|
<string>Save growth measurements to Health app</string>
|
|
```
|
|
|
|
### 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
|
|
<!-- android/app/src/main/AndroidManifest.xml -->
|
|
<uses-permission android:name="android.permission.INTERNET" />
|
|
<uses-permission android:name="android.permission.CAMERA" />
|
|
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
|
<uses-permission android:name="android.permission.VIBRATE" />
|
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
|
|
|
<!-- Google Play Services -->
|
|
<uses-permission android:name="com.google.android.gms.permission.AD_ID" tools:node="remove" />
|
|
```
|
|
|
|
### 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 |