mcpField
A
axiom-background-processing-diag

axiom-background-processing-diag

github.com/charleswiltgen開発1.2k169 回インストール今日更新
リポジトリ

axiom-background-processing-diag について

iOS のバックグラウンド処理を症状別に調査する、開発者向けの診断スキルです。タスクの未実行や早期終了、URLSession デリゲートの問題、不安定なスケジューリング、バックグラウンド起動時のクラッシュを扱います。

主な機能

  1. 01タスクが実行されない問題の診断
  2. 02タスクの早期終了の調査
  3. 03バックグラウンド URLSession デリゲートの確認
  4. 04不安定なスケジューリングの調査
  5. 05起動と期限切れ処理のテスト

活用シーン

  1. 01登録したバックグラウンドタスクが開始しない原因の特定
  2. 02完了前にタスクが終了する問題の調査
  3. 03デリゲートが呼ばれないダウンロードのデバッグ
  4. 04開発環境と本番環境の動作差の分析

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/charleswiltgen/axiom --skill axiom-background-processing-diag

インストール後、Claude Code で/axiom-background-processing-diagを入力して読み込まれたか確認します。

詳細

バックグラウンド処理の診断

バックグラウンドタスクの問題を症状別にトラブルシューティングします。

関連スキル:axiom-background-processing(パターン、チェックリスト)、axiom-background-processing-ref(API リファレンス)


症状 1:タスクが実行されない

submit() が成功しているにもかかわらず、ハンドラーが呼び出されません。

クイック診断(5 分)
Task never runs?
│
├─ Step 1: Check Info.plist (2 min)
│  ├─ BGTaskSchedulerPermittedIdentifiers contains EXACT identifier?
│  │  └─ NO → Add identifier, rebuild
│  ├─ UIBackgroundModes includes "fetch" or "processing"?
│  │  └─ NO → Add required mode
│  └─ Identifiers case-sensitive match code?
│     └─ NO → Fix typo, rebuild
│
├─ Step 2: Check registration timing (2 min)
│  ├─ Registered in didFinishLaunchingWithOptions?
│  │  └─ NO → Move registration before return true
│  └─ Registration before first submit()?
│     └─ NO → Ensure register() precedes submit()
│
└─ Step 3: Check app state (1 min)
   ├─ App swiped away from App Switcher?
   │  └─ YES → No background until user opens app
   └─ Background App Refresh disabled in Settings?
      └─ YES → Enable or inform user
時間とコストの分析
方法時間成功率
Info.plist と登録を確認5 分70%(ほとんどの問題を検出)
コンソールログを追加15 分90%
LLDB で起動をシミュレート5 分95%(ハンドラーが動作することを確認)
手当たり次第にコードを変更2 時間以上低い
LLDB クイックテスト

ハンドラーが正しく登録されていることを確認します。

e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.yourapp.refresh"]

ブレークポイントにヒットする場合 → 登録は正しく、問題はスケジューリングやシステム要因にあります。 何も起こらない場合 → 登録に問題があります。


症状 2:タスクが予期せず終了する

ハンドラーは呼び出されますが、終了前に処理が完了しません。

クイック診断(5 分)
Task terminates early?
│
├─ Step 1: Check expiration handler (1 min)
│  ├─ Expiration handler set FIRST in handler?
│  │  └─ NO → Move to very first line
│  └─ Expiration handler actually cancels work?
│     └─ NO → Add cancellation logic
│
├─ Step 2: Check setTaskCompleted (2 min)
│  ├─ Called in success path?
│  ├─ Called in failure path?
│  ├─ Called after expiration?
│  └─ ANY path missing → Task never signals completion
│
├─ Step 3: Check work duration (2 min)
│  ├─ BGAppRefreshTask work > 30 seconds?
│  │  └─ YES → Chunk work or use BGProcessingTask
│  └─ BGProcessingTask work > system limit?
│     └─ YES → Save progress, resume on next launch
よくある原因
原因修正方法
有効期限ハンドラーがない最初の行でハンドラーを設定する
setTaskCompleted が呼び出されないすべてのコードパスに追加する
処理に時間がかかりすぎる分割してチェックポイントを設定する
ネットワークのタイムアウトがタスク時間を超えるバックグラウンド URLSession を使用する
有効期限切れ後に非同期コールバックが実行されるshouldContinue フラグを確認する
有効期限処理のテスト
// First simulate launch
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.yourapp.refresh"]

// Then force expiration
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateExpirationForTaskWithIdentifier:@"com.yourapp.refresh"]

有効期限ハンドラーが実行され、処理が適切に停止することを確認します。


症状 3:バックグラウンド URLSession のデリゲートが呼び出されない

ダウンロードは完了しますが、didFinishDownloadingTo が呼び出されません。

クイック診断(5 分)
URLSession delegate not called?
│
├─ Step 1: Check session configuration (2 min)
│  ├─ Using URLSessionConfiguration.background()?
│  │  └─ NO → Must use background config
│  ├─ Session identifier unique?
│  │  └─ NO → Use unique bundle-prefixed ID
│  └─ sessionSendsLaunchEvents = true?
│     └─ NO → Set for app relaunch on completion
│
├─ Step 2: Check AppDelegate handler (2 min)
│  ├─ handleEventsForBackgroundURLSession implemented?
│  │  └─ NO → Required for session events
│  └─ Completion handler stored and called later?
│     └─ NO → Store handler, call after events processed
│
└─ Step 3: Check delegate assignment (1 min)
   ├─ Session created with delegate?
   └─ Delegate not nil when task completes?
必須の AppDelegate コード
// Store completion handler
var backgroundSessionCompletionHandler: (() -> Void)?

func application(_ application: UIApplication,
                 handleEventsForBackgroundURLSession identifier: String,
                 completionHandler: @escaping () -> Void) {
    backgroundSessionCompletionHandler = completionHandler
}

// Call after all events processed
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
    DispatchQueue.main.async {
        self.backgroundSessionCompletionHandler?()
        self.backgroundSessionCompletionHandler = nil
    }
}

症状 4:開発環境では動作するが、本番環境では動作しない

デバッガーを接続するとタスクが実行されますが、リリースビルドやユーザー環境では失敗します。

クイック診断(10 分)
Works in dev, not prod?
│
├─ Step 1: Check system constraints (3 min)
│  ├─ Low Power Mode enabled?
│  │  └─ Check ProcessInfo.isLowPowerModeEnabled
│  ├─ Background App Refresh disabled?
│  │  └─ Check UIApplication.backgroundRefreshStatus
│  └─ Battery < 20%?
│     └─ System pauses discretionary work
│
├─ Step 2: Check app state (2 min)
│  ├─ App force-quit from App Switcher?
│  │  └─ YES → No background until foreground launch
│  └─ App recently used?
│     └─ Rarely used apps get lower priority
│
├─ Step 3: Check build differences (3 min)
│  ├─ Debug vs Release optimization differences?
│  ├─ #if DEBUG code excluding production?
│  └─ Different bundle identifier in release?
│
└─ Step 4: Add production logging (2 min)
   └─ Log task schedule/launch/complete to analytics
スケジューリングに影響する 7 つの要因

これらはすべて、本番環境でのタスク実行に影響します。

要因確認事項
バッテリー残量が著しく少ないバッテリー残量が 20% 未満ですか?
低電力モードProcessInfo.isLowPowerModeEnabled
アプリの使用状況ユーザーは頻繁にアプリを開いていますか?
アプリスイッチャーアプリをスワイプして終了していませんか?
App のバックグラウンド更新設定で有効になっていますか?
システムの予算最近、バックグラウンドで何度も起動していますか?
レート制限リクエストの頻度が高すぎませんか?
本番環境でのデバッグ

何が起きているかを追跡するため、ログを追加します。

func scheduleRefresh() {
    let request = BGAppRefreshTaskRequest(identifier: "com.app.refresh")
    do {
        try BGTaskScheduler.shared.submit(request)
        Analytics.log("background_task_scheduled")
    } catch {
        Analytics.log("background_task_schedule_failed", error: error)
    }
}

func handleRefresh(task: BGAppRefreshTask) {
    Analytics.log("background_task_started")
    // ... work ...
    Analytics.log("background_task_completed")
    task.setTaskCompleted(success: true)
}

症状 5:タスクのスケジューリングが安定しない

タスクが実行されることもありますが、タイミングが予測できません。

クイック診断(5 分)
Inconsistent scheduling?
│
├─ Step 1: Understand earliestBeginDate (2 min)
│  ├─ This is MINIMUM delay, not scheduled time
│  │  └─ System runs when convenient AFTER this date
│  └─ Set too far in future (> 1 week)?
│     └─ System may skip task entirely
│
├─ Step 2: Check scheduling pattern (2 min)
│  ├─ Scheduling same task multiple times?
│  │  └─ Call getPendingTaskRequests to check
│  └─ Scheduling in handler for continuity?
│     └─ Required for continuous refresh
│
└─ Step 3: Understand system behavior (1 min)
   ├─ BGAppRefreshTask runs based on USER patterns
   │  └─ User rarely opens app = rare runs
   └─ BGProcessingTask runs when charging
      └─ User doesn't charge overnight = no runs
想定される動作
タスクの種類スケジューリングの動作
BGAppRefreshTaskアプリの使用が予測される時間より前に実行されます
BGProcessingTask充電中かつアイドル状態のときに実行されます(通常は夜間)
サイレントプッシュレート制限されます。プッシュ 14 回で起動 7 回となる場合があります

重要なポイント:時間枠をリクエストするのはアプリですが、実行するかどうか、いつ実行するかはシステムが決定します。


症状 6:バックグラウンド起動時にアプリがクラッシュする

バックグラウンドタスクのためにシステムがアプリを起動すると、アプリがクラッシュします。

クイック診断(5 分)
Crash on background launch?
│
├─ Step 1: Check launch initialization (2 min)
│  ├─ UI setup before task handler?
│  │  └─ Background launch may not have UI context
│  ├─ Accessing files before first unlock?
│  │  └─ Use completeUntilFirstUserAuthentication protection
│  └─ Force unwrapping optionals that may be nil?
│     └─ Guard against nil in background context
│
├─ Step 2: Check handler safety (2 min)
│  ├─ Handler captures self strongly?
│  │  └─ Use [weak self] to prevent retain cycles
│  └─ Handler accesses UI on non-main thread?
│     └─ Dispatch UI work to main queue
│
└─ Step 3: Check data protection (1 min)
   └─ Files accessible when device locked?
      └─ Use .completeUnlessOpen or .completeUntilFirstUserAuthentication
バックグラウンドタスクのファイル保護
// Set appropriate protection when creating files
try data.write(to: url, options: .completeFileProtectionUntilFirstUserAuthentication)

// Or configure in entitlements for entire app
安全なハンドラーパターン
BGTaskScheduler.shared.register(
    forTaskWithIdentifier: "com.app.refresh",
    using: nil
) { [weak self] task in
    guard let self = self else {
        task.setTaskCompleted(success: false)
        return
    }

    // Don't access UI
    // Use background-safe APIs only
    self.performBackgroundWork(task: task)
}

症状 7:タスクが複数回実行される

同じタスクが繰り返し、または並列で実行されているように見えます。

クイック診断(5 分)
Task runs multiple times?
│
├─ Step 1: Check scheduling logic (2 min)
│  ├─ Scheduling on every app launch?
│  │  └─ Check getPendingTaskRequests first
│  ├─ Scheduling in handler AND elsewhere?
│  │  └─ Consolidate to single location
│  └─ Using same identifier for different purposes?
│     └─ Use unique identifiers per task type
│
├─ Step 2: Check for duplicate submissions (2 min)
│  └─ Multiple submit() calls queued?
│     └─ System may batch into single execution
│
└─ Step 3: Check handler execution (1 min)
   └─ setTaskCompleted called promptly?
      └─ Delay may cause system to think task hung
重複スケジューリングの防止
func scheduleRefreshIfNeeded() {
    BGTaskScheduler.shared.getPendingTaskRequests { requests in
        let alreadyScheduled = requests.contains {
            $0.identifier == "com.app.refresh"
        }

        if !alreadyScheduled {
            self.scheduleRefresh()
        }
    }
}

クイック診断チェックリスト

30 秒で確認
  • Info.plist に識別子がありますか?
  • didFinishLaunchingWithOptions で登録していますか?
  • アプリをスワイプして終了していませんか?
5 分で確認
  • 識別子は完全に一致していますか(大文字と小文字を区別)?
  • バックグラウンドモード(fetch/processing)は有効ですか?
  • すべてのコードパスで setTaskCompleted を呼び出していますか?
  • 有効期限ハンドラーを最初に設定していますか?
15 分の調査
  • LLDB で起動をシミュレートすると動作しますか?
  • LLDB でシミュレートした有効期限を処理できますか?
  • コンソールに登録やスケジューリングのログが表示されますか?
  • シミュレーターだけでなく、実機で確認していますか?
  • デバッグビルドだけでなく、リリースビルドで確認していますか?
  • 設定で App のバックグラウンド更新が有効になっていますか?

コンソールログのフィルター

// All background task events
subsystem:com.apple.backgroundtaskscheduler

// Specific to your app
subsystem:com.apple.backgroundtaskscheduler message:"com.yourapp"
想定されるログの順序
  1. 「Registered handler for task with identifier」
  2. 「Scheduling task with identifier」
  3. 「Starting task with identifier」
  4. (処理が実行されます)
  5. 「Task completed with identifier」

いずれかのステップが欠けている場合 = その段階で問題が発生しています。


リソース

WWDC: 2019-707 (デバッグコマンド)、2020-10063 (7 つの要因)

スキル: axiom-background-processing、axiom-background-processing-ref


最終更新: 2025-12-31 プラットフォーム: iOS 13+

コメント