iOS Application Signing Setup (Certificates, Provisioning Profiles)
Apple's signing system is one of the most frequent time-wasters in iOS development. Xcode can manage signing automatically, but in CI/CD environments, team workflows, or with multiple entitlements, automatic management breaks unpredictably. Build fails with "No signing certificate found," and Xcode stays silent about the real cause.
What Breaks and Why
Problems usually arise in three situations.
Expired certificate in keychain. Apple Developer Certificate valid one year. When it expires, old Provisioning Profiles tied to it become invalid automatically. Xcode sometimes doesn't report expiration explicitly—just can't find needed signature. Check current status: Keychain Access → My Certificates → look for iPhone Distribution or Apple Distribution with correct date.
Bundle ID and Provisioning Profile mismatch. Profile created for specific App ID. Wildcard profile (com.example.*) convenient for quick dev, but doesn't support most entitlements: Push Notifications, Associated Domains, App Groups, HealthKit—all require explicit App ID. Project with Push enabled but wildcard profile—build passes, but entitlements don't apply, and APNS won't work.
CI/CD without keychain access. Fresh CI agent has neither certificates nor profiles. Standard approach—match (Fastlane): encrypted repository with certificates that match downloads and imports before build. Alternative—Xcode Cloud with automatic management, but it's not flexible for custom steps.
Complete Setup Process
Apple Developer Portal
- Create App ID (Identifiers → App IDs) with explicit Bundle ID and needed Capabilities
- Create Certificate Signing Request via Keychain Access: Certificate Assistant → Request a Certificate
- Upload CSR to Apple Developer Portal, download certificate, install in Keychain
- Create Provisioning Profile, binding App ID + Certificate + needed devices (Development) or without devices (Distribution)
Xcode Configuration
In Signing & Capabilities select Manual signing. Specify Team, Bundle Identifier, and select profile explicitly. For multiple targets (main app + Extension)—each target needs its own Provisioning Profile.
<!-- Example entitlements file for app with Push + App Groups -->
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" ...>
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>production</string>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.example.app</string>
</array>
</dict>
</plist>
Entitlements in .entitlements file must match exactly what's enabled in App ID on Portal. Mismatch → reject on archive with Provisioning profile doesn't support the ... entitlement.
Fastlane match for Teams
# Matchfile
git_url("https://github.com/your-org/ios-certificates")
storage_mode("git")
type("appstore") # or "development", "adhoc"
app_identifier(["com.example.app", "com.example.app.notification-extension"])
username("[email protected]")
fastlane match appstore --readonly # on CI, read-only
fastlane match development # on local machine, update
--readonly on CI is important: prevents accidental profile regeneration during build.
Multiple Extension Targets
Notification Service Extension, Share Extension, Widget—each needs separate App ID (e.g., com.example.app.widget) and separate Provisioning Profile. App Groups let them share data via UserDefaults(suiteName:) or common file container. App Group must be enabled in App ID of each target.
Common Mistakes
- Download Provisioning Profile manually and put in ~/Library/MobileDevice/Provisioning Profiles—works locally, breaks on CI and for other developers
- Forget to update profile after adding new device to Portal (for Development)
- One certificate for whole team instead of Certificate per developer—when one certificate is revoked, builds fail for everyone
Workflow
Audit current state: certificates in Keychain, profiles in Portal, entitlements in project.
Align App ID, Capabilities, and Provisioning Profiles.
Setup Fastlane match or Xcode Cloud for team work and CI/CD.
Test build on simulator and real device, archive, and verify via Altool or Transporter.
Timeline
One-off signing setup for one target—2–4 hours. Multiple Extensions, App Groups, CI/CD setup via Fastlane match—1–2 days.







