mobile deployment - nself-org/nchat GitHub Wiki
Complete guide for deploying nself-chat mobile applications to iOS App Store and Google Play Store.
- Overview
- iOS Deployment
- Android Deployment
- Fastlane Integration
- Automated Deployments
- Troubleshooting
nself-chat supports deployment to both iOS and Android platforms using Capacitor. This guide covers the complete deployment process for both platforms.
-
iOS: Use
scripts/deploy-mobile-ios.sh -
Android: Use
scripts/deploy-mobile-android.sh - Troubleshooting: See Troubleshooting section
iOS:
- TestFlight (Internal/External testing)
- App Store Production
Android:
- Internal Testing (immediate rollout)
- Closed Testing (Beta, requires opt-in)
- Open Testing (Public beta)
- Production
-
Apple Developer Account ($99/year)
- Sign up at: https://developer.apple.com
- Agree to developer agreements
-
App Store Connect Access
- Go to: https://appstoreconnect.apple.com
- Create your app listing
-
Development Environment
- macOS with Xcode installed
- Xcode Command Line Tools:
xcode-select --install - Valid signing certificates and provisioning profiles
-
App-Specific Password
- Generate at: https://appleid.apple.com/account/manage
- Required for command-line uploads
- Store securely (use in APP_SPECIFIC_PASSWORD env var)
-
Required Information
- Apple Team ID (found in developer.apple.com/account)
- Bundle Identifier (e.g.,
com.yourcompany.nchat) - App Name and Description
TestFlight allows you to distribute beta builds to internal and external testers.
- Go to https://appstoreconnect.apple.com
- Click "My Apps" → "+" → "New App"
- Fill in required information:
- Platform: iOS
- Name: Your app name (e.g., "nChat")
- Primary Language: English
- Bundle ID: Select your bundle identifier
- SKU: Unique identifier (can be bundle ID)
- Go to App Information
- Set Privacy Policy URL
- Set Category (Social Networking or Productivity)
- Configure Age Rating
- Upload app icon (1024x1024px, no transparency)
# Set required environment variables
export APPLE_TEAM_ID="ABC123XYZ"
export APPLE_ID="[email protected]"
export APP_SPECIFIC_PASSWORD="xxxx-xxxx-xxxx-xxxx"
# Deploy to TestFlight
cd /path/to/nself-chat
./scripts/deploy-mobile-ios.sh --testflightThe script will:
- Run tests
- Build web assets
- Sync to iOS platform
- Create archive
- Export IPA
- Upload to App Store Connect
After upload completes (10-30 minutes for processing):
- Go to App Store Connect → TestFlight
- Select the new build
- Add "What to Test" notes for testers
- Configure test information:
- Beta App Description
- Beta App Review Information
- Test Information
- Screenshot (optional)
- Go to TestFlight → Internal Testing
- Click "+" to add testers
- Enter email addresses
- Testers receive invitation email immediately
- They can install via TestFlight app
Internal Testing:
- Up to 100 testers
- No App Review required
- Immediate availability after processing
- 90-day expiration
- Go to TestFlight → External Testing
- Create a new group
- Add testers (up to 10,000)
- Submit for Beta App Review
- Wait for approval (1-2 days)
External Testing:
- Requires Beta App Review
- Public link available after approval
- 90-day expiration
- Can distribute publicly
- Go to App Store Connect → My Apps → Your App
- Create new version (if needed)
- Complete required information:
- App Name (max 30 characters)
- Subtitle (max 30 characters)
- Description (max 4,000 characters)
- Keywords (max 100 characters)
- Support URL
- Marketing URL (optional)
- Promotional Text (170 characters, can update without new version)
See iOS Screenshots section for requirements.
Required sizes:
- 6.7" Display (iPhone 14 Pro Max): 1290 x 2796 px
- 6.5" Display (iPhone 11 Pro Max): 1242 x 2688 px
- 5.5" Display (iPhone 8 Plus): 1242 x 2208 px
Minimum 3 screenshots per size, maximum 10.
# Deploy to production (requires manual submission)
./scripts/deploy-mobile-ios.sh --production- Select the uploaded build
- Set App Store release options:
- Manual release
- Automatic release
- Scheduled release
- Configure Age Rating
- Complete Export Compliance information
- Submit for Review
Review Timeline:
- 24-48 hours typically
- May be faster or slower depending on complexity
- Check status in App Store Connect
After approval:
- Manual: Click "Release This Version" when ready
- Automatic: Released immediately upon approval
- Scheduled: Released at specified date/time
The deployment script uses automatic signing by default:
# Xcode manages certificates and profiles automatically
./scripts/deploy-mobile-ios.sh --testflightXcode will:
- Create/download required certificates
- Create/download provisioning profiles
- Handle signing automatically
If you need manual control:
-
Create Certificates (developer.apple.com):
- Development: iOS App Development
- Distribution: iOS Distribution
-
Create App ID:
- Go to Certificates, Identifiers & Profiles
- Create App ID with your Bundle Identifier
- Enable required capabilities (Push Notifications, etc.)
-
Create Provisioning Profiles:
- Development: For testing on devices
- Ad Hoc: For limited distribution
- App Store: For App Store distribution
-
Install in Xcode:
- Download certificates and profiles
- Double-click to install
- Select in Xcode project settings
-
Configure Build Script:
export IOS_SIGNING_IDENTITY="iPhone Distribution: Your Name" export IOS_PROVISIONING_PROFILE="UUID-of-profile" ./scripts/deploy-mobile-ios.sh
"No signing certificate found"
- Install certificates from developer.apple.com
- Check in Xcode → Preferences → Accounts → Download Manual Profiles
"No provisioning profile found"
- Create provisioning profile in developer portal
- Ensure it includes your device UDIDs (for development)
- Download and install in Xcode
"Code signing entitlements don't match"
- Check App ID capabilities
- Regenerate provisioning profile
- Clean build folder and rebuild
Apple requires screenshots for multiple device sizes:
| Device | Resolution | Orientation |
|---|---|---|
| 6.7" (iPhone 14 Pro Max) | 1290 x 2796 px | Portrait |
| 6.5" (iPhone 11 Pro Max) | 1242 x 2688 px | Portrait |
| 5.5" (iPhone 8 Plus) | 1242 x 2208 px | Portrait |
| 12.9" iPad Pro | 2048 x 2732 px | Portrait |
Notes:
- Minimum 3 screenshots, maximum 10 per size
- PNG or JPEG format
- RGB color space
- No transparency
- Can show app in use, not device frame
Method 1: Simulator
# Start iOS Simulator
cd platforms/capacitor
npx cap open ios
# In Simulator:
# 1. Device → Select device type (iPhone 14 Pro Max)
# 2. Navigate to screens you want to capture
# 3. Cmd+S to save screenshot
# 4. Screenshots saved to DesktopMethod 2: Actual Device
# Connect device via USB
# Take screenshots on device (Power + Volume Up)
# Transfer via AirDrop or cableMethod 3: Automated (Fastlane Snapshot)
# Install fastlane
gem install fastlane
# Set up snapshot
cd platforms/capacitor/ios
fastlane snapshot init
# Configure Snapfile and UI tests
# Run snapshot
fastlane snapshotContent Guidelines:
- Show actual app functionality
- Use realistic data (not Lorem Ipsum)
- Avoid offensive content
- No pricing/promotion in screenshots (use promotional text)
- Localize for each language
Technical Guidelines:
- High quality, sharp images
- Proper color calibration
- No pixelation or artifacts
- Consistent status bar (can be hidden or standardized)
Best Practices:
- First screenshot is most important (shows in search)
- Show key features in order of importance
- Use captions to explain features
- Keep text readable
- Consider adding device frames for visual appeal (external tools)
- Simulator: Built into Xcode
- fastlane snapshot: Automated screenshot generation
- Shotbot: AI-powered screenshot generation
- DaVinci: Create marketing screenshots with device frames
- Screenshot Studio: Add device frames and backgrounds
-
Google Play Developer Account ($25 one-time fee)
- Sign up at: https://play.google.com/console/signup
- Pay registration fee
- Agree to developer agreements
-
Google Play Console Access
- Go to: https://play.google.com/console
- Create your app listing
-
Development Environment
- Android Studio installed
- Android SDK and build tools
- Java Development Kit (JDK 17+)
-
Release Keystore
- Create signing keystore (see below)
- Store securely and backup (cannot be recovered if lost)
-
Required Information
- Application ID (e.g.,
com.yourcompany.nchat) - App Name and Description
- Privacy Policy URL
- Application ID (e.g.,
- Go to https://play.google.com/console
- Click "Create app"
- Fill in required information:
- App name
- Default language
- App or game: App
- Free or paid: Free (or Paid)
- Declarations: Accept all required policies
# Generate release keystore
keytool -genkey -v \
-keystore release.keystore \
-alias upload-key \
-keyalg RSA \
-keysize 2048 \
-validity 10000
# Follow prompts to enter:
# - Keystore password (SAVE THIS!)
# - Key password (SAVE THIS!)
# - Your information (CN, OU, O, L, ST, C)
# IMPORTANT: Backup this file securely!
# If lost, you cannot update your app# Add to ~/.bashrc or ~/.zshrc
export ANDROID_KEYSTORE_PATH="/path/to/release.keystore"
export ANDROID_KEYSTORE_PASSWORD="your-keystore-password"
export ANDROID_KEY_ALIAS="upload-key"
export ANDROID_KEY_PASSWORD="your-key-password"
# Or create .env file (DO NOT COMMIT)
echo "ANDROID_KEYSTORE_PATH=/path/to/release.keystore" >> .env.local
echo "ANDROID_KEYSTORE_PASSWORD=your-password" >> .env.local
echo "ANDROID_KEY_ALIAS=upload-key" >> .env.local
echo "ANDROID_KEY_PASSWORD=your-password" >> .env.local# Build and prepare for upload
./scripts/deploy-mobile-android.sh --internal
# AAB file created at: platforms/capacitor/dist/nchat-release.aabManual Upload:
- Go to Play Console → Testing → Internal testing
- Click "Create new release"
- Upload AAB file:
platforms/capacitor/dist/nchat-release.aab - Add release notes
- Review and click "Start rollout to Internal testing"
- Create email list for internal testers
- Share internal testing link with team
Internal Testing Features:
- Up to 100 testers
- Immediate availability (no review)
- Can test for up to 90 days
- Fast iteration
- Go to Testing → Closed testing
- Create testing track
- Click "Create new release"
- Option 1: Promote from Internal testing
- Option 2: Upload new AAB
- Add release notes
- Review and rollout
- Wait for Pre-launch report (1-2 hours)
- Create opt-in URL for beta testers
Closed Testing Features:
- Up to 100,000 testers
- Requires Pre-launch report review
- Opt-in via link
- More thorough testing
- Go to Play Console → Main store listing
- Fill in required fields:
- App name (max 50 characters)
- Short description (max 80 characters)
- Full description (max 4,000 characters)
- App icon (512 x 512 px, 32-bit PNG)
- Feature graphic (1,024 x 500 px)
- Screenshots (see below)
- Category (Social or Communication)
- Contact details
- Privacy Policy URL
See Android Screenshots for requirements.
- Go to Content rating
- Start questionnaire
- Answer all questions honestly
- Receive rating (Everyone, Teen, Mature, etc.)
- Go to Pricing & distribution
- Select countries
- Set pricing (Free recommended for open-source)
- Confirm content guidelines compliance
# Build release bundle
./scripts/deploy-mobile-android.sh --production
# AAB created at: platforms/capacitor/dist/nchat-release.aab- Go to Production
- Create new release
- Upload AAB file
- Add release notes
- Review all details
- Submit for review
Review Timeline:
- Usually 1-7 days
- First submission may take longer
- Subsequent updates faster
- Check status in Play Console
Instead of releasing to 100%, you can:
- Start with 5% rollout
- Monitor crash rates and ratings
- Increase to 10%, 20%, 50%
- Roll back if issues found
- Eventually reach 100%
Android requires two types of keys:
- Upload Key: Used to sign APKs/AABs uploaded to Play Store
- App Signing Key: Google manages this for Play App Signing
Play App Signing (Recommended):
- Google manages your app signing key
- You keep your upload key
- Benefits:
- Can reset upload key if lost
- Optimized APKs for devices
- Enhanced security
When you first upload:
- Google generates app signing key, or
- You can upload your own signing key
Recommended: Let Google generate
- More secure
- Easier upload key reset
- No action needed
The deployment script handles signing automatically:
# Create keystore (one time)
keytool -genkey -v -keystore release.keystore \
-alias upload-key -keyalg RSA -keysize 2048 -validity 10000
# Set environment variables
export ANDROID_KEYSTORE_PATH="/path/to/release.keystore"
export ANDROID_KEYSTORE_PASSWORD="password"
export ANDROID_KEY_ALIAS="upload-key"
export ANDROID_KEY_PASSWORD="password"
# Deploy (automatically signs)
./scripts/deploy-mobile-android.shIf you need to sign manually:
# Build unsigned
cd platforms/capacitor/android
./gradlew bundleRelease
# Sign with jarsigner
jarsigner -verbose \
-sigalg SHA256withRSA \
-digestalg SHA-256 \
-keystore /path/to/release.keystore \
app/build/outputs/bundle/release/app-release.aab \
upload-key
# Verify signature
jarsigner -verify -verbose -certs \
app/build/outputs/bundle/release/app-release.aab-
Backup Your Keystore
- Store in multiple secure locations
- Use encrypted cloud storage
- Keep offline backup
- CRITICAL: You cannot update app if keystore is lost
-
Protect Passwords
- Use strong, unique passwords
- Store in password manager
- Never commit to git
- Use environment variables
-
Secure Storage
- Encrypt keystore file
- Restrict file permissions:
chmod 600 release.keystore - Store in secure location
- Consider hardware security module for CI/CD
Google Play requires screenshots for phone and tablet:
| Device Type | Min Resolution | Max Resolution | Quantity |
|---|---|---|---|
| Phone | 320 x 320 px | 3,840 x 3,840 px | 2-8 |
| 7" Tablet | 320 x 320 px | 3,840 x 3,840 px | 0-8 |
| 10" Tablet | 320 x 320 px | 3,840 x 3,840 px | 0-8 |
Common Sizes:
- Phone: 1080 x 1920 px (16:9) or 1080 x 2340 px (19.5:9)
- Tablet: 1200 x 1920 px or 2560 x 1600 px
Notes:
- PNG or JPEG format
- 16:9 or 9:16 aspect ratio recommended
- Can upload up to 8 per device type
- First screenshot is most prominent
Method 1: Emulator
# Start Android emulator
cd platforms/capacitor
npx cap open android
# In Android Studio:
# 1. Run app on emulator
# 2. Navigate to screens
# 3. Click camera icon in emulator toolbar
# 4. Or use Ctrl+S / Cmd+S
# 5. Screenshots saved to project folderMethod 2: Actual Device
# Connect device via USB
# Enable USB Debugging
# Take screenshots: Power + Volume Down
# Use adb to pull screenshots
adb pull /sdcard/Screenshots/ ./screenshots/Method 3: Automated (Fastlane Screengrab)
# Install fastlane
gem install fastlane
# Set up screengrab
cd platforms/capacitor/android
fastlane screengrab init
# Configure Screengrabfile
# Run screengrab
fastlane screengrabContent Guidelines:
- Show actual app functionality
- Use realistic, appropriate content
- Avoid graphic violence or adult content
- No misleading features
- Localize for supported languages
Technical Guidelines:
- High resolution (1080p or higher recommended)
- Sharp, clear images
- Proper color reproduction
- No alpha channel/transparency
- No device chrome (just app content)
Best Practices:
- First screenshot is most important
- Show key features first
- Use captions to explain features
- Consistent styling across screenshots
- Show diverse use cases
Required for Play Store listing:
- Size: 1,024 x 500 px
- Format: PNG or JPEG
- Purpose: Shown at top of store listing
- Content: App name, key features, branding
- No device frames: Just app branding/features
Create feature graphic with:
- App logo
- Tagline
- Key feature preview
- Brand colors
- No text overlap on important areas (can be cut off on mobile)
Fastlane automates screenshot generation, signing, and deployment.
# Install via RubyGems
gem install fastlane
# Or via Homebrew
brew install fastlane
# Verify installation
fastlane --version# Navigate to iOS project
cd platforms/capacitor/ios
# Initialize fastlane
fastlane init
# Select option 4 (Manual setup)
# Configure Appfile
cat > fastlane/Appfile <<'EOF'
app_identifier("com.yourcompany.nchat")
apple_id("[email protected]")
team_id("ABC123XYZ")
# App Store Connect API key (optional)
# api_key_path("./AuthKey_ABC123.p8")
EOF
# Configure Fastfile
cat > fastlane/Fastfile <<'EOF'
default_platform(:ios)
platform :ios do
desc "Push a new beta build to TestFlight"
lane :beta do
increment_build_number
build_app(
workspace: "App/App.xcworkspace",
scheme: "App",
export_method: "app-store"
)
upload_to_testflight(
skip_waiting_for_build_processing: true
)
end
desc "Deploy to App Store"
lane :release do
build_app(
workspace: "App/App.xcworkspace",
scheme: "App",
export_method: "app-store"
)
upload_to_app_store(
submit_for_review: false,
automatic_release: false
)
end
desc "Generate screenshots"
lane :screenshots do
snapshot
end
end
EOF# Navigate to Android project
cd platforms/capacitor/android
# Initialize fastlane
fastlane init
# Follow prompts to set up Google Play integration
# Configure Appfile
cat > fastlane/Appfile <<'EOF'
json_key_file("path/to/service-account.json")
package_name("com.yourcompany.nchat")
EOF
# Configure Fastfile
cat > fastlane/Fastfile <<'EOF'
default_platform(:android)
platform :android do
desc "Deploy to Internal Testing"
lane :internal do
gradle(
task: "bundle",
build_type: "Release"
)
upload_to_play_store(
track: "internal",
aab: "app/build/outputs/bundle/release/app-release.aab"
)
end
desc "Deploy to Beta"
lane :beta do
gradle(
task: "bundle",
build_type: "Release"
)
upload_to_play_store(
track: "beta",
aab: "app/build/outputs/bundle/release/app-release.aab"
)
end
desc "Deploy to Production"
lane :production do
gradle(
task: "bundle",
build_type: "Release"
)
upload_to_play_store(
track: "production",
aab: "app/build/outputs/bundle/release/app-release.aab"
)
end
desc "Generate screenshots"
lane :screenshots do
screengrab
end
end
EOF# iOS: Deploy to TestFlight
cd platforms/capacitor/ios
fastlane beta
# iOS: Deploy to App Store
fastlane release
# iOS: Generate screenshots
fastlane screenshots
# Android: Deploy to Internal Testing
cd platforms/capacitor/android
fastlane internal
# Android: Deploy to Beta
fastlane beta
# Android: Deploy to Production
fastlane production
# Android: Generate screenshots
fastlane screenshotsFor automated Android deployments:
- Go to Google Play Console
- Settings → API access
- Create new service account
- Grant permissions:
- Release apps
- View app information
- Manage testing tracks
- Download JSON key file
- Store securely (do not commit)
- Reference in Fastfile
# Set up service account
export GOOGLE_PLAY_SERVICE_ACCOUNT="/path/to/service-account.json"
# Use in deployment
fastlane betaCreate workflow for automated deployments.
# .github/workflows/deploy-ios.yml
name: Deploy iOS
on:
push:
tags:
- 'v*'
workflow_dispatch:
jobs:
deploy:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build web assets
run: pnpm build
- name: Setup iOS certificates
uses: apple-actions/import-codesign-certs@v2
with:
p12-file-base64: ${{ secrets.IOS_DIST_CERT }}
p12-password: ${{ secrets.IOS_CERT_PASSWORD }}
- name: Deploy to TestFlight
env:
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APP_SPECIFIC_PASSWORD: ${{ secrets.APP_SPECIFIC_PASSWORD }}
run: |
chmod +x scripts/deploy-mobile-ios.sh
./scripts/deploy-mobile-ios.sh --testflight# .github/workflows/deploy-android.yml
name: Deploy Android
on:
push:
tags:
- 'v*'
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Setup Java
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build web assets
run: pnpm build
- name: Decode keystore
run: |
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > release.keystore
- name: Deploy to Play Store
env:
ANDROID_KEYSTORE_PATH: ./release.keystore
ANDROID_KEYSTORE_PASSWORD: ${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
ANDROID_KEY_ALIAS: ${{ secrets.ANDROID_KEY_ALIAS }}
ANDROID_KEY_PASSWORD: ${{ secrets.ANDROID_KEY_PASSWORD }}
GOOGLE_PLAY_SERVICE_ACCOUNT: ${{ secrets.GOOGLE_PLAY_SERVICE_ACCOUNT }}
run: |
chmod +x scripts/deploy-mobile-android.sh
./scripts/deploy-mobile-android.sh --internalAdd these secrets to your GitHub repository:
iOS:
-
APPLE_TEAM_ID: Your Apple Team ID -
APPLE_ID: Your Apple ID email -
APP_SPECIFIC_PASSWORD: App-specific password -
IOS_DIST_CERT: Distribution certificate (base64) -
IOS_CERT_PASSWORD: Certificate password
Android:
-
ANDROID_KEYSTORE_BASE64: Keystore file (base64 encoded) -
ANDROID_KEYSTORE_PASSWORD: Keystore password -
ANDROID_KEY_ALIAS: Key alias -
ANDROID_KEY_PASSWORD: Key password -
GOOGLE_PLAY_SERVICE_ACCOUNT: Service account JSON (base64)
See the dedicated Mobile Deployment Troubleshooting Guide for common issues and solutions.
iOS build fails:
# Clean build
cd platforms/capacitor/ios
rm -rf build/
xcodebuild clean
# Update pods
pod install --repo-updateAndroid build fails:
# Clean build
cd platforms/capacitor/android
./gradlew clean
# Update Gradle
./gradlew wrapper --gradle-version=8.0Code signing errors:
# iOS: Reset signing
# Open in Xcode and disable/enable automatic signing
# Android: Verify keystore
keytool -list -v -keystore release.keystore- iOS App Distribution Guide
- Google Play Launch Checklist
- Capacitor iOS Documentation
- Capacitor Android Documentation
- Fastlane Documentation
- Transporter - Upload iOS builds
- bundletool - Test Android App Bundles
- fastlane - Automate deployments
- Screener - Generate app screenshots
For issues or questions:
- Check the Troubleshooting Guide
- Search GitHub Issues
- Create new issue with:
- Platform (iOS/Android)
- Error message
- Steps to reproduce
- Environment details
Last Updated: January 31, 2026 Version: 1.0.0