Post

Replies

Boosts

Views

Activity

Reply to BGAppRefreshTask expires after few seconds (2-5 seconds).
Thank you Kevin, Regarding Bugsnag initialization, we start it in applicationDidFinishlaunching on the main thread and given our launch times from Xcode organizer (around 1 second 90% and around 0.5 second 50%) and users never complaining of having long start times I don't see how it could take that much longer time than normally it does (sub 100ms). Regarding using notification to test the behavior, the idea is nice, but the slight problem is that it requires somebody closely watching the phone to quickly react to unpredictable background fetch event. I was testing it before and setting to the be triggered as quickly as possible, but usually it was hours of waiting for it to occur after backgrounding the app. Is there a way to force triggering it earlier? The only way I'm able to trigger background fetches (except when running the app via Xcode) is on my jailbroken device by attaching the debugger to DASDaemon and executing forceRunActivities however I think it won't work when the device is locked. We also never saw those early expirations during development or beta testing, they are not in large percentage, but the number of events is not small. It's that we just waste users and our server resources because of those quick expirations. Regarding the Does the system let you track issues by device, even though the device itself is anonymous? the data is very limited (e.g. language, app version, compiler version, thread stack trace), it's way less than in organizer crash logs. So before I close the thread, please confirm that those steps are correct: call scheduleAppRefresh() in applicationDidEnterBackground(_: UIApplication) call scheduleAppRefresh() in the handleAppRefresh directly like in the Apple's documentation and in the code snipped I provided. Lastly, is there a way to know if the app was launched due to the app refresh? If we know that we can avoid a lot of unnecessary initializations. Thank you!
Apr ’25
Reply to BGAppRefreshTask expires after few seconds (2-5 seconds).
I validated our app code again, it strictly follows Apple examples. I also validated the logic around scheduling the next fetch date, we already had unit tests around it to ensure it is always the date in the future (we aim for background fetches during the weekend). Regarding when we track the expiration handler it's the BGAppRefreshTask expiration handler. The app uses Bugsnag to track handled and unhandled errors and it shows the time of the event since when the Bugsnag was loaded (applicationDidFinishLaunching). This is how I can see that a very large number of expired tasks are under 5 seconds after the Bugsnag was loaded. We are not able to reproduce those expiration on our devices (or the QA devices) so there's no way to get sysdiagnose because our error tracking is fully anonymized and our app don't have accounts, we don't know which exact users are affected. @available(iOS 13.0, *) private func handleAppRefresh(task: BGAppRefreshTask) { scheduleAppRefresh() task.expirationHandler = { Tracker.trackErrorMessage("handleAppRefresh expirationHandler: \(task.identifier)") task.setTaskCompleted(success: false) } // Fetch sounds metadata. DataManager.shared.updateLibrary { _ in task.setTaskCompleted(success: true) } } How can I test the following: Test what happens if you unlock your phone immediately after your refresh task starts. I don't think this happens with refresh tasks, but we do expire processing tasks if the phone unlocks (processing tasks should only run when the device is idle). The easy way to test this case is to have you app post a local notification when it enters "handleAppRefresh" and the open the device as soon as you see that notification. Thank you.
Apr ’25
Reply to BGAppRefreshTask expires after few seconds (2-5 seconds).
I just went through Apple docs again. And I can see that the code matches the logic from https://developer.apple.com/documentation/uikit/using-background-tasks-to-update-your-app example. So now I'm again lost. The code from the documentation also schedules app refresh directly from handleAppRefresh like our app does. func handleAppRefresh(task: BGAppRefreshTask) { // Schedule a new refresh task. scheduleAppRefresh() // Create an operation that performs the main part of the background task. let operation = RefreshAppContentsOperation() // Provide the background task with an expiration handler that cancels the operation. task.expirationHandler = { operation.cancel() } // Inform the system that the background task is complete // when the operation completes. operation.completionBlock = { task.setTaskCompleted(success: !operation.isCancelled) } // Start the operation. operationQueue.addOperation(operation) } Is the documentation incorrect?
Apr ’25
Reply to BGAppRefreshTask expires after few seconds (2-5 seconds).
Thank you for the quick reply. The app schedules background fetch in func applicationDidEnterBackground(_: UIApplication). However I can see the code also re-schedules the background task in the launchHandler: @escaping (BGTask). I now think it should re-schedule the task in expiration handler or when the tasks is finished. I wonder now how it worked so far, because those errors started appearing recently, before they were very rare. Anyway thank you again for the reply it helped spotting the problem in the code.
Apr ’25
Reply to Mocking or simulating CBPeripheral, CBCentralManager, etc in tests
They are NSObjects and you can instantiate them even thought their initializers are private. In one of my apps I use the following approach to mock NSObject classes with private initializers. In case of CBPeripheral the following can be used as a start (assuming you are using Swift): let p = CBPeripheral.perform(NSSelectorFromString("new")).takeRetainedValue() as! CBPeripheral In my case I use the helper: func create<O : NSObject>(_ class: O.Type = O.self) -> O { return O.perform(NSSelectorFromString("new")).takeRetainedValue() as! O } let p = create(CBPeripheral.self)
Jan ’25
Reply to Transaction fails with ASDServerErrorDomain Code=3504 in production
I can see the following errors reported in Bugsnag, the app is waiting for the review (there are no new products added): "NSLocalizedDescription": "An unknown error occurred", "NSUnderlyingError": "Error Domain=ASDServerErrorDomain Code=3506 \"Missing application adam id or bundle id.\" UserInfo={NSLocalizedFailureReason=Missing application adam id or bundle id.}" } "NSLocalizedDescription": "An unknown error occurred", "NSUnderlyingError": "Error Domain=ASDServerErrorDomain Code=3504 \"This item cannot be found.\" UserInfo={NSLocalizedFailureReason=This item cannot be found.}"
Topic: App & System Services SubTopic: StoreKit Tags:
Sep ’23