ios – SwiftUI and .backgroundTask(.appRefresh(..)) not working

0
240


Using iOS16.1, Swift5.7.1, XCode 14.1,

My SwiftUI App shall be pimped with some background work done.

First question: Is it correct that periodically occurring background-work can only be done if the App is still running (i.e. if the app is not entirely closed but rather covered by other apps) ?? Or can you periodically execute background-work with a completely closed App ? If yes, how ?

Second question: What is wrong with the following code ?

There is unfortunately no background work done with this code, why ?? (I tried with and without the debugger and also, I tried on the actual device)

import SwiftUI
import BackgroundTasks

@main
struct MyApp: App {
    
    @Environment(\.scenePhase) private var phase
    
    @State private var counter = 0;
    
    var body: some Scene {
        WindowGroup {
            ZStack {
                Text("\(counter)")
            }
        }
        .onChange(of: phase) { newPhase in
            switch newPhase {
            case .background:
                scheduleDataRefetch()
            default: break
            }
        }
        .backgroundTask(.appRefresh("com.url.myidentifier")) {
            await refetch()
            scheduleDataRefetch()
        }
    }
    
    private func refetch() async {
        if await refetchData() {
            print("refetch done...")
        }
    }
    
    private func refetchData() async -> Bool {
        
        counter += 1
        print(counter)
        
        return true
    }
}

func scheduleDataRefetch() {
    
    let request = BGAppRefreshTaskRequest(identifier: "com.url.myidentifier")
    request.earliestBeginDate = .now.addingTimeInterval(5)
    do {
        try BGTaskScheduler.shared.submit(request)
        // HERE I SET THE BREAKPOINT IF WORKING WITH DEBUGGER
        print("Background Task scheduled..")
    } catch {
        print("Could not first-time schedule app refresh: \(error)")
    }
}

I use the following line in lldb to execute the actual background task in the Debugger:

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

When I set a breackpoint right after registering, I can make the background-taks work exactly one time by executing the above line via the lldb debugger terminal. However, when I try this a second time, then the following error occurrs. Why ?

The error message I get is:

2022-11-16 15:08:54.801942+0100 myApp[5035:1253266] Simulating launch for task with identifier com.url.myidentifier
Background Task scheduled..
2022-11-16 15:08:56.215666+0100 myApp[5035:1253265] Marking simulated task complete: <BGAppRefreshTask: com.url.myidentifer>
2022-11-16 15:08:56.218075+0100 myApp[5035:1253298] Task with identifier <decode: missing data> is already running
2022-11-16 15:08:56.221317+0100 myApp[5035:1253298] *** Assertion failure in -[BGTaskScheduler _simulateLaunchForTaskWithIdentifier:], BGTaskScheduler.m:591
2022-11-16 15:08:56.230648+0100 myApp[5035:1253298] [xpc.exceptions] <NSXPCConnection: 0x2825850e0> connection to service with pid 76 named com.apple.duetactivityscheduler: Exception caught during invocation of reply block to message 'getPendingTaskRequestsWithCompletionHandler:'.

Exception: No launch handler registered for task with identifier {public}@
(
    0   CoreFoundation                      0x00000001a33d9e94 5CDC5D9A-E506-3740-B64E-BB30867B4F1B + 40596
    1   libobjc.A.dylib                     0x000000019c7138d8 objc_exception_throw + 60
    2   Foundation                          0x000000019dd01b4c C431ACB6-FE04-3D28-B677-4DE6E1C7D81F + 5528396
    3   BackgroundTasks                     0x000000020a9e9880 5AF8F9BB-273F-3BE1-AC5A-A4A6929CC5E0 + 22656
    4   BackgroundTasks                     0x000000020a9e806c 5AF8F9BB-273F-3BE1-AC5A-A4A6929CC5E0 + 16492
    5   CoreFoundation                      0x00000001a3444704 5CDC5D9A-E506-3740-B64E-BB30867B4F1B + 476932
    6   CoreFoundation                      0x00000001a33f0b6c 5CDC5D9A-E506-3740-B64E-BB30867B4F1B + 133996
    7   Foundation                          0x000000019d85db08 C431ACB6-FE04-3D28-B677-4DE6E1C7D81F + 662280
    8   Foundation                          0x000000019d82eef0 C431ACB6-FE04-3D28-B677-4DE6E1C7D81F + 470768
    9   Foundation                          0x000000019de082e4 C431ACB6-FE04-3D28-B677-4DE6E1C7D81F + 6603492
    10  libxpc.dylib                        0x00000001f0490f1c 7A0CA8D2-7285-37DD-AE97-2EFAA1DE763E + 122652
    11  libxpc.dylib                        0x00000001f0483fb4 7A0CA8D2-7285-37DD-AE97-2EFAA1DE763E + 69556
    12  libdispatch.dylib                   0x00000001097120dc _dispatch_client_callout3 + 20
    13  libdispatch.dylib                   0x0000000109731df0 _dispatch_mach_msg_async_reply_invoke + 392
    14  libdispatch.dylib                   0x0000000109719ea8 _dispatch_lane_serial_drain + 376
    15  libdispatch.dylib                   0x000000010971ae34 _dispatch_lane_invoke + 420
    16  libdispatch.dylib                   0x0000000109727cbc _dispatch_workloop_worker_thread + 740
    17  libsystem_pthread.dylib             0x00000001f042fdf8 _pthread_wqthread + 288
    18  libsystem_pthread.dylib             0x00000001f042fb98 start_wqthread + 8
)
2022-11-16 15:08:56.234625+0100 myApp[5035:1253298] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'No launch handler registered for task with identifier {public}@'
*** First throw call stack:
(0x1a33d9e88 0x19c7138d8 0x19dd01b4c 0x20a9e9880 0x20a9e806c 0x1a3444704 0x1a33f0b6c 0x19d85db08 0x19d82eef0 0x19de082e4 0x1f0490f1c 0x1f0483fb4 0x1097120dc 0x109731df0 0x109719ea8 0x10971ae34 0x109727cbc 0x1f042fdf8 0x1f042fb98)
libc++abi: terminating with uncaught exception of type NSException

I don’t care too much about the debugger in the lldb-terminal not working (we are used by now that not everything works with XCode) – but I would really like to know why the code is also not working for an actual device. Any help on this highly appreciated !