I. Aim

I wanted my app, iQuake to run quietly and efficiently in the background and alert users if there was an earthquake nearby. No ads, no nonsense etc. Just helpful, timely alerts pulled from official feeds. I figured SwiftUI's .backgroundTask() and BGAppRefreshTaskRequest would make this clean and elegant.

iQuake app screenshot

II. Starting Off

First things first — the fetch and filter logic. Here's what needed to work:

III. Silence

I had everything in place. Background mode set. Plist updated. Scene phase triggers ready. Ran the app… and then, absolutely nothing. No handler. No log messages. Simulator's "Simulate Background Fetch"? Did less than nothing. I checked everything — identifiers, settings, permissions — and still got the digital equivalent of a shrug.

IV. Crashes

Then came the crash. SIGABRT, thanks to an assertion failure buried in BGTaskScheduler. Stack trace showed it was SwiftUI’s internal registration system acting up. Time to ditch the shiny tools.

No more crashes, finally. But still no background fetch. This time, though, I had something new: dasd logs. They showed the task being submitted… then declined. DecisionToRun: 0. Apparently the system didn't think the app deserved a background wake-up yet. iOS was gatekeeping me.

iQuake app Swift code

V. Progress

Using LLDB I forced a launch: e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"..."]. It ran! The handler executed. The logic worked. That was huge. But oddly, my iPad wasn’t showing notifications.

Turns out I forgot to request permission with:

UNUserNotificationCenter.current().requestAuthorization(...).

Once that was added, notifications showed up properly across devices. Classic oversight in the middle of a messy bug hunt.

VI. Lessons Learned

iQuake alerts firing

This one took longer than it should have, but that happens me quite often. And seeing that first real background-triggered notification hit the lock screen? Worth it.

Droid Crypt logo