app-store-deployment

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

App Store Deployment

应用商店部署

Overview

概述

Publish mobile applications to official app stores with proper code signing, versioning, testing, and submission procedures.
通过规范的代码签名、版本控制、测试及提交流程,将移动应用发布至官方应用商店。

When to Use

适用场景

  • Publishing apps to App Store and Google Play
  • Managing app versions and releases
  • Configuring signing certificates and provisioning profiles
  • Automating build and deployment processes
  • Managing app updates and rollouts
  • 将应用发布至App Store和Google Play
  • 管理应用版本与发布
  • 配置签名证书与描述文件
  • 自动化构建与部署流程
  • 管理应用更新与推送

Instructions

操作指南

1. iOS Deployment Setup

1. iOS部署配置

bash
undefined
bash
undefined

Create development and distribution signing certificates

Create development and distribution signing certificates

Step 1: Generate Certificate Signing Request (CSR) in Keychain Access

Step 1: Generate Certificate Signing Request (CSR) in Keychain Access

Step 2: Create App ID in Apple Developer Portal

Step 2: Create App ID in Apple Developer Portal

Step 3: Create provisioning profiles (Development, Distribution)

Step 3: Create provisioning profiles (Development, Distribution)

Xcode configuration for signing

Xcode configuration for signing

Set Team ID, Bundle Identifier, and select provisioning profiles

Set Team ID, Bundle Identifier, and select provisioning profiles

Build Settings:

Build Settings:

- Code Sign Identity: "iPhone Distribution"

- Code Sign Identity: "iPhone Distribution"

- Provisioning Profile: Select appropriate profile

- Provisioning Profile: Select appropriate profile

- Code Sign Style: Automatic (recommended)

- Code Sign Style: Automatic (recommended)

Info.plist settings

Info.plist settings

<?xml version="1.0" encoding="UTF-8"?> <plist version="1.0"> <dict> <key>CFBundleShortVersionString</key> <string>1.0.0</string> <key>CFBundleVersion</key> <string>1</string> <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <false/> </dict> <key>NSUserTrackingUsageDescription</key> <string>We use tracking for analytics</string> </dict> </plist>
<?xml version="1.0" encoding="UTF-8"?> <plist version="1.0"> <dict> <key>CFBundleShortVersionString</key> <string>1.0.0</string> <key>CFBundleVersion</key> <string>1</string> <key>NSAppTransportSecurity</key> <dict> <key>NSAllowsArbitraryLoads</key> <false/> </dict> <key>NSUserTrackingUsageDescription</key> <string>We use tracking for analytics</string> </dict> </plist>

Build for App Store submission

Build for App Store submission

xcodebuild -workspace MyApp.xcworkspace
-scheme MyApp
-configuration Release
-archivePath ~/Desktop/MyApp.xcarchive
archive
xcodebuild -workspace MyApp.xcworkspace
-scheme MyApp
-configuration Release
-archivePath ~/Desktop/MyApp.xcarchive
archive

Export for distribution

Export for distribution

xcodebuild -exportArchive
-archivePath ~/Desktop/MyApp.xcarchive
-exportOptionsPlist ExportOptions.plist
-exportPath ~/Desktop/MyApp
xcodebuild -exportArchive
-archivePath ~/Desktop/MyApp.xcarchive
-exportOptionsPlist ExportOptions.plist
-exportPath ~/Desktop/MyApp

ExportOptions.plist

ExportOptions.plist

<?xml version="1.0" encoding="UTF-8"?> <plist version="1.0"> <dict> <key>teamID</key> <string>YOUR_TEAM_ID</string> <key>signingStyle</key> <string>automatic</string> <key>method</key> <string>app-store</string> </dict> </plist>
<?xml version="1.0" encoding="UTF-8"?> <plist version="1.0"> <dict> <key>teamID</key> <string>YOUR_TEAM_ID</string> <key>signingStyle</key> <string>automatic</string> <key>method</key> <string>app-store</string> </dict> </plist>

Upload to App Store

Upload to App Store

xcrun altool --upload-app --file MyApp.ipa
--type ios
-u your-apple-id@example.com
-p your-app-specific-password
undefined
xcrun altool --upload-app --file MyApp.ipa
--type ios
-u your-apple-id@example.com
-p your-app-specific-password
undefined

2. Android Deployment Setup

2. Android部署配置

gradle
// build.gradle configuration
android {
  compileSdkVersion 33

  defaultConfig {
    applicationId "com.example.myapp"
    minSdkVersion 21
    targetSdkVersion 33
    versionCode 1
    versionName "1.0.0"
  }

  signingConfigs {
    release {
      storeFile file("keystore.jks")
      storePassword System.getenv("KEYSTORE_PASSWORD")
      keyAlias System.getenv("KEY_ALIAS")
      keyPassword System.getenv("KEY_PASSWORD")
    }
  }

  buildTypes {
    release {
      signingConfig signingConfigs.release
      minifyEnabled true
      shrinkResources true
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }
}

dependencies {
  implementation 'com.google.android.play:core:1.10.3'
}
bash
undefined
gradle
// build.gradle configuration
android {
  compileSdkVersion 33

  defaultConfig {
    applicationId "com.example.myapp"
    minSdkVersion 21
    targetSdkVersion 33
    versionCode 1
    versionName "1.0.0"
  }

  signingConfigs {
    release {
      storeFile file("keystore.jks")
      storePassword System.getenv("KEYSTORE_PASSWORD")
      keyAlias System.getenv("KEY_ALIAS")
      keyPassword System.getenv("KEY_PASSWORD")
    }
  }

  buildTypes {
    release {
      signingConfig signingConfigs.release
      minifyEnabled true
      shrinkResources true
      proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
    }
  }
}

dependencies {
  implementation 'com.google.android.play:core:1.10.3'
}
bash
undefined

Create keystore for app signing

Create keystore for app signing

keytool -genkey -v
-keystore ~/my-release-key.jks
-keyalg RSA
-keysize 2048
-validity 10950
-alias my-key-alias
keytool -genkey -v
-keystore ~/my-release-key.jks
-keyalg RSA
-keysize 2048
-validity 10950
-alias my-key-alias

Build App Bundle

Build App Bundle

./gradlew bundleRelease
./gradlew bundleRelease

Build APK for testing

Build APK for testing

./gradlew assembleRelease
./gradlew assembleRelease

Verify APK signature

Verify APK signature

jarsigner -verify -verbose -certs app/build/outputs/apk/release/app-release.apk
undefined
jarsigner -verify -verbose -certs app/build/outputs/apk/release/app-release.apk
undefined

3. Version Management

3. 版本管理

bash
undefined
bash
undefined

Version tracking

Version tracking

package.json

package.json

{ "name": "myapp", "version": "1.0.0", "build": { "ios": { "buildNumber": "1" }, "android": { "versionCode": 1 } } }
{ "name": "myapp", "version": "1.0.0", "build": { "ios": { "buildNumber": "1" }, "android": { "versionCode": 1 } } }

Increment version script

Increment version script

#!/bin/bash CURRENT=$(jq -r '.version' package.json) IFS='.' read -ra VER <<< "$CURRENT"
MAJOR=${VER[0]} MINOR=${VER[1]} PATCH=${VER[2]}
PATCH=$((PATCH + 1)) NEW_VERSION="$MAJOR.$MINOR.$PATCH"
jq ".version = "$NEW_VERSION"" package.json > package.json.tmp mv package.json.tmp package.json
echo "Version updated to $NEW_VERSION"
undefined
#!/bin/bash CURRENT=$(jq -r '.version' package.json) IFS='.' read -ra VER <<< "$CURRENT"
MAJOR=${VER[0]} MINOR=${VER[1]} PATCH=${VER[2]}
PATCH=$((PATCH + 1)) NEW_VERSION="$MAJOR.$MINOR.$PATCH"
jq ".version = "$NEW_VERSION"" package.json > package.json.tmp mv package.json.tmp package.json
echo "Version updated to $NEW_VERSION"
undefined

4. Automated CI/CD with GitHub Actions

4. 基于GitHub Actions的自动化CI/CD

yaml
name: Deploy to App Stores

on:
  push:
    tags:
      - 'v*'

jobs:
  build-ios:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm install

      - name: Build iOS App
        run: |
          cd ios
          pod install
          xcodebuild -workspace MyApp.xcworkspace \
            -scheme MyApp \
            -configuration Release \
            -archivePath ~/Desktop/MyApp.xcarchive \
            archive

      - name: Upload to App Store
        env:
          APPLE_ID: ${{ secrets.APPLE_ID }}
          APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
        run: |
          xcrun altool --upload-app \
            --file MyApp.ipa \
            --type ios \
            -u $APPLE_ID \
            -p $APPLE_PASSWORD

  build-android:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Java
        uses: actions/setup-java@v3
        with:
          java-version: '11'

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm install

      - name: Build Android App
        env:
          KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
          KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
          KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
        run: |
          cd android
          ./gradlew bundleRelease

      - name: Upload to Google Play
        uses: r0adkll/upload-google-play@v1
        with:
          serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT }}
          packageName: com.example.myapp
          releaseFiles: android/app/build/outputs/bundle/release/app.aab
          track: internal
          status: completed

  create-release:
    runs-on: ubuntu-latest
    needs: [build-ios, build-android]
    steps:
      - uses: actions/checkout@v3

      - name: Create GitHub Release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          body: Release notes here
          draft: false
          prerelease: false
yaml
name: Deploy to App Stores

on:
  push:
    tags:
      - 'v*'

jobs:
  build-ios:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm install

      - name: Build iOS App
        run: |
          cd ios
          pod install
          xcodebuild -workspace MyApp.xcworkspace \
            -scheme MyApp \
            -configuration Release \
            -archivePath ~/Desktop/MyApp.xcarchive \
            archive

      - name: Upload to App Store
        env:
          APPLE_ID: ${{ secrets.APPLE_ID }}
          APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
        run: |
          xcrun altool --upload-app \
            --file MyApp.ipa \
            --type ios \
            -u $APPLE_ID \
            -p $APPLE_PASSWORD

  build-android:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Setup Java
        uses: actions/setup-java@v3
        with:
          java-version: '11'

      - name: Setup Node
        uses: actions/setup-node@v3
        with:
          node-version: '18'

      - name: Install dependencies
        run: npm install

      - name: Build Android App
        env:
          KEYSTORE_PASSWORD: ${{ secrets.KEYSTORE_PASSWORD }}
          KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
          KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
        run: |
          cd android
          ./gradlew bundleRelease

      - name: Upload to Google Play
        uses: r0adkll/upload-google-play@v1
        with:
          serviceAccountJsonPlainText: ${{ secrets.PLAY_STORE_SERVICE_ACCOUNT }}
          packageName: com.example.myapp
          releaseFiles: android/app/build/outputs/bundle/release/app.aab
          track: internal
          status: completed

  create-release:
    runs-on: ubuntu-latest
    needs: [build-ios, build-android]
    steps:
      - uses: actions/checkout@v3

      - name: Create GitHub Release
        uses: actions/create-release@v1
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        with:
          tag_name: ${{ github.ref }}
          release_name: Release ${{ github.ref }}
          body: Release notes here
          draft: false
          prerelease: false

5. Pre-Deployment Checklist

5. 部署前检查清单

markdown
undefined
markdown
undefined

iOS Checklist

iOS检查清单

  • Increment version (CFBundleShortVersionString)
  • Update build number (CFBundleVersion)
  • Run all tests (>80% coverage)
  • Test on minimum iOS version
  • Review crash logs
  • Check for deprecated APIs
  • Verify all permissions documented
  • Test offline functionality
  • Verify app icon (1024x1024)
  • Set privacy policy URL
  • Archive and verify build
  • Test on real devices
  • 升级版本号(CFBundleShortVersionString)
  • 更新构建号(CFBundleVersion)
  • 运行所有测试(覆盖率>80%)
  • 在最低iOS版本上测试
  • 查看崩溃日志
  • 检查已废弃的API
  • 验证所有权限已文档化
  • 测试离线功能
  • 验证应用图标(1024x1024)
  • 设置隐私政策URL
  • 归档并验证构建包
  • 在真实设备上测试

Android Checklist

Android检查清单

  • Increment versionCode and versionName
  • Run all tests (>80% coverage)
  • Test on API 21+ devices
  • Verify navigation
  • Check battery optimization
  • Enable app signing
  • Build release AAB
  • Verify ProGuard obfuscation
  • Test landscape/portrait
  • Upload screenshots
  • Add release notes
  • Test on multiple devices
undefined
  • 升级versionCode和versionName
  • 运行所有测试(覆盖率>80%)
  • 在API 21+设备上测试
  • 验证导航功能
  • 检查电池优化设置
  • 启用应用签名
  • 构建发布版AAB
  • 验证ProGuard混淆配置
  • 测试横屏/竖屏模式
  • 上传截图
  • 添加发布说明
  • 在多台设备上测试
undefined

Best Practices

最佳实践

✅ DO

✅ 建议

  • Use signed certificates and provisioning profiles
  • Automate builds with CI/CD
  • Test on real devices before submission
  • Keep version numbers consistent
  • Document deployment procedures
  • Use environment-specific configurations
  • Implement proper error tracking
  • Monitor app performance post-launch
  • Plan rollout strategy
  • Keep backup of signing materials
  • Test offline functionality
  • Maintain release notes
  • 使用签名证书与描述文件
  • 通过CI/CD自动化构建
  • 提交前在真实设备上测试
  • 保持版本号一致
  • 文档化部署流程
  • 使用环境专属配置
  • 实现完善的错误追踪
  • 发布后监控应用性能
  • 规划推送策略
  • 备份签名材料
  • 测试离线功能
  • 维护发布说明

❌ DON'T

❌ 禁忌

  • Commit signing materials to git
  • Skip device testing
  • Release untested code
  • Ignore store policies
  • Use hardcoded API keys
  • Skip security reviews
  • Deploy without monitoring
  • Ignore crash reports
  • Make large version jumps
  • Use invalid certificates
  • Deploy without backups
  • Release during holidays
  • 将签名材料提交至Git
  • 跳过设备测试
  • 发布未测试的代码
  • 忽略应用商店政策
  • 使用硬编码API密钥
  • 跳过安全审查
  • 无监控部署
  • 忽略崩溃报告
  • 大幅跳跃版本号
  • 使用无效证书
  • 无备份部署
  • 节假日期间发布