Search code examples
iosswiftxcodebackgroundslack

Network request with iOS app in background


I am creating an ad-hoc app that will be distributed at my workplace in order to keep an eye on device charge levels for our test devices. I'm keeping the app awake in the background to check levels using a popular technique documented across the web: Using AVAudioPlayer to play a blank audio file: see article.

This was working fine and all was good and well, however a big part of the app is that it should post to our slack account using their web hook API, and when I do this the app seems to be killed by watchdog:

Incident Identifier: 1CC4B288-4A42-4E4D-9430-58F0FBFF112A
CrashReporter Key:   df80e009afab39b6c94933dd8d9206d4d293f81e
Hardware Model:      iPhone8,2
Process:             Battery [19555]
Path:                /private/var/containers/Bundle/Application/07816F5B-6850-481F-9FA7-6C717BF3946B/Battery.app/Battery
Identifier:          com.yellowbrickbear.Battery
Version:             1 (1.0)
Code Type:           ARM-64 (Native)
Role:                Foreground
Parent Process:      launchd [1]
Coalition:           com.yellowbrickbear.Battery [6957]


Date/Time:           2017-06-22 16:46:41.1031 +0100
Launch Time:         2017-06-22 16:43:36.2253 +0100
OS Version:          iPhone OS 10.3.2 (14F89)
Report Version:      104

Exception Type:  EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Exception Note:  EXC_CORPSE_NOTIFY
Termination Reason: Namespace <0xF>, Code 0x8badf00d
Triggered by Thread:  0

Filtered syslog:
None found

Thread 0 name:  Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libsystem_kernel.dylib          0x0000000180623224 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x000000018062309c mach_msg + 72
2   CoreFoundation                  0x00000001815f4e90 __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x00000001815f2ae4 __CFRunLoopRun + 1060
4   CoreFoundation                  0x0000000181522da4 CFRunLoopRunSpecific + 424
5   GraphicsServices                0x0000000182f8c074 GSEventRunModal + 100
6   UIKit                           0x00000001877dd058 UIApplicationMain + 208
7   Battery                         0x000000010002e2d4 0x100020000 + 58068
8   libdyld.dylib                   0x000000018053159c start + 4

Thread 1 name:  com.apple.uikit.eventfetch-thread
Thread 1:
0   libsystem_kernel.dylib          0x0000000180623224 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x000000018062309c mach_msg + 72
2   CoreFoundation                  0x00000001815f4e90 __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x00000001815f2ae4 __CFRunLoopRun + 1060
4   CoreFoundation                  0x0000000181522da4 CFRunLoopRunSpecific + 424
5   Foundation                      0x000000018203cd74 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 304
6   Foundation                      0x000000018205db44 -[NSRunLoop(NSRunLoop) runUntilDate:] + 96
7   UIKit                           0x00000001881676a8 -[UIEventFetcher threadMain] + 136
8   Foundation                      0x000000018213a2d8 __NSThread__start__ + 996
9   libsystem_pthread.dylib         0x000000018070968c _pthread_body + 240
10  libsystem_pthread.dylib         0x000000018070959c _pthread_body + 0
11  libsystem_pthread.dylib         0x0000000180706cb4 thread_start + 4

Thread 2 name:  AVAudioSession Notify Thread
Thread 2:
0   libsystem_kernel.dylib          0x0000000180623224 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x000000018062309c mach_msg + 72
2   CoreFoundation                  0x00000001815f4e90 __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x00000001815f2ae4 __CFRunLoopRun + 1060
4   CoreFoundation                  0x0000000181522da4 CFRunLoopRunSpecific + 424
5   AVFAudio                        0x000000019b866540 GenericRunLoopThread::Entry(void*) + 164
6   AVFAudio                        0x000000019b88c814 CAPThread::Entry(CAPThread*) + 84
7   libsystem_pthread.dylib         0x000000018070968c _pthread_body + 240
8   libsystem_pthread.dylib         0x000000018070959c _pthread_body + 0
9   libsystem_pthread.dylib         0x0000000180706cb4 thread_start + 4

Thread 3 name:  com.apple.coreaudio.AQClient
Thread 3:
0   libsystem_kernel.dylib          0x0000000180623224 mach_msg_trap + 8
1   libsystem_kernel.dylib          0x000000018062309c mach_msg + 72
2   CoreFoundation                  0x00000001815f4e90 __CFRunLoopServiceMachPort + 192
3   CoreFoundation                  0x00000001815f2ae4 __CFRunLoopRun + 1060
4   CoreFoundation                  0x0000000181522da4 CFRunLoopRunSpecific + 424
5   AudioToolbox                    0x00000001845ad9fc GenericRunLoopThread::Entry(void*) + 164
6   AudioToolbox                    0x00000001847814bc CAPThread::Entry(CAPThread*) + 84
7   libsystem_pthread.dylib         0x000000018070968c _pthread_body + 240
8   libsystem_pthread.dylib         0x000000018070959c _pthread_body + 0
9   libsystem_pthread.dylib         0x0000000180706cb4 thread_start + 4

Thread 4:
0   libsystem_pthread.dylib         0x0000000180706ca8 start_wqthread + 0

Thread 5:
0   libsystem_pthread.dylib         0x0000000180706ca8 start_wqthread + 0

The code I'm using to post to slack is as follows:

DispatchQueue.global(qos: .default).async { [weak self] in
        
    guard let urlComponents = URLComponents(string: "https://hooks.slack.com/services/"), let url = urlComponents.url else { return } // URL shortened so you can't spam us via this S.O!
        
    let urlRequest = NSMutableURLRequest(url: url)
        
    let data = [
        "text": text,
        "channel": /*channel != nil ? channel! :*/ "@simon",
        "icon_emoji": ":passport_control:",
        "username": "Battery Police"
    ]
        
    guard let jsonData = try? JSONSerialization.data(withJSONObject: data, options: []) else {
            return
        }
        
    urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
    urlRequest.httpBody = jsonData
    urlRequest.httpMethod = "POST"
        
    let dataTask = self?.defaultSession?.dataTask(with: urlRequest as URLRequest)
    dataTask?.resume()
}

where defaultSession is set up with a background session configuration. What I'm trying to work out, is why this is crashing the app and if there's anything I can do to stop watchdog killing it!


Solution

  • It seems like this was either solved by @CharlyPico's suggestion to create my queue using the .background qos, or by the fact somehow the call to .play() on my AVAudioPlayer had been removed in a commit. I'm fairly certain it's the former as at one point disabling the API request made the app run forever so that was likely before the .play() call was accidentally removed!