Detects apps that abuse iOS background execution modes — particularly silent audio used to keep the app alive, location background mode used for non-navigation purposes, and background task implementations that do excessive work — enforcing Guideline 2.5.4.
Install
npx skillscat add cruisediary/apple-app-review-skills/background-execution-audit Install via the SkillsCat registry.
Skill: Background Execution Audit
Purpose
Detects apps that abuse iOS background execution modes — particularly silent audio used to keep the app alive, location background mode used for non-navigation purposes, and background task implementations that do excessive work — enforcing Guideline 2.5.4 which requires background modes to be used only for their intended purpose.
Apple Guideline
- Primary: 2.5.4 — Performance: Multitasking and Background Modes
- Related: 5.1.5
- Reference:
references/guidelines/2-performance.md
Real-World Rejection Cases
Case: App declared the
audiobackground mode and played a silent audio session to prevent the system from suspending the app — rejected under 2.5.4
Source: Apple Developer Forums (multiple reports)
Root cause: Playing silent audio in the background solely to prevent app suspension is explicitly prohibited — it abuses the audio background mode, which is intended for apps that provide audible content to the user. UseBGTaskSchedulerfor background processing instead.Case: Fitness app declared
locationbackground mode to track user steps, but only needed step count data — Apple reviewer noted the app used CoreLocation for step counting instead of the appropriate CoreMotion/CMPedometer API
Source: Apple Developer Forums (Guideline 2.5.4 enforcement)
Root cause: Background location must be used only when the app's core functionality genuinely requires continuous location updates (navigation, geo-fencing). Using it as a workaround to run in the background for non-location tasks violates 2.5.4.Case: App declared
voipbackground mode to maintain a persistent socket connection for non-VoIP chat — rejected; VoIP mode is reserved for apps providing telephone-like calling features
Source: Apple Developer Forums
Root cause: Each background mode has a specific intended use case — declaring a background mode for a purpose other than its design is treated as abuse. UseBGProcessingTaskorBGAppRefreshTaskfor periodic background work.
Trigger
Invoke on any iOS/macOS project that declares background modes in Info.plist or uses BGTaskScheduler, CLLocationManager, or AVAudioSession.
Inputs
| Name | Type | Default | Description |
|---|---|---|---|
project_root |
path | cwd | iOS/macOS project root |
shared_context |
object | nil | Pre-collected context from appstore-full-audit Phase 1 |
Actions
Phase 1: Context Collection
Skip this phase if shared_context is provided.
Glob**/Info.plist— locate Info.plist for background mode declarations.Glob**/*.swift— collect all Swift source files.
Phase 2: Checks
Background audio mode with silent/zero-volume session
ReadInfo.plist — checkUIBackgroundModesforaudio.
Ifaudiois declared,GrepAVAudioSession|AVAudioPlayerin**/*.swift.
If audio session category is.ambientor.soloAmbientwith no audible content, OR if volume is set to 0 near background mode activation → 🔴 CRITICAL. Silent audio background mode abuse.Background location declared — justify core use
ReadInfo.plist — checkUIBackgroundModesforlocation.
Iflocationis present,GrepCMPedometer|CMMotionActivityManager|CoreMotionin**/*.swift.
If the app uses CoreMotion/pedometer APIs while also declaring background location → 🟠 HIGH. Step counting and activity tracking belong in CoreMotion, not CoreLocation — background location should not be used as a substitute.VoIP background mode without calling functionality
ReadInfo.plist — checkUIBackgroundModesforvoip.
Ifvoipis present,GrepCXProvider|CXCallController|CallKit|VoIPin**/*.swift.
Ifvoipbackground mode declared but no CallKit integration found → 🔴 CRITICAL. VoIP background mode is reserved for apps providing telephone-like calling via CallKit — using it for persistent socket connections violates 2.5.4.BGTaskScheduler not registered for declared modes
GreppatternBGTaskScheduler|BGProcessingTask|BGAppRefreshTaskin**/*.swift.
If background modesfetchorprocessingare declared butBGTaskScheduler.shared.registeris absent → 🟠 HIGH. Background fetch/processing tasks must be registered withBGTaskScheduler— unregistered tasks waste background time and will be deprecated.Location background mode with Always authorization
GreppatternrequestAlwaysAuthorizationin**/*.swift.
IfrequestAlwaysAuthorizationis called but background location mode is absent from Info.plist → 🟠 HIGH. Requesting Always authorization without declaring background location mode causes the OS to silently downgrade to WhenInUse.
Phase 3: Output
Collect all findings from Phase 2 and build the prioritised findings list below. Include file paths and line numbers. Omit tiers with no findings.
Output Format
## Background Execution Audit — Findings
### 🔴 CRITICAL — Guaranteed rejection
- [ ] TODO: Remove silent audio background mode — playing inaudible audio to prevent suspension violates 2.5.4; use BGTaskScheduler for background work — `AudioKeepAlive.swift:12` — Guideline 2.5.4
- [ ] TODO: Remove voip background mode or integrate CallKit — voip mode requires telephone-like calling functionality via CXProvider — `Info.plist` — Guideline 2.5.4
### 🟠 HIGH — Very likely rejection
- [ ] TODO: Replace CoreLocation-based step counting with CMPedometer — background location is not required for pedometry — `StepTracker.swift:34` — Guideline 2.5.4
- [ ] TODO: Register BGProcessingTask in BGTaskScheduler — background-processing mode declared but BGTaskScheduler not configured — `AppDelegate.swift` — Guideline 2.5.4
### 🟡 MEDIUM — Possible rejection
- [ ] TODO: Review all declared UIBackgroundModes against actual usage — remove any mode not actively used by a core feature
### 🟢 LOW — Best practice
- [ ] TODO: Add a comment next to each UIBackgroundMode entry explaining which feature requires it — helps reviewers and future maintainers understand the justificationTools Used
Glob, Grep, Read
Constraints
- Read-only. No file edits.
- No network calls.
- Skip Phase 1 if
shared_contextis provided by orchestrating agent. - Legitimate uses of background modes (music players for
audio, navigation apps forlocation, calling apps forvoip) are not flagged — context from Phase 2 checks determines whether usage matches intent.
Quick Commands
# Check declared background modes
!plutil -convert json -o - Info.plist 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print('Background modes:', d.get('UIBackgroundModes', 'none'))"
# Check for silent audio pattern
!grep -rn "AVAudioSession\|AVAudioPlayer" . --include="*.swift" -A5 | grep -i "ambient\|volume.*0\|setVolume(0"
# Check for BGTaskScheduler usage
!grep -rn "BGTaskScheduler\|BGProcessingTask\|BGAppRefreshTask" . --include="*.swift"
# Check for voip + CallKit
!grep -rn "CXProvider\|CXCallController\|CallKit" . --include="*.swift" | wc -lSwift Anti-Pattern Reference
examples/swift/BackgroundExecutionPatterns.swift
Detection Steps
Find target files
- Glob:
**/Info.plist,**/*.swift,**/*.m
- Glob:
Search for rejection patterns
- Read
Info.plist→ checkUIBackgroundModesarray values - Grep
AVAudioSession.*categoryPlayback\|AVAudioSession.*setCategory.*playback+mixWithOthers— silent audio abuse - Grep
kCLAuthorizationStatusAuthorizedAlways\|requestAlwaysAuthorization— always location - Grep
PKPushRegistry\|voipinInfo.plistUIBackgroundModes— VoIP background mode - Grep
CXProvider\|CXCallController— CallKit usage (required for VoIP)
- Read
Determine verdict
audioinUIBackgroundModes+mixWithOthersoption (silent audio trick) → 🔴 CRITICAL (Guideline 2.5.4)locationinUIBackgroundModes+ app is not navigation/fitness → 🔴 CRITICALvoipinUIBackgroundModes+ noCXProvider(CallKit) usage → 🔴 CRITICAL- Background modes match actual app functionality → 🟢 pass
Report
UIBackgroundModesvalues found in Info.plist- File path + line of silent audio / location / VoIP misuse
- Fix: Remove background modes that don't match core app features; implement CallKit for VoIP