Flutter 앱을 TestFlight에 올렸는데 앱 실행 즉시 크래시가 발생하는 경우가 있다. 코드에 try-catch를 감싸뒀는데도 크래시가 잡히지 않는다면 workmanager 패키지의 iOS BGTaskScheduler 문제일 가능성이 높다.
증상
- 앱을 켜자마자 즉시 크래시 (스플래시도 안 뜸)
- 시뮬레이터/실기기 모두 동일
try-catch로 감쌌는데도 앱이 죽음- 로컬 debug 빌드에서는 정상 동작하다가 release 빌드에서만 크래시
크래시 로그 분석
macOS 크래시 리포트는 ~/Library/Logs/DiagnosticReports/에 .ips 파일로 저장된다.
ls ~/Library/Logs/DiagnosticReports/ | grep Runner
# Runner-2026-02-25-190740.ips
.ips 파일을 파싱하면 스택 트레이스를 확인할 수 있다.
import json
with open('Runner-2026-02-25-190740.ips') as f:
content = f.read()
lines = content.split('\n', 1)
data = json.loads(lines[1])
exc = data.get('exception', {})
print('Type:', exc.get('type')) # EXC_BAD_ACCESS
print('Signal:', exc.get('signal')) # SIGSEGV
실제 크래시 스택 트레이스:
-[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:]
-[BGTaskScheduler _unsafe_submitTaskRequest:error:]
-[BGTaskScheduler submitTaskRequest:error:]
static WorkmanagerPlugin.schedulePeriodicTask(taskIdentifier:earliestBeginInSeconds:)
WorkmanagerPlugin.registerPeriodicTask(request:completion:)
...
UIApplicationMain
원인
workmanager 패키지는 iOS에서 BGTaskScheduler를 사용해 백그라운드 작업을 등록한다. BGTaskScheduler는 태스크 ID가 Info.plist의 BGTaskSchedulerPermittedIdentifiers에 없거나, 기타 조건을 충족하지 못하면 Objective-C NSException을 던진다.
문제는 Dart의 try-catch가 ObjC NSException을 잡지 못한다는 점이다.
// 이 코드는 동작하지 않는다
try {
await Workmanager().initialize(callbackDispatcher);
await Workmanager().registerPeriodicTask(...);
} catch (e) {
// NSException은 여기서 잡히지 않음
// 앱이 그냥 크래시됨
}
Swift의 do-catch도 ObjC NSException을 직접 잡지 못한다. ObjC 예외는 ARC 환경에서 undefined behavior로 이어져 앱이 즉시 종료된다.
해결 방법
방법 1: iOS에서는 workmanager 비활성화
workmanager의 iOS 지원은 공식적으로 실험적(experimental) 이다. Android 전용으로만 사용하는 것이 가장 안전하다.
import 'dart:io';
import 'package:workmanager/workmanager.dart';
Future<void> initialize() async {
// iOS에서는 실행하지 않음
if (Platform.isIOS) return;
try {
await Workmanager().initialize(callbackDispatcher);
await Workmanager().registerPeriodicTask(
'my_task',
'my_task',
frequency: const Duration(minutes: 15),
);
} catch (e) {
print('Workmanager init failed: $e');
}
}
방법 2: workmanager 완전 제거
iOS에서 백그라운드 주기 동기화가 꼭 필요하지 않다면 workmanager 자체를 제거하는 것이 깔끔하다.
pubspec.yaml에서 제거:
dependencies:
# 제거
# workmanager: ^0.9.0
Info.plist에서 관련 항목 제거:
<!-- 이 부분 전체 제거 -->
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>my_task_identifier</string>
</array>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>processing</string>
</array>
주의사항
BGTaskSchedulerPermittedIdentifiers에 태스크 ID를 등록했더라도 시뮬레이터나 특정 iOS 버전에서는 BGTaskScheduler가 예외를 던질 수 있다. Info.plist 설정이 올바르더라도 크래시가 발생한다면 ObjC 예외 문제를 의심해야 한다.
workmanager iOS 지원 현황은 공식 저장소 이슈에서 확인할 수 있다.

💬 댓글
비밀번호를 기억해두면 나중에 내 댓글을 삭제할 수 있어요.