Post

Replies

Boosts

Views

Activity

Reply to Picture-In-Picture not starting with Custom Player
Adding a second cause for -1001, since this thread is the top result for it and the failure reason in the original post doesn't cover the case in the July 2023 reply. To be clear about what I can't help with: if your UIScene genuinely isn't ForegroundActive, the message in the first post is your answer and mine isn't. This is for the other case — the scene logs as UISceneActivationStateForegroundActive and startPictureInPicture() still fails. AVKit will not start Picture in Picture for a player layer that isn't on screen. Foreground is not the same test. In my app the video lives on one tab and the control that starts PiP is on another, so the layer was alive, attached to the controller, and simply not being displayed. isPictureInPicturePossible stayed true the entire time. The call produced: pip: calling startPictureInPicture() (active=false) pip: FAILED to start -- AVKitErrorDomain -1001: Failed to start picture in picture. The fix was to bring the layer on screen first and then ask, and to keep asking, because "is it laid out yet" isn't knowable up front — select the tab, then call startPictureInPicture() at 350/600/900/1200ms until isPictureInPictureActive comes back true. Verified on a physical iPhone 17. The same error turned up separately in a recovery path that built a fresh AVPlayerLayer while the app was backgrounded — a layer that has never been displayed behaves the same way, though that case is also consistent with the scene explanation so I'd not count it as independent evidence. Two things worth doing whatever your cause turns out to be: Implement pictureInPictureController(_:failedToStartPictureInPictureWithError:) if you haven't. startPictureInPicture() returns Void and that delegate method is the only place AVKit hands back an NSError. I'd been reasoning from "the flag is true and nothing happened" for a while before I implemented it. Log ns.localizedFailureReason, not just ns.localizedDescription. localizedDescription is the useless half ("Failed to start picture in picture."); the failure reason is the field carrying the diagnosis in the original post above. I logged only the description and so I can't tell you what reason, if any, AVKit attached to mine. One more thing that wasted my time and may be wasting someone's here: if you have a timeout around the start, check it isn't cutting off successes. Mine gave up at four seconds and the log showed a start landing in the same second as the giving-up, so users got told it had failed and then got a PiP window. Longer write-up with the retry ladder and the isPictureInPicturePossible part: https://mcmizzle.com/blog/pip-wont-start-avkit-1001/
Topic: Media Technologies SubTopic: Audio Tags:
4d
Reply to Background Health Store Access for Lock Screen Widgets
I don't have a way around the locked-store restriction either. There's now an explicit DTS answer confirming reads aren't permitted while locked (thread 824819, May 2026), so I've stopped hoping for one. What I can offer is the failure mode I hit while working around it, because it's easy to ship by accident and it presents as a completely different bug. A statistics query that fails because the store is encrypted reports no sum. That is the same thing it reports for a day with genuinely no samples. So if your read does something like result?.sumQuantity()?.doubleValue(for: unit) ?? 0 and binds the error parameter to _, a failed read returns a confident 0. Mine then got published to the widget with a current timestamp, so every morning the widget showed a plausible, freshly-stamped, completely wrong zero until the app was next opened. It reads exactly like a refresh bug — I lost time on timeline reloads and App Group configuration before noticing the timestamp was fresh, which meant the data wasn't stale, it was freshly wrong. What worked, given we can't read while locked: Return an optional from the read. nil for a failed query, and 0 only for HKError.errorNoData, which is HealthKit's way of saying the range really is empty. On failure, publish nothing and leave the previous values untouched. A widget showing yesterday's number is far better than one showing a wrong number today. Audit every path that writes to the widget, not just the one you fixed. A freshly-initialized model object is full of zeros too, and those are every bit as plausible as the ones a failed query produces. Carry the day the numbers describe separately from the "updated at" time. Once a write can be skipped, "when was this written" stops answering "which day is this about" — and that distinction is what lets you render a stale payload as visibly stale instead of asserting it. None of that gets data while locked. It does stop the lock from producing wrong data, which in my case was the actual user-visible bug. Longer version: https://mcmizzle.com/blog/healthkit-widget-shows-zero/
Aug ’26
Reply to Lifecycle of a tvOS 13.2 TopShelf extension?
Late to this thread, but it still happens on the tvOS 27.0 public beta (24J5325d), on an Apple TV 4K (3rd gen), with an app whose deployment target is tvOS 17. I don't think the caching angle has come up here. Something a reboot does that reinstalling doesn't: the Home screen process caches the rendered Top Shelf tile and dedupes incoming content against that cache. In my case that cache survived a changed item identifier and a full uninstall and reinstall of the app, and kept drawing a tile built from an earlier build for hours while the current code was correct. The log line that finally showed it: Skipping content update for [com.example.app] because it is unchanged If your item identifier is a constant, a corrected item is indistinguishable from the cached one, so a fix to what's in the tile can never reach the screen. Deriving the identifier from the content you're rendering closes that particular trap. (Use the content string itself, not its hashValue — Swift seeds Hashable per process, so a hash changes every launch regardless of content, which isn't what you want.) I want to be careful not to overclaim: your symptom is the extension not running at all after an Xcode relaunch, and mine was a running extension whose output wasn't reaching the screen. Those may well be different bugs. But if you're in the position of "only a reboot fixes it," it's worth checking whether the system is even accepting your content before concluding the extension is dead. Two other things that cost me an evening and are much easier to state than to discover: print() from a Top Shelf extension reaches nobody, and log stream has no device flag. os.Logger at .notice, read in Console.app with the Apple TV tethered, is the channel that works. Not .debug, which isn't persisted by default and so is missing from exactly the capture you collected. An extension can read the shared App Group container but is sandbox-denied from creating files in it — deny(1) file-write-create, surfacing as NSCocoaErrorDomain 513. The containing app has no such restriction. If you need something dynamic on the shelf, the app writes it and the extension only reads it. Full write-up if it's any use: https://mcmizzle.com/blog/tvos-top-shelf-stale-cache/
Aug ’26
Reply to Picture-In-Picture not starting with Custom Player
Adding a second cause for -1001, since this thread is the top result for it and the failure reason in the original post doesn't cover the case in the July 2023 reply. To be clear about what I can't help with: if your UIScene genuinely isn't ForegroundActive, the message in the first post is your answer and mine isn't. This is for the other case — the scene logs as UISceneActivationStateForegroundActive and startPictureInPicture() still fails. AVKit will not start Picture in Picture for a player layer that isn't on screen. Foreground is not the same test. In my app the video lives on one tab and the control that starts PiP is on another, so the layer was alive, attached to the controller, and simply not being displayed. isPictureInPicturePossible stayed true the entire time. The call produced: pip: calling startPictureInPicture() (active=false) pip: FAILED to start -- AVKitErrorDomain -1001: Failed to start picture in picture. The fix was to bring the layer on screen first and then ask, and to keep asking, because "is it laid out yet" isn't knowable up front — select the tab, then call startPictureInPicture() at 350/600/900/1200ms until isPictureInPictureActive comes back true. Verified on a physical iPhone 17. The same error turned up separately in a recovery path that built a fresh AVPlayerLayer while the app was backgrounded — a layer that has never been displayed behaves the same way, though that case is also consistent with the scene explanation so I'd not count it as independent evidence. Two things worth doing whatever your cause turns out to be: Implement pictureInPictureController(_:failedToStartPictureInPictureWithError:) if you haven't. startPictureInPicture() returns Void and that delegate method is the only place AVKit hands back an NSError. I'd been reasoning from "the flag is true and nothing happened" for a while before I implemented it. Log ns.localizedFailureReason, not just ns.localizedDescription. localizedDescription is the useless half ("Failed to start picture in picture."); the failure reason is the field carrying the diagnosis in the original post above. I logged only the description and so I can't tell you what reason, if any, AVKit attached to mine. One more thing that wasted my time and may be wasting someone's here: if you have a timeout around the start, check it isn't cutting off successes. Mine gave up at four seconds and the log showed a start landing in the same second as the giving-up, so users got told it had failed and then got a PiP window. Longer write-up with the retry ladder and the isPictureInPicturePossible part: https://mcmizzle.com/blog/pip-wont-start-avkit-1001/
Topic: Media Technologies SubTopic: Audio Tags:
Replies
Boosts
Views
Activity
4d
Reply to Background Health Store Access for Lock Screen Widgets
I don't have a way around the locked-store restriction either. There's now an explicit DTS answer confirming reads aren't permitted while locked (thread 824819, May 2026), so I've stopped hoping for one. What I can offer is the failure mode I hit while working around it, because it's easy to ship by accident and it presents as a completely different bug. A statistics query that fails because the store is encrypted reports no sum. That is the same thing it reports for a day with genuinely no samples. So if your read does something like result?.sumQuantity()?.doubleValue(for: unit) ?? 0 and binds the error parameter to _, a failed read returns a confident 0. Mine then got published to the widget with a current timestamp, so every morning the widget showed a plausible, freshly-stamped, completely wrong zero until the app was next opened. It reads exactly like a refresh bug — I lost time on timeline reloads and App Group configuration before noticing the timestamp was fresh, which meant the data wasn't stale, it was freshly wrong. What worked, given we can't read while locked: Return an optional from the read. nil for a failed query, and 0 only for HKError.errorNoData, which is HealthKit's way of saying the range really is empty. On failure, publish nothing and leave the previous values untouched. A widget showing yesterday's number is far better than one showing a wrong number today. Audit every path that writes to the widget, not just the one you fixed. A freshly-initialized model object is full of zeros too, and those are every bit as plausible as the ones a failed query produces. Carry the day the numbers describe separately from the "updated at" time. Once a write can be skipped, "when was this written" stops answering "which day is this about" — and that distinction is what lets you render a stale payload as visibly stale instead of asserting it. None of that gets data while locked. It does stop the lock from producing wrong data, which in my case was the actual user-visible bug. Longer version: https://mcmizzle.com/blog/healthkit-widget-shows-zero/
Replies
Boosts
Views
Activity
Aug ’26
Reply to Lifecycle of a tvOS 13.2 TopShelf extension?
Late to this thread, but it still happens on the tvOS 27.0 public beta (24J5325d), on an Apple TV 4K (3rd gen), with an app whose deployment target is tvOS 17. I don't think the caching angle has come up here. Something a reboot does that reinstalling doesn't: the Home screen process caches the rendered Top Shelf tile and dedupes incoming content against that cache. In my case that cache survived a changed item identifier and a full uninstall and reinstall of the app, and kept drawing a tile built from an earlier build for hours while the current code was correct. The log line that finally showed it: Skipping content update for [com.example.app] because it is unchanged If your item identifier is a constant, a corrected item is indistinguishable from the cached one, so a fix to what's in the tile can never reach the screen. Deriving the identifier from the content you're rendering closes that particular trap. (Use the content string itself, not its hashValue — Swift seeds Hashable per process, so a hash changes every launch regardless of content, which isn't what you want.) I want to be careful not to overclaim: your symptom is the extension not running at all after an Xcode relaunch, and mine was a running extension whose output wasn't reaching the screen. Those may well be different bugs. But if you're in the position of "only a reboot fixes it," it's worth checking whether the system is even accepting your content before concluding the extension is dead. Two other things that cost me an evening and are much easier to state than to discover: print() from a Top Shelf extension reaches nobody, and log stream has no device flag. os.Logger at .notice, read in Console.app with the Apple TV tethered, is the channel that works. Not .debug, which isn't persisted by default and so is missing from exactly the capture you collected. An extension can read the shared App Group container but is sandbox-denied from creating files in it — deny(1) file-write-create, surfacing as NSCocoaErrorDomain 513. The containing app has no such restriction. If you need something dynamic on the shelf, the app writes it and the extension only reads it. Full write-up if it's any use: https://mcmizzle.com/blog/tvos-top-shelf-stale-cache/
Replies
Boosts
Views
Activity
Aug ’26