Xcode Doctor: Static Analysis Tooling for iOS Configuration Errors
Xcode Doctor is a native macOS app that runs 9 static configuration checks on an iOS project in under 2 seconds. It identifies bundle ID inconsistencies, entitlement mismatches, missing required Info.plist keys, and other configuration errors that cause App Store rejections — before they reach Apple Review. This case study covers the design premise, architecture, and the nine checks it runs.
The Configuration Problem
iOS App Store rejection cycles are expensive. Apple's review process takes 24–72 hours. A rejection for a configuration issue — a bundle ID mismatch, a missing entitlement, an incorrect associated domain format — adds that wait time to every fix-and-resubmit cycle.
The time cost is not just the review wait. The developer who submitted the build needs to context-switch back, diagnose the rejection, fix it, rebuild, resubmit, and wait again. Each cycle in a T&M engagement is billable. In a fixed-scope sprint, each cycle compresses the timeline.
Most configuration errors that cause rejections are detectable without submitting to Apple. They are static properties of the project files — bundle IDs, entitlements, Info.plist keys — that can be read and validated before the build is even run.
Xcode Doctor was built to run those checks in under 2 seconds.
The Design Premise
Three design constraints shaped everything:
Read-only analysis. Xcode Doctor never writes to project files. It only reads. This means it cannot introduce errors and can be run on any project without risk.
No data to server. No project data — file paths, bundle IDs, team IDs, configuration values — leaves the machine. The analysis is entirely local. This is not a privacy policy claim; it is an architectural fact. There is no network stack in the analysis layer.
Fast enough to run before every build. Under 2 seconds for all 9 checks on a typical iOS project. This is the threshold that makes the tool worth opening habitually. A tool that takes 30 seconds will be run occasionally. A tool that takes 2 seconds becomes part of the pre-build routine.
Architecture
Parsing the Project Configuration
iOS project configuration lives in three file types:
Info.plist— app metadata, required keys, usage description strings.entitlements— capability declarations (HealthKit, CloudKit, Associated Domains, etc.)project.pbxprojinside.xcodeproj— build settings, target configuration, scheme definitions
Foundation's PropertyListSerialization handles Info.plist and .entitlements:
func parsePlist(at url: URL) throws -> [String: Any] {
let data = try Data(contentsOf: url)
let result = try PropertyListSerialization.propertyList(
from: data,
options: [],
format: nil
)
guard let dict = result as? [String: Any] else {
throw ParseError.unexpectedFormat
}
return dict
}
.xcodeproj/project.pbxproj is an Apple-format property list with a custom structure. Xcode Doctor parses it with a custom XML parser that extracts build settings, target names, and bundle identifier assignments without depending on xcodebuild or any external tooling.
No External Dependencies
Xcode Doctor has zero external Swift package dependencies. The analysis layer uses:
Foundationfor file I/O and property list parsingCombinefor result aggregation and UI bindingSwiftUIfor the interface
The absence of dependencies is intentional: no dependency management, no version conflicts, no supply chain risk. The app is entirely Apple framework code.
The Nine Checks
1. Bundle ID Consistency
Verifies that bundle identifiers are consistent across all targets and match the provisioning profile bundle ID patterns. A common failure mode: the main app target has com.company.app but the widget extension has com.company.App (capitalisation) — which causes provisioning failures at archive time.
2. Entitlements File Validity
Verifies that all entitlement keys are valid for the declared app capabilities, that the entitlements file is well-formed, and that no declared entitlement is missing its corresponding capability in the App Store Connect configuration.
3. Background Mode Declarations
Verifies that all UIBackgroundModes values declared in Info.plist are valid strings and match the entitlements declared for background execution. An app that declares background-processing in Info.plist but not in entitlements will pass local build but fail App Store review.
4. Associated Domains Format
Associated domains for Universal Links must follow the format applinks:yourdomain.com with no protocol prefix, no paths, and no trailing slashes. Malformed associated domain entries are a common rejection cause.
// Correct
applinks:yourapp.com
// Incorrect (causes rejection)
applinks:https://yourapp.com
applinks:yourapp.com/app
5. Required Info.plist Keys
Verifies that all keys required for the declared capabilities are present. Common missing keys: NSCameraUsageDescription when camera entitlement is declared, NSHealthShareUsageDescription when HealthKit is used, NSContactsUsageDescription when ContactsUI is imported.
6. Swift Package Dependencies
Checks the Swift package dependency graph for: unresolved package references, packages with no activity in 12+ months (potential maintenance risk), and packages that have known replacements in native iOS APIs.
7. Build Settings Consistency
Verifies that critical build settings are consistent across Debug and Release configurations: SWIFT_VERSION, IPHONEOS_DEPLOYMENT_TARGET, and ENABLE_BITCODE (deprecated, presence indicates outdated project configuration).
8. Provisioning Profile Alignment
Verifies that the declared bundle ID, team ID, and capability set match the expectations for the attached provisioning profile. This check operates on the project configuration — it does not require a downloaded provisioning profile to be present.
9. Required Capabilities Declarations
Verifies that all capabilities accessed in code (HealthKit, Core NFC, ARKit, etc.) are declared in the app's UIRequiredDeviceCapabilities where appropriate, and that capabilities that require App Store Connect configuration are flagged if they are missing from the declared entitlement set.
Results
Analysis speed: under 2 seconds for a typical iOS project with 3–5 targets
False positive rate: near-zero — checks are designed around documented Apple requirements, not heuristics
Rejection cycles prevented: based on developer feedback, the most common prevented rejections are associated domain format errors, missing usage description keys, and bundle ID capitalisation mismatches
No data egress: verified by network inspection — zero outbound connections during analysis
App Store first-submission approval: Xcode Doctor itself passed App Store review on first submission
Explore Xcode Doctor
If you are shipping iOS apps and losing time to App Store rejection cycles for configuration errors, Xcode Doctor runs the checks before Apple does.