Skip to main content

iOS Build System

This guide explains how the iOS build system is structured, including Xcode schemes, build configurations, provisioning profiles, and Fastlane lanes.


Architecture Overview


Xcode Schemes

A scheme defines what targets to build, what configuration to use, and what actions to perform. Each environment has its own scheme.

Available Schemes

SchemeConfigurationBundle IDPurpose
dev.pivot3Dev.debug / Dev.releasejobs.pivot.devDevelopment builds
dev2.pivot3Dev2.debug / Dev2.releasejobs.pivot.dev2Development 2 builds
qa.pivot3QA.debug / QA.releasejobs.pivot.qaQA/Staging builds
pivot3Debug / Releasecom.pivot3Production builds

Scheme Files Location

ios/pivot3.xcodeproj/xcshareddata/xcschemes/
├── dev.pivot3.xcscheme
├── dev2.pivot3.xcscheme
├── qa.pivot3.xcscheme
└── pivot3.xcscheme

Build Configurations

Each scheme uses specific build configurations that define compiler flags, bundle IDs, and signing settings.

Configuration Mapping

Configuration Details

ConfigurationUse CaseCode SigningOptimization
*.debugLocal developmentDevelopmentNone
*.releaseTestFlight / DistributionAdHoc or App StoreFull

Provisioning Profiles

Provisioning profiles link your app to a specific team, bundle ID, and set of devices.

Profile Types

TypePurposeUsed For
DevelopmentLocal device testingRunning on physical devices during development
AdHocTestFlight internalBeta testing via TestFlight
App StoreProduction releaseApp Store distribution

Profile Naming Convention

Fastlane Match creates profiles with this naming pattern:

match [Type] [Bundle ID]

Examples:
- match AdHoc jobs.pivot.dev
- match AdHoc jobs.pivot.dev2
- match AdHoc jobs.pivot.qa
- match AppStore com.pivot3

Profile Storage

All profiles are stored in the pivot-mob-cert Git repository:

pivot-mob-cert/
├── certs/
│ ├── distribution/ # AdHoc & App Store certificates
│ └── development/ # Development certificates
└── profiles/
├── adhoc/
│ ├── AdHoc_jobs.pivot.dev.mobileprovision
│ ├── AdHoc_jobs.pivot.dev2.mobileprovision
│ └── AdHoc_jobs.pivot.qa.mobileprovision
└── appstore/
└── AppStore_com.pivot3.mobileprovision

Fastlane Configuration

Fastlane automates the build and deployment process.

Lane Structure

Lane Definitions

Each environment has its own lane in fastlane/Fastfile:

# Development lane
lane :dev do
app_store_connect_api_key(...)
latest_testflight_build_number(app_identifier: "jobs.pivot.dev")
increment_build_number(...)
match(type: "adhoc", app_identifier: "jobs.pivot.dev")
copy_files(source: "...development.plist", destination: "...")
build_app(scheme: "dev.pivot3", configuration: "Dev.release")
pilot(app_identifier: "jobs.pivot.dev")
end

# Development 2 lane
lane :dev2 do
# Same structure, different identifiers
app_store_connect_api_key(...)
match(type: "adhoc", app_identifier: "jobs.pivot.dev2")
build_app(scheme: "dev2.pivot3", configuration: "Dev2.release")
pilot(app_identifier: "jobs.pivot.dev2")
end

Build Settings in Xcode

Bundle ID Configuration

Bundle IDs are configured per-configuration in project.pbxproj:

Build Settings > Signing & Capabilities > Bundle Identifier

Dev.debug: jobs.pivot.dev
Dev.release: jobs.pivot.dev
Dev2.debug: jobs.pivot.dev2
Dev2.release: jobs.pivot.dev2
QA.debug: jobs.pivot.qa
QA.release: jobs.pivot.qa
Debug: com.pivot3
Release: com.pivot3

Provisioning Profile Configuration

Build Settings > Signing & Capabilities > Provisioning Profile

Dev.release: match AdHoc jobs.pivot.dev
Dev2.release: match AdHoc jobs.pivot.dev2
QA.release: match AdHoc jobs.pivot.qa
Release: match AppStore com.pivot3

GitHub Actions Workflow

Each branch triggers a specific workflow.

Workflow Structure

# .github/workflows/ios-dev2-build.yml
name: iOS Dev2 Build

on:
push:
branches: [development2]

jobs:
build:
uses: ./.github/workflows/ios-build.yml
with:
environment: "Dev2"
fastlane_lane: "dev2"
secrets: inherit

Reusable Workflow

All iOS builds use a shared workflow (.github/workflows/ios-build.yml) that:

  1. Checks out the code
  2. Sets up Ruby and Node.js
  3. Installs dependencies
  4. Configures SSH for certificate access
  5. Runs the specified Fastlane lane

Troubleshooting

Common Issues

"No matching provisioning profile"

Cause: Profile not synced or doesn't include required capabilities.

Solution:

bundle exec fastlane match adhoc --app_identifier jobs.pivot.dev2 --force
warning

Only use --force when you need to regenerate. This invalidates existing profiles.

"Code signing is required"

Cause: Wrong build configuration selected.

Solution: Ensure you're using the release configuration for distribution builds:

build_app(
scheme: "dev2.pivot3",
configuration: "Dev2.release" # Not Dev2.debug
)

"Missing capability in provisioning profile"

Cause: App capability (like Sign in with Apple) not enabled in the profile.

Solution:

  1. Enable capability in Apple Developer Portal
  2. Regenerate profile: fastlane match adhoc --force

Next Steps