axiom-background-processing

1
1
Source

Use when implementing BGTaskScheduler, debugging background tasks that never run, understanding why tasks terminate early, or testing background execution - systematic task lifecycle management with proper registration, expiration handling, and Swift 6 cancellation patterns

Install

mkdir -p .claude/skills/axiom-background-processing && curl -L -o skill.zip "https://mcp.directory/api/skills/download/5772" && unzip -o skill.zip -d .claude/skills/axiom-background-processing && rm skill.zip

Installs to .claude/skills/axiom-background-processing

About this skill

Background Processing

Overview

Background execution is a privilege, not a right. iOS actively limits background work to protect battery life and user experience. Core principle: Treat background tasks as discretionary jobs — you request a time window, the system decides when (or if) to run your code.

Key insight: Most "my task never runs" issues stem from registration mistakes or misunderstanding the 7 scheduling factors that govern execution. This skill provides systematic debugging, not guesswork.

Energy optimization: For reducing battery impact of background tasks, see axiom-energy skill. This skill focuses on task mechanics — making tasks run correctly and complete reliably.

Requirements: iOS 13+ (BGTaskScheduler), iOS 26+ (BGContinuedProcessingTask), Xcode 15+

Example Prompts

Real questions developers ask that this skill answers:

1. "My background task never runs. I register it, schedule it, but nothing happens."

→ The skill covers the registration checklist and debugging decision tree for "task never runs" issues

2. "How do I test background tasks? They don't seem to trigger in the simulator."

→ The skill covers LLDB debugging commands and simulator limitations

3. "My task gets terminated before it completes. How do I extend the time?"

→ The skill covers task types (BGAppRefresh 30s vs BGProcessing minutes), expiration handlers, and incremental progress saving

4. "Should I use BGAppRefreshTask or BGProcessingTask? What's the difference?"

→ The skill provides decision tree for choosing the correct task type based on work duration and system requirements

5. "How do I integrate Swift 6 concurrency with background task expiration?"

→ The skill covers withTaskCancellationHandler patterns for bridging BGTask expiration to structured concurrency

6. "My background task works in development but not in production."

→ The skill covers the 7 scheduling factors, throttling behavior, and production debugging


Red Flags — Task Won't Run or Terminates

If you see ANY of these, suspect registration or scheduling issues:

  • Task never runs: Handler never called despite successful submit()
  • Task terminates immediately: Handler called but work doesn't complete
  • Works in dev, not prod: Task runs with debugger but not in release builds
  • Console shows no launch: No "BackgroundTask" entries in unified logging
  • Identifier mismatch errors: Task identifier not matching Info.plist
  • "No handler registered": Handler not registered before first scheduling

Difference from energy issues

  • Energy issue: Task runs but drains battery (see axiom-energy skill)
  • This skill: Task doesn't run, or terminates before completing work

Mandatory First Steps

ALWAYS verify these before debugging code:

Step 1: Verify Info.plist Configuration (2 minutes)

<!-- Required in Info.plist -->
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
    <string>com.yourapp.refresh</string>
    <string>com.yourapp.processing</string>
</array>

<!-- For BGAppRefreshTask -->
<key>UIBackgroundModes</key>
<array>
    <string>fetch</string>
</array>

<!-- For BGProcessingTask (add to UIBackgroundModes) -->
<array>
    <string>fetch</string>
    <string>processing</string>
</array>

Common mistake: Identifier in code doesn't EXACTLY match Info.plist. Check for typos, case sensitivity.

Step 2: Verify Registration Timing (2 minutes)

Registration MUST happen before app finishes launching:

// ✅ CORRECT: Register in didFinishLaunchingWithOptions
func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    BGTaskScheduler.shared.register(
        forTaskWithIdentifier: "com.yourapp.refresh",
        using: nil
    ) { task in
        // Safe force cast: identifier guarantees BGAppRefreshTask type
        self.handleAppRefresh(task: task as! BGAppRefreshTask)
    }

    return true  // Register BEFORE returning
}

// ❌ WRONG: Registering after launch or on-demand
func someButtonTapped() {
    // TOO LATE - registration won't work
    BGTaskScheduler.shared.register(...)
}

Exception: BGContinuedProcessingTask (iOS 26+) uses dynamic registration when user initiates the action.

Step 3: Check Console Logs (5 minutes)

Filter Console.app for background task events:

subsystem:com.apple.backgroundtaskscheduler

Look for:

  • "Registered handler for task with identifier"
  • "Scheduling task with identifier"
  • "Starting task with identifier"
  • "Task completed with identifier"
  • Error messages about missing handlers or identifiers

Step 4: Verify App Not Swiped Away (1 minute)

Critical: If user force-quits app from App Switcher, NO background tasks will run.

Check in App Switcher: Is your app still visible? Swiping away = no background execution until user launches again.


Background Task Decision Tree

Need to run code in the background?
│
├─ User initiated the action explicitly (button tap)?
│  ├─ iOS 26+? → BGContinuedProcessingTask (Pattern 4)
│  └─ iOS 13-25? → beginBackgroundTask + save progress (Pattern 5)
│
├─ Keep content fresh throughout the day?
│  ├─ Runtime needed ≤ 30 seconds? → BGAppRefreshTask (Pattern 1)
│  └─ Need several minutes? → BGProcessingTask with constraints (Pattern 2)
│
├─ Deferrable maintenance work (DB cleanup, ML training)?
│  └─ BGProcessingTask with requiresExternalPower (Pattern 2)
│
├─ Large downloads/uploads?
│  └─ Background URLSession (Pattern 6)
│
├─ Triggered by server data changes?
│  └─ Silent push notification → fetch data → complete handler (Pattern 7)
│
└─ Short critical work when app backgrounds?
   └─ beginBackgroundTask (Pattern 5)

Task Type Comparison

TypeRuntimeWhen RunsUse Case
BGAppRefreshTask~30 secondsBased on user app usage patternsFetch latest content
BGProcessingTaskSeveral minutesDevice charging, idle (typically overnight)Maintenance, ML training
BGContinuedProcessingTaskExtendedSystem-managed with progress UIUser-initiated export/publish
beginBackgroundTask~30 secondsImmediately when backgroundingSave state, finish upload
Background URLSessionAs neededSystem-friendly time, even after terminationLarge transfers

Common Patterns

Pattern 1: BGAppRefreshTask — Keep Content Fresh

Use when: You need to fetch new content so app feels fresh when user opens it.

Runtime: ~30 seconds

When system runs it: Predicted based on user's app usage patterns. If user opens app every morning, system learns and refreshes before then.

Registration (at app launch)

func application(_ application: UIApplication,
                 didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

    BGTaskScheduler.shared.register(
        forTaskWithIdentifier: "com.yourapp.refresh",
        using: nil
    ) { task in
        self.handleAppRefresh(task: task as! BGAppRefreshTask)
    }

    return true
}

Scheduling (when app backgrounds)

func scheduleAppRefresh() {
    let request = BGAppRefreshTaskRequest(identifier: "com.yourapp.refresh")

    // earliestBeginDate = MINIMUM delay, not exact time
    // System may run hours later based on usage patterns
    request.earliestBeginDate = Date(timeIntervalSinceNow: 15 * 60)  // At least 15 min

    do {
        try BGTaskScheduler.shared.submit(request)
    } catch {
        print("Failed to schedule refresh: \(error)")
    }
}

// Call when app enters background
func applicationDidEnterBackground(_ application: UIApplication) {
    scheduleAppRefresh()
}

// Or with SceneDelegate / SwiftUI
.onChange(of: scenePhase) { newPhase in
    if newPhase == .background {
        scheduleAppRefresh()
    }
}

Handler

func handleAppRefresh(task: BGAppRefreshTask) {
    // 1. IMMEDIATELY set expiration handler
    task.expirationHandler = { [weak self] in
        // Cancel any in-progress work
        self?.currentOperation?.cancel()
    }

    // 2. Schedule NEXT refresh (continuous refresh pattern)
    scheduleAppRefresh()

    // 3. Do the work
    fetchLatestContent { [weak self] result in
        switch result {
        case .success:
            task.setTaskCompleted(success: true)
        case .failure:
            task.setTaskCompleted(success: false)
        }
    }
}

Key points:

  • Set expiration handler FIRST
  • Schedule next refresh inside handler (continuous pattern)
  • Call setTaskCompleted in ALL code paths (success AND failure)
  • Keep work under 30 seconds

Pattern 2: BGProcessingTask — Deferrable Maintenance

Use when: Maintenance work that can wait for optimal system conditions (charging, WiFi, idle).

Runtime: Several minutes

When system runs it: Typically overnight when device is charging. May not run daily.

Registration

BGTaskScheduler.shared.register(
    forTaskWithIdentifier: "com.yourapp.maintenance",
    using: nil
) { task in
    self.handleMaintenance(task: task as! BGProcessingTask)
}

Scheduling with Constraints

func scheduleMaintenanceIfNeeded() {
    // Be conscientious — only schedule when work is actually needed
    guard needsMaintenance() else { return }

    let request = BGProcessingTaskRequest(identifier: "com.yourapp.maintenance")

    // CRITICAL: Set requiresExternalPower for CPU-intensive work
    request.requiresExternalPower = true

    // Optional: Require network for cloud sync
    request.requiresNetworkConnectivity = true

    // Don't set earliestBeginDate too far — max ~1 week
    // If user doesn't return to app, task won't run

    do {
        try BGTaskScheduler.shared.submit(request)
    } catch BGTaskScheduler.Error.unavailable {
        pr

---

*Content truncated.*

axiom-swiftui-nav-diag

CharlesWiltgen

Use when debugging navigation not responding, unexpected pops, deep links showing wrong screen, state lost on tab switch or background, crashes in navigationDestination, or any SwiftUI navigation failure - systematic diagnostics with production crisis defense

54

axiom-swiftui-26-ref

CharlesWiltgen

Use when implementing iOS 26 SwiftUI features - covers Liquid Glass design system, performance improvements, @Animatable macro, 3D spatial layout, scene bridging, WebView/WebPage, AttributedString rich text editing, drag and drop enhancements, and visionOS integration for iOS 26+

33

axiom-extensions-widgets-ref

CharlesWiltgen

Use when implementing widgets, Live Activities, Control Center controls, or app extensions - comprehensive API reference for WidgetKit, ActivityKit, App Groups, and extension lifecycle for iOS 14+

13

axiom-ios-build

CharlesWiltgen

Use when ANY iOS build fails, test crashes, Xcode misbehaves, or environment issue occurs before debugging code. Covers build failures, compilation errors, dependency conflicts, simulator problems, environment-first diagnostics.

253

axiom-camera-capture-ref

CharlesWiltgen

Reference — AVCaptureSession, AVCapturePhotoSettings, AVCapturePhotoOutput, RotationCoordinator, photoQualityPrioritization, deferred processing, AVCaptureMovieFileOutput, session presets, capture device APIs

42

axiom-swiftdata

CharlesWiltgen

Use when working with SwiftData - @Model definitions, @Query in SwiftUI, @Relationship macros, ModelContext patterns, CloudKit integration, iOS 26+ features, and Swift 6 concurrency with @MainActor — Apple's native persistence framework

12

You might also like

flutter-development

aj-geddes

Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.

1,6851,428

ui-ux-pro-max

nextlevelbuilder

"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."

1,2671,333

drawio-diagrams-enhanced

jgtolentino

Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.

1,5381,147

godot

bfollington

This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.

1,356809

nano-banana-pro

garg-aayush

Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.

1,264728

pdf-to-markdown

aliceisjustplaying

Convert entire PDF documents to clean, structured Markdown for full context loading. Use this skill when the user wants to extract ALL text from a PDF into context (not grep/search), when discussing or analyzing PDF content in full, when the user mentions "load the whole PDF", "bring the PDF into context", "read the entire PDF", or when partial extraction/grepping would miss important context. This is the preferred method for PDF text extraction over page-by-page or grep approaches.

1,489684