Publishing to App Stores
Guide to submitting Capacitor apps to Apple App Store and Google Play Store.
When to Use This Skill
- •User is ready to publish app
- •User asks about app store submission
- •User needs app store screenshots
- •User has app rejection issues
- •User needs to update app listing
Pre-Submission Checklist
Universal Requirements
- • App icon in all required sizes
- • Splash screen configured
- • App name and bundle ID set
- • Version and build numbers set
- • Privacy policy URL
- • Terms of service URL
- • Support email/URL
- • Age rating content questionnaire
- • App description (short and long)
- • Keywords/tags
- • Screenshots for all device sizes
- • Feature graphic (Android)
- • App preview video (optional)
iOS-Specific
- • Apple Developer Program membership ($99/year)
- • App Store Connect app created
- • Signing certificates and profiles
- • Info.plist usage descriptions
- • App Tracking Transparency (if applicable)
- • Sign in with Apple (if social login used)
- • Export compliance (encryption)
Android-Specific
- • Google Play Developer account ($25 one-time)
- • App signed with release keystore
- • Target SDK level (API 34+)
- • 64-bit support
- • Permissions declared in manifest
- • Data safety form completed
- • Content rating questionnaire
App Store Configuration
Version and Build Numbers
typescript
// capacitor.config.ts - Not stored here, just for reference // iOS: Info.plist // CFBundleShortVersionString = "1.2.3" (user-visible) // CFBundleVersion = "45" (build number, increment each upload) // Android: build.gradle // versionName = "1.2.3" (user-visible) // versionCode = 45 (must increment each upload)
iOS Info.plist
xml
<!-- ios/App/App/Info.plist --> <key>CFBundleDisplayName</key> <string>My App</string> <key>CFBundleShortVersionString</key> <string>1.0.0</string> <key>CFBundleVersion</key> <string>1</string> <!-- Privacy descriptions - REQUIRED for permissions --> <key>NSCameraUsageDescription</key> <string>Take photos for your profile</string> <key>NSPhotoLibraryUsageDescription</key> <string>Select photos from your library</string> <key>NSLocationWhenInUseUsageDescription</key> <string>Find nearby locations</string> <key>NSFaceIDUsageDescription</key> <string>Secure login with Face ID</string> <key>NSMicrophoneUsageDescription</key> <string>Record voice messages</string> <!-- App Tracking Transparency --> <key>NSUserTrackingUsageDescription</key> <string>Allow tracking for personalized ads</string> <!-- Export compliance --> <key>ITSAppUsesNonExemptEncryption</key> <false/>
Android build.gradle
groovy
// android/app/build.gradle
android {
defaultConfig {
applicationId "com.yourcompany.yourapp"
minSdkVersion 22
targetSdkVersion 34
versionCode 1
versionName "1.0.0"
// 64-bit support
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
buildTypes {
release {
minifyEnabled true
shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
bundle {
language {
enableSplit = true
}
density {
enableSplit = true
}
abi {
enableSplit = true
}
}
}
App Icons
iOS App Icons
Required sizes (place in Assets.xcassets):
| Size | Scale | Usage |
|---|---|---|
| 20pt | 2x, 3x | Notification |
| 29pt | 2x, 3x | Settings |
| 40pt | 2x, 3x | Spotlight |
| 60pt | 2x, 3x | App Icon |
| 76pt | 1x, 2x | iPad |
| 83.5pt | 2x | iPad Pro |
| 1024pt | 1x | App Store |
Android App Icons
Required sizes (place in res/mipmap-*):
| Density | Size | Folder |
|---|---|---|
| mdpi | 48x48 | mipmap-mdpi |
| hdpi | 72x72 | mipmap-hdpi |
| xhdpi | 96x96 | mipmap-xhdpi |
| xxhdpi | 144x144 | mipmap-xxhdpi |
| xxxhdpi | 192x192 | mipmap-xxxhdpi |
Also needed:
- •Adaptive icon (foreground + background layers)
- •Play Store icon: 512x512
Generate Icons
bash
# Use capacitor-assets bun add -D @capacitor/assets bunx capacitor-assets generate --iconBackgroundColor '#ffffff'
Screenshots
iOS Screenshot Sizes
| Device | Size | Required |
|---|---|---|
| iPhone 6.7" | 1290x2796 | Yes |
| iPhone 6.5" | 1284x2778 | Yes |
| iPhone 5.5" | 1242x2208 | Yes |
| iPad Pro 12.9" | 2048x2732 | If supporting iPad |
| iPad Pro 11" | 1668x2388 | If supporting iPad |
Android Screenshot Sizes
| Type | Size | Required |
|---|---|---|
| Phone | 1080x1920 to 1080x2400 | Yes (2-8) |
| 7" Tablet | 1200x1920 | If supporting |
| 10" Tablet | 1600x2560 | If supporting |
Feature Graphic (Android)
- •Size: 1024x500
- •Required for Play Store listing
Generating Screenshots
typescript
// Use Playwright for automated screenshots
import { test } from '@playwright/test';
const devices = [
{ name: 'iPhone 14 Pro Max', viewport: { width: 430, height: 932 } },
{ name: 'iPhone 14', viewport: { width: 390, height: 844 } },
{ name: 'Pixel 7', viewport: { width: 412, height: 915 } },
];
test('generate screenshots', async ({ page }) => {
for (const device of devices) {
await page.setViewportSize(device.viewport);
// Screenshot 1: Home
await page.goto('/');
await page.screenshot({
path: `screenshots/${device.name}-home.png`,
fullPage: false,
});
// Screenshot 2: Feature
await page.goto('/feature');
await page.screenshot({
path: `screenshots/${device.name}-feature.png`,
});
}
});
App Store Connect Submission
1. Create App
- •Go to https://appstoreconnect.apple.com
- •My Apps > + > New App
- •Fill in:
- •Platform: iOS
- •Name: Your App Name
- •Primary Language
- •Bundle ID
- •SKU (unique identifier)
2. App Information
- •Category (primary and secondary)
- •Content Rights
- •Age Rating (complete questionnaire)
3. Pricing and Availability
- •Price (Free or paid tier)
- •Availability (countries)
4. App Privacy
- •Privacy Policy URL (required)
- •Data collection types:
- •Contact Info
- •Health & Fitness
- •Financial Info
- •Location
- •Identifiers
- •Usage Data
- •etc.
5. Version Information
- •Screenshots (all sizes)
- •Promotional Text (170 chars)
- •Description (4000 chars)
- •Keywords (100 chars, comma-separated)
- •Support URL
- •Marketing URL (optional)
- •What's New (for updates)
6. Build Upload
bash
# Using Xcode # Product > Archive > Distribute App > App Store Connect # Using Fastlane fastlane ios release # Using xcrun xcrun altool --upload-app --type ios --file App.ipa \ --apiKey KEY_ID --apiIssuer ISSUER_ID
7. Submit for Review
- •Answer export compliance questions
- •Add notes for reviewer (if needed)
- •Submit
Google Play Console Submission
1. Create App
- •Go to https://play.google.com/console
- •All apps > Create app
- •Fill in:
- •App name
- •Default language
- •App or game
- •Free or paid
2. Store Listing
- •Short description (80 chars)
- •Full description (4000 chars)
- •Screenshots (2-8 per device type)
- •Feature graphic (1024x500)
- •App icon (512x512)
- •Video URL (optional, YouTube)
3. Content Rating
Complete the questionnaire for IARC rating
4. Target Audience
- •Target age group
- •Ads declaration
5. Data Safety
- •Data collection
- •Data sharing
- •Security practices
- •Data deletion request handling
6. App Content
- •Ads (yes/no)
- •App category
- •Contact details
- •Privacy policy
7. Release
bash
# Build AAB (required for new apps) cd android && ./gradlew bundleRelease # Upload via Play Console or API # Production > Create new release > Upload AAB
Release Tracks
| Track | Purpose |
|---|---|
| Internal testing | Up to 100 testers, instant |
| Closed testing | Invite-only, review |
| Open testing | Public beta |
| Production | Full release |
Common Rejection Reasons
iOS Rejections
| Reason | Solution |
|---|---|
| Crashes | Test on real devices, fix bugs |
| Broken links | Verify all URLs work |
| Incomplete metadata | Fill all required fields |
| Missing privacy info | Complete App Privacy section |
| Login issues | Provide demo account |
| Guideline 4.2 (Minimum Functionality) | Add meaningful features |
| Guideline 5.1.1 (Data Collection) | Justify data usage |
Android Rejections
| Reason | Solution |
|---|---|
| Crashes/ANRs | Fix stability issues |
| Policy violation | Review Play policies |
| Deceptive behavior | Be transparent about features |
| Sensitive permissions | Justify in-app |
| Target SDK too low | Update to API 34+ |
Updates and Versioning
Version Incrementing
bash
# Increment patch (1.0.0 -> 1.0.1) bun version patch # Increment minor (1.0.0 -> 1.1.0) bun version minor # Increment major (1.0.0 -> 2.0.0) bun version major
Phased Rollout
iOS:
- •Enable phased release in App Store Connect
- •7-day gradual rollout (1%, 2%, 5%, 10%, 20%, 50%, 100%)
Android:
- •Set rollout percentage in release
- •Monitor crash rate before increasing
Resources
- •App Store Review Guidelines: https://developer.apple.com/app-store/review/guidelines
- •Google Play Policy Center: https://play.google.com/about/developer-content-policy
- •App Store Connect: https://appstoreconnect.apple.com
- •Google Play Console: https://play.google.com/console
- •Capacitor Assets: https://github.com/ionic-team/capacitor-assets