โ† All Articles

Shipping RummyScoreKeeper to the Apple App Store taught me more about iOS code signing in one week than I'd learned in years of backend engineering. The combination of provisioning profiles, distribution certificates, entitlements, and App Store Connect can feel deliberately hostile to anyone who isn't already initiated. This guide is the article I wish I'd had โ€” a complete walkthrough from zero to App Store submission using Fastlane.

What You'll Need Before Starting

Step 1: Generate Your Certificate Signing Request (CSR)

A CSR proves to Apple that you own the private key associated with your certificate. Generate it on your Mac:

# Open Keychain Access โ†’ Certificate Assistant โ†’ Request a Certificate From a Certificate Authority
# Fill in your email, select "Saved to disk", and save as CertificateSigningRequest.certSigningRequest

# Alternatively, via command line:
openssl genrsa -out distribution.key 2048
openssl req -new -key distribution.key -out distribution.csr \
  -subj "/emailAddress=your@email.com/CN=Tarun Adari/C=US"
Important

Keep your private key (distribution.key) secure. If you lose it, you'll need to revoke and regenerate your certificate. Store it in a secure location โ€” I use an encrypted disk image.

Step 2: Create Your Distribution Certificate

  1. Go to developer.apple.com โ†’ Certificates, IDs & Profiles โ†’ Certificates
  2. Click the + button, select Apple Distribution
  3. Upload your CSR file
  4. Download the resulting .cer file and double-click to install it in Keychain

You now have a Distribution certificate in your Keychain, linked to the private key you generated. Verify: open Keychain Access, find "Apple Distribution: Your Name" โ€” it should show a disclosure triangle with the private key beneath it. If there's no private key, the certificate is useless on this machine.

Step 3: Create an App ID and Provisioning Profile

An App ID uniquely identifies your app (e.g., com.tarunadari.rummyscorekeeper). A Provisioning Profile ties together your App ID, your distribution certificate, and your developer account into a signed bundle that Apple accepts.

# In developer.apple.com:
# 1. Identifiers โ†’ Register App ID โ†’ set bundle ID to match your React Native project
# 2. Profiles โ†’ New Profile โ†’ App Store โ†’ select your App ID โ†’ select your certificate
# 3. Download the .mobileprovision file

Step 4: Install and Configure Fastlane

# Install Fastlane
gem install fastlane

# From your project root
cd ios && fastlane init

Fastlane will ask a few questions and create a fastlane/ directory with an Appfile and Fastfile. Configure the Appfile first:

# fastlane/Appfile
app_identifier("com.tarunadari.rummyscorekeeper")
apple_id("your-apple-id@email.com")
team_id("YOUR_TEAM_ID") # Found in developer.apple.com โ†’ Membership

Step 5: Write the Fastfile

This is where the magic happens. The Fastfile defines your distribution lane โ€” the exact sequence of steps to build and submit your app:

# fastlane/Fastfile
default_platform(:ios)

platform :ios do
  lane :release do
    # Ensure the version and build number are set
    increment_build_number(xcodeproj: "RummyScoreKeeper.xcodeproj")

    # Build the app with manual signing
    build_app(
      workspace: "RummyScoreKeeper.xcworkspace",
      scheme: "RummyScoreKeeper",
      configuration: "Release",
      export_method: "app-store",
      export_options: {
        provisioningProfiles: {
          "com.tarunadari.rummyscorekeeper" => "RummyScoreKeeper AppStore"
        }
      }
    )

    # Upload to App Store Connect
    upload_to_app_store(
      skip_metadata: true,
      skip_screenshots: true,
      submit_for_review: false # Set true when ready to submit
    )
  end
end

Common Gotchas

Key Takeaways