Post

Replies

Boosts

Views

Activity

Reply to BGContinuedProcessingTask register block not called, submit does not throw an error
Hey @DTS Engineer! I got a sysdiagnose and the logs are interesting. The user tapped the button to start processing and the launch handler was not invoked nor was an error thrown after waiting 2 seconds. Relevant logs I see: default 2025-12-13 15:54:32.261450 +0000 AppName Daemon connection established with BGTaskScheduler client default 2025-12-13 15:54:32.261461 +0000 dasd Queried for device resource capabilities default 2025-12-13 15:54:32.261511 +0000 dasd Device Background GPU signals: supportsGraphicsSet: YES, hasSwap: NO default 2025-12-13 15:54:32.261553 +0000 AppName submitTaskRequest: <BGContinuedProcessingTaskRequest: com.jordanhipwell.datestamp.stamp_task.787334072261, (title: Preparing to Stamp…, subtitle: 1 Photo, resources: Default, submissionStrategy: Fail)> default 2025-12-13 15:54:32.261606 +0000 AppName Submitting task request activity: <private> error 2025-12-13 15:54:32.262042 +0000 dasd bgContinuedProcessing-com.jordanhipwell.datestamp.stamp_task.787334072261: Foregrounded apps (<private>) don't include expected identifier: <private> This is from my Info.plist: <key>BGTaskSchedulerPermittedIdentifiers</key> <array> <string>$(PRODUCT_BUNDLE_IDENTIFIER).stamp_task.*</string> </array> And PRODUCT_BUNDLE_IDENTIFIER in the project is com.jordanhipwell.datestamp. I've uploaded the full sysdiagnose to FB21052216.
20h
Reply to Cannot submit apps with Xcode 26.2 RC
I installed the RC (replacing 26.1), tested my app, and went to create a release for an update that happens to need to be released pretty quickly. I recall from previous experience RC builds could submit apps to the App Store so figured I wouldn’t run into any problems. Now I’m blocked. I could go download Xcode 26.1 and redownload the iOS 26.1 Simulator and retest my app with that SDK version but that’s a lot of wasted time/resources only to release the update on a very soon to be out of date SDK. :/ Do you expect this RC build to be accepted in the near future?
1w
Reply to RequestReviewAction never triggering rating dialog
If you’re testing in TestFlight, note the documentation states it won’t appear. When your app calls this method while it’s in development mode, StoreKit always displays the rating and review request view, so you can test the user interface and experience. However, this method has no effect in apps that you distribute for beta testing using TestFlight. Do also be mindful of this note Because this method may not present an alert, don’t call requestReview() or requestReview(in:) in response to a button tap or other user action.
1w
Reply to BGContinuedProcessingTask register block not called, submit does not throw an error
First off, this shouldn't REALLY happen. Generally speaking, any work you're tying to BGContinuedProcessingTask should take at LEAST 20-30s to complete; otherwise, you'd just use UIApplication.beginBackgroundTask(...) so you can always finish the work. However, IF it were to happen, it can just immediately complete the task. My app's use case could take as short as 1 second or as long as thousands of seconds. It's a photo editing app where the user could select for example 1 photo or 1,000 photos to process. Even with 1 photo it could take for example 20 seconds to download the full quality photo from iCloud before it can be edited, so it's unpredictable how long it will take even though the number of photos is known upfront. I'll work to get a sysdiagnose to add to the bug report, after that I'll try to rework the approach to start processing and then submit the request. Thanks for all your help Kevin!
3w
Reply to BGContinuedProcessingTask register block not called, submit does not throw an error
In terms of the API "contract", the expectation is that a request set as "fail" should either start "immediately" or return an error. 👍 my guess as to what happened is something like ... 4. Whatever happened at #3 didn't clear, so the job never started. A couple thoughts here: maybe the job would have started if the user waited additional time, it didn't start within a few seconds in the recording, I don't know if it never would have started. Seems likely though because they didn't report it start processing randomly at some point in the future. If there is some system bug, something funky with the daemon or otherwise, I'm surprised restarting the iPhone did not change the behavior, but waiting some time and trying it again got it to work. (Note I'm taking the user's word on that.) Without a sysdiagnose to see what actually happened, this is just speculation. I'll see what I can do to get one captured. Perhaps instead of starting automatically after 1.5s I'll ask them to contact support and provide a button to continue without background processing. What object is this? And is there ANY possibility that this object might deallocate? It's the "main" view controller in the app that registers the block and performs the work. It can deallocate in uncommon circumstances (eg closing the app and triggering a Home Screen quick action will recreate the root view controller). If you set things up right, #2 is simply hooking into existing functionality of #1 that's already being used by other parts of your app— the progress object is that same progress object #1 already uses, expiration is just save/cancel/etc. I'm struggling to follow this. It would be incredibly helpful to have a sample project with an example implementation showing the different approaches this API supports :) When the work is "done", then you call setTaskCompleted(success:). The complicated scenario I have in mind with the "start work first then request background continued processing task" approach is if the work were to complete before the register launchHandler got called. When the work gets "done" there is no background task persisted because it hasn't started yet and thus can't call that, then later it'd start for the work that is already done. in the case of BGContinuedProcessingTask, I think you'll basically always send "true". You pass "false" when you need the system to run to your task "again", but that doesn't apply to BGContinuedProcessingTask. I think that's not correct. You're supposed to send false when your work encounters an error and that will show the user it failed in the Live Activity, and the system won't run it again, is what I understand. Your snippet doesn't include setting an expiration handler. Do you set one somewhere else? I do in the real app yep, set inside the startProcessing function. Do you call setTaskCompleted(success:) and do you always pass in "true"? I do inside startProcessing after the task completes, passing true if successful and false if an error occurred. Are you reusing the same task identifier? No, it has a dynamic suffix using the wildcard notation that's unique down to the milliseconds* at the time the user tapped the button to start processing. *I did originally use seconds (which was in place when this user encountered the problem). When the task didn't start, some users rage clicked the start button resulting in the register block getting called again with the same number of seconds, which crashed the app because it's a fatal exception to register the same identifier twice in the same session. Switched to ms with the update that put in the 1.5s manual workaround fix. I've encountered a couple surprises shipping this! 😆 Note I've received 25 of these crash reports, so I know this issue has happened (more than) that many times, because when startProcessing is invoked my in-app progress UI prevents tapping the button again, which means my in-app UI did not appear before the user was able to trigger it again, hence the launchHandler wasn't invoked nor was an error thrown immediately. Sadly none of those users reached out to support or I'd ask them to capture a sysdiagnose.
3w
Reply to BGContinuedProcessingTask register block not called, submit does not throw an error
Thanks Kevin! how do you "know" that? And what other devices have you tested on? That particular device does NOT have a dynamic island, so starting a task doesn't necessarily have any "visible" impact. The task DOES start, but you won't see any system UI unless the app is backgrounded or there are other tasks active. The user shared a screen recording where tapping the start processing button did not start processing (which I have not replicated on my devices). Reviewing the code, I'm quite positive the only way that's possible is if the register launchHandler is not invoked nor the catch block entered from submitting the request because when one of those occurs, I present in-app UI that shows progress in addition to updating the background task progress (if non-nil) in the implementation of the startProcessing() func which didn't get called because in-app UI did not appear in the screen recording. If your user is willing to help, what we really need is a sysdiagnose. I asked them but they said the issue is no longer occurring 😮 I inquired if anything had changed, any device settings, low power mode enabled state or anything like that, but nothing they can think of. I suspect no one else is going to reach out to report the issue because I quickly put a workaround in place to call startProcessing(backgroundTask: nil) if it is not called within 1.5s of submitting the request. 😅 Remember that taskIdentifier needs to be unique to each task. If you try to run the same ID "again", the second submit won't work. Yes they are unique. Similarly, if you're running multiple tasks, make sure that startProcessing() accounts for that and can track "all" of them. I don't support running multiple tasks simultaneously, after one completes the user could start another one if desired. it's certainly possible that there's an issue (or bug) with their particular device configuration. One thing I would check here is "Settings.app-> General-> Background App Refresh". That setting is tied to the BackgroundTask framework, and it's possible that disabling it would also disable BGContinuedProcessingTask. Testing this on my devices, when I turn off Background App Refresh, the register launchHandler is still called immediately. If there were an issue with the device configuration, wouldn't the submit request throw an error since the strategy is set to fail if it can't be started immediately? Or are there scenarios where it's expected behavior for an error to not be thrown and yet the launchHandler won't be called? your app doesn't actually have to wait for the request to fire before it starts its work ... If your app is going to do the work "no matter what", then waiting for the handler to fire is just adding additional complexity, delays, and testing load. I'd start the work "immediately" and update BGContinuedProcessingTask if/when it starts. For my simple use case it seems much more straightforward to perform the work once the launchHandler is invoked (or if the submit request fails perform the work without a BGContinuedProcessingTask). I can directly pass a BGContinuedProcessingTask or nil to the function that does the work, as opposed to needing to persist the BGContinuedProcessingTask when it starts and clean it up upon completion/cancelation/failure. This also avoids a seemingly complicated scenario: what do you do if the register launchHandler is invoked after its work had already completed/was canceled/failed, unclear what you'd do with that BGContinuedProcessingTask, shouldn't persist it, there's not a way to "cancel" it. State management for that seems very complicated. Tis much more straightforward to set the strategy to fail and begin processing once it starts or fails to start, since one of those is supposed to happen immediately when strategy is .fail, and that's a totally valid approach for using this API, is was what I understood.
3w
Reply to Creating Swift Package with binaryTarget that has dependencies
Thanks Ed. To confirm I understand correctly, if you develop a framework project and create an XCFramework to distribute as a closed source SDK, your framework cannot have dependencies on open source code-based packages. Every dependency, if any, must be a closed source XCFramework. It is not possible to create and distribute a Swift Package that is a binary target that has dependencies on other packages that are raw source code. When you do have the requirements to build an XCFramework with dependencies on open and closed source libraries, is the recommendation to use CocoaPods*? Are there plans to support this with Swift Package Manager in the future? *This setup "just works" with CocoaPods. You define a Podfile for your framework project specifying the dependencies with specific version numbers, run pod install, build your XCFramework from the workspace specifying BUILD_LIBRARIES_FOR_DISTRIBUTION=YES and SKIP_INSTALL=NO, create your Podspec specifying the vendored framework and those same dependencies, then add that pod in a new app. When you run pod install for the app, it takes care of downloading and integrating the dependencies appropriately, including open and closed source libraries your framework relies on. Since it can be achieved with CocoaPods, I'm surprised it seemingly can't with SPM.
Oct ’25
Reply to Creating Swift Package with binaryTarget that has dependencies
Thanks Ed! I appreciate the goal of reducing dependencies as much as possible. In this simple example to outline the approach in detail, I chose Kingfisher. Our real SDK is much more complicated, it utilizes a couple dependencies that would be very difficult to build ourselves. For our use case, it is acknowledged that if the app itself adds a dependency that our SDK relies on, it should be the same version number or an otherwise compatible version. Our dependencies are not super popular so that is fairly rare, though it does happen. And our SDK is not widely integrated in apps either, it happens to be quite niche. Note our SDK is already in use distributed via CocoaPods and we haven't had an issue thus far, we are now trying to understand how to distribute it via SPM instead. I'm interested to understand why I see the duplicate class warnings with the example I put together, given the app itself did not add Kingfisher as a dependency, its only dependency is the sample WallpaperKitDist SDK. Perhaps because I didn't configure the framework or package correctly so Kingfisher unintentionally got included in the framework and the app? Which is a good segue to your next comment. If you do want to keep the dependency for your XCFramework library, one thing you can sometimes do is set up a package to vend your XCFramework, and declare a dependency in that package so that consumers of the XCFramework also get a resolved version of the library dependency. The build of your framework would need to be configured so that this dependency doesn't wind up built in to your library binary. This way, the build of the client app provides a resolved version of the dependency. This sounds perfect. Given the steps outlined in my post to create an example framework, what do I need to do differently? Thanks!
Oct ’25