Skip to content
application · mobile · ios

Signed, sealed, shipped,iOS.

Apple's tightly integrated mobile platform demands strict code signing and provisioning before anything reaches a device. This guide walks the full KBVE pipeline — certificates and profiles, GitHub secrets, CI/CD on macOS runners, local build testing, and the shared Apple setup that UE5 iOS builds reuse.

One Apple setup, every project

Certificates, provisioning profiles, and the Team ID are shared infrastructure — complete the Apple Developer setup once and reuse the same credentials across React Native, UE5, and future frameworks.

  • Certificates — .p12 exports stored as base64 secrets.
  • Profiles — link cert, app ID, and device UDIDs.
  • CI/CD — temporary keychains on macOS runners.
$99/yearDeveloper Program
com.kbve.appBundle ID
xcodebuildBuild tool
macOSCI runners

Start here

Information

iOS development requires a macOS environment and enrollment in the Apple Developer Program ($99/year) to deploy applications to physical devices and distribute through the App Store. This guide covers code signing, provisioning profiles, CI/CD setup, and best practices for building iOS applications at KBVE.

Jump to code signing, GitHub secrets, the CI/CD workflow, troubleshooting, or UE5 iOS builds.

Our React Native iOS applications use Expo for streamlined development and deployment workflows, with custom native modules when needed for advanced features.

Certificates & profiles

Code Signing Setup

Apple’s code signing system ensures app integrity and prevents unauthorized modifications. All iOS apps must be signed before deployment to devices or the App Store.

  1. Apple Developer Account

    • Enroll at developer.apple.com
    • Cost: $99/year for individual or organization membership
    • Required for device testing and App Store distribution
  2. Development Environment

    • macOS with Xcode installed
    • Xcode Command Line Tools: xcode-select --install
    • CocoaPods: sudo gem install cocoapods
  3. Bundle Identifier

    • KBVE React Native App: com.kbve.app
    • Must match across Xcode project, provisioning profiles, and App Store Connect

iOS App Development Certificate

Used for testing on physical devices during development.

Terminal window
# Generate via Xcode (automatic)
# Or manually via Keychain Access → Certificate Assistant → Request from CA
# Export as .p12 (for CI/CD)
# Keychain Access → Right-click certificate → Export

Provisioning profiles link certificates, app IDs, and device UDIDs together.

TypeUse CaseDevice Registration
DevelopmentTesting on registered devicesRequired
Ad HocBeta testing outside TestFlightRequired (max 100 devices)
App StoreApp Store distributionNot required
Terminal window
# Export provisioning profile to base64
base64 -i profile.mobileprovision | pbcopy

Secure credentials

GitHub Secrets Configuration

Add these secrets to your repository for CI/CD workflows.

Secret NameDescriptionHow to Generate
APPLE_CERT_DATABase64-encoded .p12 certificatebase64 -i certificate.p12 | pbcopy
APPLE_CERT_PASSWORDPassword for .p12 fileSet when exporting certificate
PROVISIONING_PROFILE_DATABase64-encoded .mobileprovisionbase64 -i profile.mobileprovision | pbcopy

Automated builds

CI/CD Workflow

Our React Native iOS builds use GitHub Actions with macOS runners.

Located at .github/workflows/ci-react-native-ios.yml

For development and CI testing (no certificates required)

Terminal window
# Trigger via GitHub Actions
# task: build
# skip_signing: true

Produces unsigned simulator build (x86_64) for testing purposes.

Packaging the IPA

Xcode Build Configuration

The exportOptions.plist file controls how the IPA is packaged.

  • Directoryapps/kbve/kbve-react-native/
    • exportOptions.plist Configuration for App Store export
    • Directoryios/ Generated by Expo prebuild
      • Podfile CocoaPods dependencies
      • *.xcworkspace Xcode workspace

exportOptions.plist Template:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>method</key>
<string>app-store</string>
<key>teamID</key>
<string>YOUR_TEAM_ID</string>
<key>uploadBitcode</key>
<false/>
<key>compileBitcode</key>
<false/>
<key>uploadSymbols</key>
<true/>
<key>signingStyle</key>
<string>manual</string>
<key>provisioningProfiles</key>
<dict>
<key>com.kbve.app</key>
<string>YOUR_PROVISIONING_PROFILE_NAME</string>
</dict>
</dict>
</plist>

Actions internals

Workflow Implementation

- name: Import signing certificate
env:
APPLE_CERT_DATA: ${{ secrets.APPLE_CERT_DATA }}
APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }}
run: |
# Create temporary keychain
KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db
KEYCHAIN_PASSWORD=$(uuidgen)
security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
security set-keychain-settings -lut 21600 $KEYCHAIN_PATH
security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH
# Import certificate
echo "$APPLE_CERT_DATA" | base64 --decode > certificate.p12
security import certificate.p12 \
-P "$APPLE_CERT_PASSWORD" \
-A \
-t cert \
-f pkcs12 \
-k $KEYCHAIN_PATH
security list-keychain -d user -s $KEYCHAIN_PATH
- name: Install provisioning profile
env:
PROVISIONING_PROFILE_DATA: ${{ secrets.PROVISIONING_PROFILE_DATA }}
run: |
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
echo "$PROVISIONING_PROFILE_DATA" | base64 --decode > \
~/Library/MobileDevice/Provisioning\ Profiles/profile.mobileprovision
- name: Build signed app
run: |
xcodebuild \
-workspace *.xcworkspace \
-scheme "kbvereactnative" \
-configuration Release \
-sdk iphoneos \
-archivePath ./build/App.xcarchive \
archive
xcodebuild \
-exportArchive \
-archivePath ./build/App.xcarchive \
-exportPath ./build \
-exportOptionsPlist exportOptions.plist

Verify locally

Local Build Testing

Verify builds work locally before pushing to CI/CD.

Terminal window
# Navigate to React Native app
cd apps/kbve/kbve-react-native
# Generate iOS native project
npx expo prebuild --platform ios --clean
# Install CocoaPods dependencies
cd ios
pod install
# Build for simulator (unsigned)
xcodebuild \
-workspace *.xcworkspace \
-scheme kbvereactnative \
-configuration Release \
-sdk iphonesimulator \
build
# Build for device (requires signing)
xcodebuild \
-workspace *.xcworkspace \
-scheme kbvereactnative \
-configuration Release \
-sdk iphoneos \
-archivePath ./build/App.xcarchive \
archive

When builds break

Troubleshooting

Symptoms: errSecInternalComponent or certificate errors during build

Solutions:

  • Verify APPLE_CERT_DATA is valid base64
  • Check certificate password matches APPLE_CERT_PASSWORD
  • Ensure certificate hasn’t expired (check in Apple Developer portal)

Symptoms: No profiles for 'com.kbve.app' were found

Solutions:

  • Ensure Bundle ID matches: com.kbve.app
  • Profile must include the signing certificate
  • Check profile hasn’t expired
  • Verify Team ID in exportOptions.plist matches certificate

Symptoms: Code signing is required for product type 'Application'

Solutions:

  • Check Team ID in exportOptions.plist
  • Verify provisioning profile name is correct
  • Ensure certificate and profile are properly installed in keychain
  • Review Xcode build settings for code signing configuration

Symptoms: pod install fails or missing native modules

Solutions:

Terminal window
# Clear CocoaPods cache
cd ios
pod cache clean --all
rm -rf Pods Podfile.lock
# Reinstall
pod install --repo-update

Same Apple, bigger binary

Unreal Engine 5 iOS Builds

KBVE also builds iOS applications using Unreal Engine 5. The UE5 iOS pipeline shares the same Apple Developer infrastructure (certificates, provisioning profiles, Team ID) as React Native builds.

Key Differences from React Native:

  • Build System: UE5 uses UnrealBuildTool (UBT) instead of xcodebuild directly
  • Project Generation: Xcode project generated via GenerateProjectFiles.sh or UE5 Editor
  • Binary Size: UE5 apps significantly larger due to engine runtime
  • Shader Compilation: Metal shaders must be precompiled for iOS targets

The UE5 iOS CI/CD pipeline is currently under development. See Issue #12875 for tracking.

Planned Tasks:

  • Configure Xcode project for UE5 iOS builds
  • Adapt code signing for UnrealBuildTool
  • Create GitHub Actions workflow for iOS builds
  • Test build pipeline on macOS runner
  • Document UE5-specific iOS build process

Shared Infrastructure:

Both React Native and UE5 iOS builds use the same:

  • Apple Developer certificates (APPLE_CERT_DATA, APPLE_CERT_PASSWORD)
  • Provisioning profiles (PROVISIONING_PROFILE_DATA)
  • macOS GitHub Actions runners
  • Fastlane automation (optional)
Terminal window
# Generate Xcode project from .uproject
# (Run on macOS with UE5 installed)
/Path/To/UE_5.X/Engine/Build/BatchFiles/Mac/GenerateProjectFiles.sh \
-project="/Path/To/YourProject.uproject" \
-platforms=iOS
# Build via UnrealBuildTool
/Path/To/UE_5.X/Engine/Build/BatchFiles/RunUBT.sh \
YourProjectEditor iOS Development \
-project="/Path/To/YourProject.uproject"
# Package for distribution
/Path/To/UE_5.X/Engine/Build/BatchFiles/RunUAT.sh BuildCookRun \
-project="/Path/To/YourProject.uproject" \
-platform=iOS \
-clientconfig=Shipping \
-cook -stage -archive -package

Get shipping

Next Steps

  1. Enroll in Apple Developer Program

  2. Generate Certificates

    • Create iOS Distribution Certificate
    • Export as .p12 with strong password
  3. Create Provisioning Profile

    • Use Bundle ID: com.kbve.app
    • Select App Store distribution type
    • Download and export to base64
  4. Configure GitHub Secrets

    • Add APPLE_CERT_DATA, APPLE_CERT_PASSWORD, PROVISIONING_PROFILE_DATA
    • Update exportOptions.plist with Team ID and profile name
  5. Test Build Workflow

    • Run with skip_signing: true first (unsigned)
    • Then test with skip_signing: false (signed)
  6. Optional: Setup Fastlane

    • Automate TestFlight uploads
    • Manage certificates and profiles via match

Questions

Frequently asked

What do I need to develop and distribute iOS apps?

A macOS machine with Xcode, and enrollment in the Apple Developer Program at $99/year. Membership is required to test on physical devices and distribute through the App Store. You also need a signing certificate, a provisioning profile, and a unique bundle identifier such as com.kbve.app.

What is the difference between a certificate and a provisioning profile?

A signing certificate proves your identity to Apple and signs the app binary. A provisioning profile links that certificate, the app ID, and (for development/ad-hoc) allowed device UDIDs, authorizing where the app can run. App Store profiles do not need device registration.

How do I sign an iOS build in CI/CD?

Store the .p12 certificate and .mobileprovision profile as base64 GitHub secrets, then in the workflow create a temporary keychain, import the decoded certificate, install the profile, and build with xcodebuild archive plus exportArchive using an exportOptions.plist. Never commit certificates to the repo.

Can I build an unsigned iOS app for testing?

Yes. A simulator build for the iphonesimulator SDK does not require signing, so CI can produce an unsigned x86_64 build for testing. Signing is only required for device installs, TestFlight, and App Store submission using the iphoneos SDK.

Do Unreal Engine 5 iOS builds use the same Apple setup?

Yes. UE5 iOS builds reuse the same Apple Developer certificates, provisioning profiles, and Team ID as React Native builds. The difference is the build system — UE5 uses UnrealBuildTool and RunUAT instead of xcodebuild directly, and produces larger binaries with precompiled Metal shaders.