iOS¶
iOS checks: Info.plist, Podfile, SwiftLint, privacy/encryption compliance, SwiftPM dependency reproducibility, and the App Store build-SDK requirement.
24 checks.
ios-allows-arbitrary-loads¶
Severity: Medium
Disabling ATS allows insecure HTTP connections, exposing the app to man-in-the-middle attacks and data interception.
How to fix: Remove NSAllowsArbitraryLoads or set it to false. Add per-domain exceptions only for domains that truly require HTTP.
ios-ats-exception-weakness¶
Severity: Low
Category-wide arbitrary loads (web/media), per-domain insecure HTTP exceptions, and sub-1.2 TLS minimums each re-open man-in-the-middle exposure for part of the app's traffic — easy to miss because the obvious ATS flag stays false.
How to fix: Remove exceptions the app does not need; serve those domains over HTTPS with TLS 1.2+. Keep NSAllowsArbitraryLoadsInWebContent/ForMedia only if the app genuinely renders arbitrary third-party web/media content.
ios-background-mode-missing-usage¶
Severity: Medium
A background mode that needs a purpose string (location, bluetooth-central/peripheral) crashes at runtime when the API is used and is a documented App Store rejection reason if the key is missing.
How to fix: Add the matching *UsageDescription key (e.g. NSLocationWhenInUseUsageDescription, NSBluetoothAlwaysUsageDescription) to Info.plist with a clear justification — or remove the background mode if the app does not use it.
ios-bitcode-enabled¶
Severity: Low
Bitcode was removed from the App Store pipeline by Apple. Enabling it adds build overhead and can cause unexpected linker behavior without any benefit.
How to fix: Set ENABLE_BITCODE = NO in your Xcode project build settings or xcconfig files. This is the default in Xcode 14+.
ios-build-sdk-requirement¶
Severity: Info
Apple raises the required build SDK roughly yearly. A stale CI Xcode image silently blocks every App Store upload once the deadline passes.
How to fix: Pin your CI to Xcode …+ (e.g. the macOS runner image / xcode-select) and keep local Xcode current.
ios-capability-missing-usage¶
Severity: Medium
A capability that always needs a purpose string (HealthKit, HomeKit) crashes at runtime the moment its API is used without the string, and is a documented App Store rejection reason.
How to fix: Add the matching NS*UsageDescription key (e.g. NSHealthShareUsageDescription, NSHomeKitUsageDescription) to the app-target Info.plist with a clear justification — or disable the capability in the .entitlements file if it is unused.
ios-deployment-target-drift¶
Severity: Medium
When the Podfile/SPM floor and the Xcode deployment target diverge, pods/packages compile against a different minimum than the app links for — you get "building for iOS X but linked for iOS Y" warnings, and code guarded on the higher floor can crash on the lower one.
How to fix: Align the minimum iOS version across the Xcode project (IPHONEOS_DEPLOYMENT_TARGET), the Podfile (platform :ios) and any SwiftPM platforms declaration.
ios-extension-activation-truepredicate¶
Severity: Medium
TRUEPREDICATE makes the extension show up in the share sheet for content it cannot handle — poor UX and a common App Store review rejection. A specific NSExtensionActivationRule dict scopes it to the types the extension actually supports.
How to fix: Replace TRUEPREDICATE with an NSExtensionActivationRule dict declaring the supported types (e.g. NSExtensionActivationSupportsWebURLWithMaxCount, NSExtensionActivationSupportsImageWithMaxCount).
ios-hardcoded-paths¶
Severity: Medium
Hardcoded paths break builds on other developers' machines and CI environments, causing mysterious build failures.
How to fix: Replace absolute paths with relative paths or Xcode build setting variables like $(SRCROOT).
ios-info-plist-overview¶
Severity: Info
Understanding the Info.plist configuration helps identify app metadata and security settings.
How to fix: Review Info.plist settings to ensure they match your release requirements.
ios-low-deploy-target¶
Severity: Medium
Supporting iOS versions below … increases maintenance burden, limits modern API adoption (async/await, SwiftUI improvements), and covers a shrinking share of active devices.
How to fix: Raise the iOS deployment target to at least ….0 in both the Podfile and Xcode project settings.
ios-missing-encryption-declaration¶
Severity: Low
A missing export-compliance declaration blocks automated TestFlight/App Store delivery and forces a manual answer on each build, slowing releases.
How to fix: Add
ios-missing-privacy-manifest¶
Severity: High
Apple has required a privacy manifest for App Store submissions since May 2024; a missing manifest blocks release.
How to fix: Add a PrivacyInfo.xcprivacy to the app target declaring data collection and required-reason API usage.
ios-missing-shared-scheme¶
Severity: Low
Without a committed shared scheme, xcodebuild -scheme … and CI pipelines cannot reliably select what to build, and teammates get an empty scheme list on a fresh checkout.
How to fix: In Xcode → Product → Scheme → Manage Schemes, tick “Shared” for the app scheme and commit the generated xcshareddata/xcschemes/*.xcscheme.
ios-oversized-resource¶
Severity:
Large asset files increase the app bundle size, slow down downloads from the App Store, and consume more device storage.
How to fix: Compress the assets, use HEIC format for photos, or leverage asset catalogs with on-demand resources for large files.
ios-pbxproj-overview¶
Severity: Info
A large number of file references can indicate project bloat, stale references, or organizational issues.
How to fix: Periodically clean up stale file references and organize the project structure.
ios-podfile-overview¶
Severity: Info
Understanding dependency count and versioning practices helps assess maintenance burden and reproducibility.
How to fix: Review pod dependencies for unused or redundant entries.
ios-run-script-missing-inputs-outputs¶
Severity: Low
A tool like SwiftLint that runs on every incremental build adds seconds to each compile with no benefit when nothing changed. It is a silent build-speed tax — the build stays green, it just gets slower.
How to fix: Declare Input Files and Output Files for the build phase (e.g. an output like $(DERIVED_FILE_DIR)/swiftlint.txt) so Xcode skips it when inputs are unchanged.
ios-strip-swift-symbols-disabled¶
Severity: Low
Shipping Swift symbol metadata bloats the Release binary (roughly 10-30%) with no runtime benefit. It is a size-only regression, so nothing breaks and it goes unnoticed.
How to fix: Set STRIP_SWIFT_SYMBOLS = YES for the Release configuration (the Xcode default).
ios-swift-optimization-off-in-release¶
Severity: Medium
An unoptimized Release binary runs measurably slower and can be larger. This usually leaks in by duplicating a target or copy-pasting debug build settings, and never surfaces as a build failure.
How to fix: Set SWIFT_OPTIMIZATION_LEVEL = -O (speed) or -Osize (size) for the Release configuration.
ios-swiftlint-excessive-disabled¶
Severity: Low
Disabling too many lint rules defeats the purpose of having a linter and allows code quality issues to accumulate undetected.
How to fix: Run swiftlint rules to see rule descriptions and identify which disabled rules are still relevant. Use swiftlint --fix for auto-correctable rules, and prefer inline // swiftlint:disable:next rule_name over global disables for legitimate exceptions.
ios-unversioned-pods¶
Severity: Low
Pods without version constraints can silently update to incompatible versions, leading to build failures or runtime bugs.
How to fix: Add version constraints to all pods, e.g., pod 'Name', '~> 1.0'.
ios-weak-permission-description¶
Severity: High
iOS shows the purpose string at the permission prompt; an empty, placeholder, or vague justification confuses users and is a common App Store review rejection reason.
How to fix: Replace each flagged purpose string with a clear, specific sentence explaining exactly why the app needs the permission.
swiftpm-branch-revision-dependency¶
Severity: Medium
A branch dependency resolves to whatever the branch points at when each machine/CI resolves it — builds silently diverge and are hard to reproduce. It is the SwiftPM equivalent of an unversioned pod or a git: pubspec dependency.
How to fix: Pin each dependency to a released version (from: "x.y.z", .upToNextMajor(from:), or exact:). Use branch/revision only for short-lived local development.