Post

Replies

Boosts

Views

Activity

Reply to Guidance on implementing Declared Age Range API in response to Texas SB2420
It will hurt some Texas users, but not the rest of the world, which is very important. I agree – one of my main concerns is how these laws will impact on all my other users. Should we terminate the app ? You could do that, but it's not a very good user experience. I plan to present some simple messaging that directs users to an Apple support article. Here's a quick sketch of how I'm currently planning to handle this across a few different apps (in SwiftUI). I would appreciate any feedback on this approach, from either a technical or legal standpoint. In my main App struct, I will branch into a new ContentViewWithAgeGate view for iOS 26.2+. WindowGroup { if #available(iOS 26.2, *) { ContentViewWithAgeGate() } else { ContentView() } } ContentViewWithAgeGate acts as a wrapper around ContentView and perfoms the checks: import SwiftUI @preconcurrency import DeclaredAgeRange @available(iOS 26.2, *) struct ContentViewWithAgeGate: View { @Environment(\.requestAgeRange) var requestAgeRange @State private var isAgeRestricted: Bool = false var body: some View { if isAgeRestricted { AgeRestrictedView() } else { ContentView() .task { isAgeRestricted = await determineIfUserIsAgeRestricted() } } } private func determineIfUserIsAgeRestricted() async -> Bool { let isEligibleForAgeFeatures = try? await AgeRangeService.shared.isEligibleForAgeFeatures guard let isEligibleForAgeFeatures, isEligibleForAgeFeatures == true else { return false } guard let ageRangeResponse = try? await requestAgeRange(ageGates: 18) else { return true } switch ageRangeResponse { case .sharing(let range): guard let lowerBound = range.lowerBound, let ageRangeDeclaration = range.ageRangeDeclaration else { // No lower bound or no declaration information; prevent access return true } if lowerBound >= 18 { // User is an adult switch ageRangeDeclaration { case .selfDeclared, .guardianDeclared: // Insufficient level of evidence; prevent access return true case .checkedByOtherMethod, .guardianCheckedByOtherMethod, .governmentIDChecked, .guardianGovernmentIDChecked, .paymentChecked, .guardianPaymentChecked: // Sufficient level of evidence; permit access return false @unknown default: // Unknown AgeRangeDeclaration value; prevent access return true } } else { // User is not old enough; prevent access return true } case .declinedSharing: // User declined to share age info; prevent access return true @unknown default: // Unknown response value; prevent access return true } } } Then, AgeRestrictedView just presents some general information: struct AgeRestrictedView: View { var body: some View { VStack(alignment: .center, spacing: 30) { Text("Access to this app is age-restricted due to local laws in your state or territory.") Text("Please verify your age with Apple and allow this app to access your age information.") Text("For further information, please refer to the following Apple support article: https://support.apple.com/en-us/122770") } .multilineTextAlignment(.center) .padding() } }
Dec ’25
Reply to Guidance on implementing Declared Age Range API in response to Texas SB2420
(0) check if iOS is 26+. Otherwise, proceed without any test (because we cannot do them) Yep, agree. In fact, we specifically need to check for iOS 26.2. in (1), which import to use AppStore.ageRatingCode ? You just need to import storekit to access that. However, as noted below, I'm considering a different option. in (2), if UIKit and not SwiftUI, need the in parameter Indeed you do. Annoyingly, you also need the in parameter if you're putting your code in some class (e.g. some kind of age manager class), and it's not clear to me what you need to pass in (assuming you have a SwiftUI app). where should parental control be tested ? In step (5) ? I honestly don't know at this point – I haven't gotten to that point yet, but as noted below, I'm looking for ways to avoid that side of things. where to deal with change in user's age or repudiation (as required by law if I read properly) My assumption is that if you check the age on every launch, then this should take care of itself. But I could be wrong. what happens if the requests in await do not respond ? Is there some type of timeout, to avoid user being locked in waiting ? I'm not sure – I'm assuming they should return quite quickly and may not even require network connectivity if the information is cashed on device (the WWDC video talks about device caching of the age info). In my testing, I've found that the API calls return very quickly (< 1 second), but that may simply be because it's in a test environment. In any case, my intention is to default to giving the user full access to the app, and I'll only override that if the methods (called in an async task) suggest the user is not allowed access. However, I do not know if this is appropriate and I am open to other suggestions. Relatedly, what should we do if the methods throw an error? Should we assume the user is a child and restrict access? My current plan is to treat the two API calls differently: If isEligibleForAgeFeatures throws, I will assume that the user is not eligible and therefore has full access. If requestAgeRange throws, I will assume the user is a child and restrict access. My logic is that if I cannot determine eligibility, then I should err on the side of the user not being eligible, since the vast majority of users (for the foreseeable future and around the world) will not be eligible. However, if the user is eligible for age features, then we should err on the side of caution, and assume child until proven otherwise. Having thought about all this for another day, my new plan is to drop the App Store age rating check (for now), and use age 18 for the age gate parameter. My primary reason for this is because I don't have much time to properly investigate the PermissionKit stuff and the significant changes stuff before the end of the year (and this stuff seems rather more complicated). So, my first priority is to make sure that the app is blocked for all under-18s (who are subject to the law) until I have a clearer understanding of those issues. However, I would be very keen to hear how other people are handling that stuff.
Dec ’25
Reply to Correctly initializing observable classes in modern SwiftUI
Thanks for getting back to me. I'm thinking specifically about the instantiation of a manager-style class that is global to the app and placed into the environment at launch time. The documentation that you linked to gives this specific example: @main struct BookReaderApp: App { @State private var library = Library() var body: some Scene { WindowGroup { LibraryView() .environment(library) } } } In the example, the Library class is created as a @State var and put into the environment. My first question (which is more theoretical) is: Why does the variable need to be annotated with @State. My (perhaps naive) assumption was that the App struct is special and is initialized only once, so it's not immediately obvious to me why its properties need to be held in state. Indeed, making it a let constant without the @State annotation seems to result in the same behavior. My second, more practical question is: What is the correct way to manually instantiate the Library (rather than doing so in the property declarations). There are various reasons why you might want to do this, but for the sake of example, I'm thinking of something along these lines: @main struct BookReaderApp: App { @State private var library init() { let thing = Thing() self.library = Library(thing: thing) } var body: some Scene { WindowGroup { LibraryView() .environment(library) } } } Note that in this case, Library is not created in the property declarations, but in the init. Searching around on GitHub, I find some examples where people do: self.library = Library(thing: thing) and other cases where people do: self._library = State(initialValue: Library(thing: thing)) I'm trying to understand what the difference is between these two (if anything). Thanks for any light you can shed on these (possibly newbie) questions!
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Nov ’25
Reply to Some issues and questions regarding the use of the BGContinuedProcessingTask API
The engineering team agrees that differentiating between "system expiration" and "user cancellation" is a significant oversight in the current API. I can't comment on future plans/scheduling, but this is something I expect the API to address. Thanks, this is good to know! if you're seeing UI when there are NOT tasks from other apps active, then that's worth filing a bug on. This is definitely happening to me. The BGContinuedProcessingTask UI (notification banner thing) shows up immediately every time I start such a task, even if there are no other apps running a background task (iPhone 12 mini, running iOS 26.1). I didn't realize that this was not the intended behavior. It's kinda hard to file a bug because I don't think there's any specific documentation that states that this is not how the API is supposed to work.
Nov ’25
Reply to BGContinuedProcessingTask expiring unpredictably
Thanks for the advice! Informally, I've generally found that a progress bar needs to update every ~0.1s (10x/sec) to ~1-2s in order to look "right". I guess this depends on the magnitude of the task. If the task takes an hour, then updating every 1s would mean that each update moves the progress bar by a fraction of a pixel. My current setup moves the progress bar about 4px at a time, which looks pretty smooth to me. You can use the progress delegate that provides "raw" rate data; however, the easier option is to use the URLSessionTask.Progress object. With single downloads, you can use that Progress object directly, while more complicated scenarios can use child progress and the flow described here. Thanks for the pointers. I looked into these options but, in the end, it feels like trying to tie the progress to bytes downloaded (rather than number of files completed) is going to open up other issues, notably: If a file fails to download for some reason (and has to be restarted), I will need to subtract out the bytes downloaded from the progress or, in some sense, track each file's progress. Not impossible, but feels fraught with state management bug potential. My task involves downloading and processing files. In some cases, the processing is very small relative to the download time, but in other cases, the processing can take longer than the download, so linking progress only to the download part is not ideal. That's why I originally chose to link progress to file completion. The modifications I'd need to make to my code (passing download progress from the URLSession delegate through an AsyncStream back to the calling task) will result in more complexity that will be hard to test, and background URLSessions are already really hard to work with. Overall, my sense is that BGContinuedProcessingTask is better suited to tasks that are primarily CPU-bound where the rate of progress and time-to-completion is fairly predictable a-priori. For tasks that are more network-bound and where progress is heavily dependent on the volume of user data, it becomes hard to guarantee a particular rate of progress. Since BGContinuedProcessingTask seems to be quite trigger happy and doesn't distinguish between user cancellation and system cancellation, I don't think it's going to be the right option for me. Which is a shame because I was quite excited about it when I saw it at WWDC. Anyway, thanks for the advice, Kevin, and for being very responsive (also to other threads on this forum). It's much appreciated!
Nov ’25
Reply to Some issues and questions regarding the use of the BGContinuedProcessingTask API
I tried different device models, and some could trigger the task normally, such as the 15 Pro Max and 12 Pro Max. However, there were also some models, such as the 17 Pro, 15 Pro, and 15, that could not trigger the task properly. Moreover, there was no additional error information to help locate the issue. I assume you're doing this on device and not the simulator, right? And did you check the Console logs to see if an error was reported there? (look for the dasd process) I also just wanted to reiterate your other points about the BGContinuedProcessingTask API, in case someone from Apple is listening: I agree that the experience on non-Dynamic Island devices is not great. The task notification banner thing is a obtrusive and redundant. My app already displays a progress bar, so displaying another progress indicator is redundant. Moreover, the banner obscures my app's UI and does not disappear automatically like normal notifications. This leaves the user uncertain if they can safely dismiss it, or if dismissing it will cancel the task. The banner is important to make the user aware that a background task is running, but it should only appear if/when the user backgrounds the app – that's when it becomes relevant. Likewise, I've also noticed that the banner text is sometimes the wrong color – sometimes black text in dark mode, or white text in light mode. But I haven't been able to reproduce it consistently. I totally agree that the API is missing a distinction between (1) the user has stopped the task and (2) the system wants to stop the task. In the case of (1), I want to completely cancel the task. In the case of (2), I want to put the task into a paused state until the user is ready to resume it. Ideally, the UI should inform the user that the task has been paused.
Nov ’25
Reply to BGContinuedProcessingTask expiring unpredictably
Based on the response from the engineer over on this post, I looked at the Console logs for the dasd process and found this: Task has not reported progress within expected cadence, marking stalled (time without update: -36.27811694145203) Does -36 mean 36 seconds since the last update? That seems plausible given my situation. What cadence do I need to hit to satisfy the system? Not sure what to do now. This limitation seems to make BGContinuedProcessingTask unsuitable for my use case, since the size of the downloaded files can vary, as can the speed of the user's connection. I could try to feed in fake progress updates to keep the task alive. Or I could try to monitor the byte count of downloading files and use that as the basis for progress updates (however, my previous experience trying to pass the byte count from URLSessionDelegate through an async stream was a nightmare). In any case, it would still be useful if someone from engineering could respond to my above queries, so that I can better understand if there might be other issues to contend with (not just the progress cadence).
Oct ’25
Reply to AlarmKit alarm UI strings are lost after updating OS
It turns out the situation is worse than I thought: it's not the OS update that triggers the bug, but merely restarting the device! If I schedule an alarm with the above code and then restart my device, the alarm triggers at the correct time, but the UI shows the localization keys instead of the strings. I just installed the iOS 26.1 beta (23B5044I) and it's still broken, so I've filed a bug report: FB20472264 As a temporary workaround, I will set my localization keys to English language strings.
Oct ’25
Reply to Safe areas ignored after navigating a WebView/WebPage back in a NavigationStack
I filed a bug report (FB20465338) but I also want to note some more details here in case this is useful to someone: When navigating back/forward in a WebView or WKWebView, the page suddenly jumps up. The reason appears to be that WebKit automatically adds some padding to the top of the webpage to account for the unsafe nav bar area, but it then forgets to account for this padding when navigating back/forward. The effect is especially pronounced if you swipe back/forward. When swiping you see a static preview of the incoming page, but when you release the swipe, the page suddenly jumps up. As far as I can tell, this has always been an issue, but before iOS 26 it wasn't really a problem because the WebView would usually be flush against a solid nav bar. However, in iOS 26, this bug is problematic because Apple is asking us to flow the web content behind the nav bar; indeed, this is the default behavior of a WebView. There's effectively no good solution in iOS 26 because you basically have two choices: Adopt the default behavior with the content flowing behind the nav bar; but then you get a janky back/forward experience. Set .ignoresSafeArea(.all, edges: .bottom) so that the content does not flow behind the top nav bar, but then the nav bar is plain white/black and it looks bad for the content to just disappear abruptly without some kind of border or fade effect. This can't simply be solved by making the nav bar a different color because then you get into issues with the glass buttons and the floating iPad sidebar. Would love to hear if someone figured out a workaround, even if it's just some styling to make Option 2 less bad.
Topic: Safari & Web SubTopic: General Tags:
Oct ’25
Reply to Guidance on implementing Declared Age Range API in response to Texas SB2420
It will hurt some Texas users, but not the rest of the world, which is very important. I agree – one of my main concerns is how these laws will impact on all my other users. Should we terminate the app ? You could do that, but it's not a very good user experience. I plan to present some simple messaging that directs users to an Apple support article. Here's a quick sketch of how I'm currently planning to handle this across a few different apps (in SwiftUI). I would appreciate any feedback on this approach, from either a technical or legal standpoint. In my main App struct, I will branch into a new ContentViewWithAgeGate view for iOS 26.2+. WindowGroup { if #available(iOS 26.2, *) { ContentViewWithAgeGate() } else { ContentView() } } ContentViewWithAgeGate acts as a wrapper around ContentView and perfoms the checks: import SwiftUI @preconcurrency import DeclaredAgeRange @available(iOS 26.2, *) struct ContentViewWithAgeGate: View { @Environment(\.requestAgeRange) var requestAgeRange @State private var isAgeRestricted: Bool = false var body: some View { if isAgeRestricted { AgeRestrictedView() } else { ContentView() .task { isAgeRestricted = await determineIfUserIsAgeRestricted() } } } private func determineIfUserIsAgeRestricted() async -> Bool { let isEligibleForAgeFeatures = try? await AgeRangeService.shared.isEligibleForAgeFeatures guard let isEligibleForAgeFeatures, isEligibleForAgeFeatures == true else { return false } guard let ageRangeResponse = try? await requestAgeRange(ageGates: 18) else { return true } switch ageRangeResponse { case .sharing(let range): guard let lowerBound = range.lowerBound, let ageRangeDeclaration = range.ageRangeDeclaration else { // No lower bound or no declaration information; prevent access return true } if lowerBound >= 18 { // User is an adult switch ageRangeDeclaration { case .selfDeclared, .guardianDeclared: // Insufficient level of evidence; prevent access return true case .checkedByOtherMethod, .guardianCheckedByOtherMethod, .governmentIDChecked, .guardianGovernmentIDChecked, .paymentChecked, .guardianPaymentChecked: // Sufficient level of evidence; permit access return false @unknown default: // Unknown AgeRangeDeclaration value; prevent access return true } } else { // User is not old enough; prevent access return true } case .declinedSharing: // User declined to share age info; prevent access return true @unknown default: // Unknown response value; prevent access return true } } } Then, AgeRestrictedView just presents some general information: struct AgeRestrictedView: View { var body: some View { VStack(alignment: .center, spacing: 30) { Text("Access to this app is age-restricted due to local laws in your state or territory.") Text("Please verify your age with Apple and allow this app to access your age information.") Text("For further information, please refer to the following Apple support article: https://support.apple.com/en-us/122770") } .multilineTextAlignment(.center) .padding() } }
Replies
Boosts
Views
Activity
Dec ’25
Reply to Guidance on implementing Declared Age Range API in response to Texas SB2420
(0) check if iOS is 26+. Otherwise, proceed without any test (because we cannot do them) Yep, agree. In fact, we specifically need to check for iOS 26.2. in (1), which import to use AppStore.ageRatingCode ? You just need to import storekit to access that. However, as noted below, I'm considering a different option. in (2), if UIKit and not SwiftUI, need the in parameter Indeed you do. Annoyingly, you also need the in parameter if you're putting your code in some class (e.g. some kind of age manager class), and it's not clear to me what you need to pass in (assuming you have a SwiftUI app). where should parental control be tested ? In step (5) ? I honestly don't know at this point – I haven't gotten to that point yet, but as noted below, I'm looking for ways to avoid that side of things. where to deal with change in user's age or repudiation (as required by law if I read properly) My assumption is that if you check the age on every launch, then this should take care of itself. But I could be wrong. what happens if the requests in await do not respond ? Is there some type of timeout, to avoid user being locked in waiting ? I'm not sure – I'm assuming they should return quite quickly and may not even require network connectivity if the information is cashed on device (the WWDC video talks about device caching of the age info). In my testing, I've found that the API calls return very quickly (< 1 second), but that may simply be because it's in a test environment. In any case, my intention is to default to giving the user full access to the app, and I'll only override that if the methods (called in an async task) suggest the user is not allowed access. However, I do not know if this is appropriate and I am open to other suggestions. Relatedly, what should we do if the methods throw an error? Should we assume the user is a child and restrict access? My current plan is to treat the two API calls differently: If isEligibleForAgeFeatures throws, I will assume that the user is not eligible and therefore has full access. If requestAgeRange throws, I will assume the user is a child and restrict access. My logic is that if I cannot determine eligibility, then I should err on the side of the user not being eligible, since the vast majority of users (for the foreseeable future and around the world) will not be eligible. However, if the user is eligible for age features, then we should err on the side of caution, and assume child until proven otherwise. Having thought about all this for another day, my new plan is to drop the App Store age rating check (for now), and use age 18 for the age gate parameter. My primary reason for this is because I don't have much time to properly investigate the PermissionKit stuff and the significant changes stuff before the end of the year (and this stuff seems rather more complicated). So, my first priority is to make sure that the app is blocked for all under-18s (who are subject to the law) until I have a clearer understanding of those issues. However, I would be very keen to hear how other people are handling that stuff.
Replies
Boosts
Views
Activity
Dec ’25
Reply to Correctly initializing observable classes in modern SwiftUI
Thanks for getting back to me. I'm thinking specifically about the instantiation of a manager-style class that is global to the app and placed into the environment at launch time. The documentation that you linked to gives this specific example: @main struct BookReaderApp: App { @State private var library = Library() var body: some Scene { WindowGroup { LibraryView() .environment(library) } } } In the example, the Library class is created as a @State var and put into the environment. My first question (which is more theoretical) is: Why does the variable need to be annotated with @State. My (perhaps naive) assumption was that the App struct is special and is initialized only once, so it's not immediately obvious to me why its properties need to be held in state. Indeed, making it a let constant without the @State annotation seems to result in the same behavior. My second, more practical question is: What is the correct way to manually instantiate the Library (rather than doing so in the property declarations). There are various reasons why you might want to do this, but for the sake of example, I'm thinking of something along these lines: @main struct BookReaderApp: App { @State private var library init() { let thing = Thing() self.library = Library(thing: thing) } var body: some Scene { WindowGroup { LibraryView() .environment(library) } } } Note that in this case, Library is not created in the property declarations, but in the init. Searching around on GitHub, I find some examples where people do: self.library = Library(thing: thing) and other cases where people do: self._library = State(initialValue: Library(thing: thing)) I'm trying to understand what the difference is between these two (if anything). Thanks for any light you can shed on these (possibly newbie) questions!
Topic: UI Frameworks SubTopic: SwiftUI Tags:
Replies
Boosts
Views
Activity
Nov ’25
Reply to Some issues and questions regarding the use of the BGContinuedProcessingTask API
The engineering team agrees that differentiating between "system expiration" and "user cancellation" is a significant oversight in the current API. I can't comment on future plans/scheduling, but this is something I expect the API to address. Thanks, this is good to know! if you're seeing UI when there are NOT tasks from other apps active, then that's worth filing a bug on. This is definitely happening to me. The BGContinuedProcessingTask UI (notification banner thing) shows up immediately every time I start such a task, even if there are no other apps running a background task (iPhone 12 mini, running iOS 26.1). I didn't realize that this was not the intended behavior. It's kinda hard to file a bug because I don't think there's any specific documentation that states that this is not how the API is supposed to work.
Replies
Boosts
Views
Activity
Nov ’25
Reply to BGContinuedProcessingTask expiring unpredictably
Thanks for the advice! Informally, I've generally found that a progress bar needs to update every ~0.1s (10x/sec) to ~1-2s in order to look "right". I guess this depends on the magnitude of the task. If the task takes an hour, then updating every 1s would mean that each update moves the progress bar by a fraction of a pixel. My current setup moves the progress bar about 4px at a time, which looks pretty smooth to me. You can use the progress delegate that provides "raw" rate data; however, the easier option is to use the URLSessionTask.Progress object. With single downloads, you can use that Progress object directly, while more complicated scenarios can use child progress and the flow described here. Thanks for the pointers. I looked into these options but, in the end, it feels like trying to tie the progress to bytes downloaded (rather than number of files completed) is going to open up other issues, notably: If a file fails to download for some reason (and has to be restarted), I will need to subtract out the bytes downloaded from the progress or, in some sense, track each file's progress. Not impossible, but feels fraught with state management bug potential. My task involves downloading and processing files. In some cases, the processing is very small relative to the download time, but in other cases, the processing can take longer than the download, so linking progress only to the download part is not ideal. That's why I originally chose to link progress to file completion. The modifications I'd need to make to my code (passing download progress from the URLSession delegate through an AsyncStream back to the calling task) will result in more complexity that will be hard to test, and background URLSessions are already really hard to work with. Overall, my sense is that BGContinuedProcessingTask is better suited to tasks that are primarily CPU-bound where the rate of progress and time-to-completion is fairly predictable a-priori. For tasks that are more network-bound and where progress is heavily dependent on the volume of user data, it becomes hard to guarantee a particular rate of progress. Since BGContinuedProcessingTask seems to be quite trigger happy and doesn't distinguish between user cancellation and system cancellation, I don't think it's going to be the right option for me. Which is a shame because I was quite excited about it when I saw it at WWDC. Anyway, thanks for the advice, Kevin, and for being very responsive (also to other threads on this forum). It's much appreciated!
Replies
Boosts
Views
Activity
Nov ’25
Reply to Some issues and questions regarding the use of the BGContinuedProcessingTask API
I tried different device models, and some could trigger the task normally, such as the 15 Pro Max and 12 Pro Max. However, there were also some models, such as the 17 Pro, 15 Pro, and 15, that could not trigger the task properly. Moreover, there was no additional error information to help locate the issue. I assume you're doing this on device and not the simulator, right? And did you check the Console logs to see if an error was reported there? (look for the dasd process) I also just wanted to reiterate your other points about the BGContinuedProcessingTask API, in case someone from Apple is listening: I agree that the experience on non-Dynamic Island devices is not great. The task notification banner thing is a obtrusive and redundant. My app already displays a progress bar, so displaying another progress indicator is redundant. Moreover, the banner obscures my app's UI and does not disappear automatically like normal notifications. This leaves the user uncertain if they can safely dismiss it, or if dismissing it will cancel the task. The banner is important to make the user aware that a background task is running, but it should only appear if/when the user backgrounds the app – that's when it becomes relevant. Likewise, I've also noticed that the banner text is sometimes the wrong color – sometimes black text in dark mode, or white text in light mode. But I haven't been able to reproduce it consistently. I totally agree that the API is missing a distinction between (1) the user has stopped the task and (2) the system wants to stop the task. In the case of (1), I want to completely cancel the task. In the case of (2), I want to put the task into a paused state until the user is ready to resume it. Ideally, the UI should inform the user that the task has been paused.
Replies
Boosts
Views
Activity
Nov ’25
Reply to iOS Simulator in Xcode 26.1 makes ReportCrash process run at 60-160% of CPU
I'm experiencing the same issue – did you find a workaround?
Replies
Boosts
Views
Activity
Nov ’25
Reply to .glassProminent toolbar buttons are glitchy in iOS 26.1 RC
FB20883820
Topic: UI Frameworks SubTopic: SwiftUI
Replies
Boosts
Views
Activity
Oct ’25
Reply to BGContinuedProcessingTask expiring unpredictably
Based on the response from the engineer over on this post, I looked at the Console logs for the dasd process and found this: Task has not reported progress within expected cadence, marking stalled (time without update: -36.27811694145203) Does -36 mean 36 seconds since the last update? That seems plausible given my situation. What cadence do I need to hit to satisfy the system? Not sure what to do now. This limitation seems to make BGContinuedProcessingTask unsuitable for my use case, since the size of the downloaded files can vary, as can the speed of the user's connection. I could try to feed in fake progress updates to keep the task alive. Or I could try to monitor the byte count of downloading files and use that as the basis for progress updates (however, my previous experience trying to pass the byte count from URLSessionDelegate through an async stream was a nightmare). In any case, it would still be useful if someone from engineering could respond to my above queries, so that I can better understand if there might be other issues to contend with (not just the progress cadence).
Replies
Boosts
Views
Activity
Oct ’25
Reply to AlarmKit alarm UI strings are lost after updating OS
Just confirming that this is still not working correctly for me as of beta 2 of iOS 26.1.
Replies
Boosts
Views
Activity
Oct ’25
Reply to Localization of NSAlarmKitUsageDescription
This appears to be fixed in beta 2 of iOS 26.1. For reference, I set NSAlarmKitUsageDescription in my InfoPlist.xcstrings and verified that the localized usage description was displayed in the authorization dialog.
Replies
Boosts
Views
Activity
Oct ’25
Reply to AlarmKit alarm UI strings are lost after updating OS
It turns out the situation is worse than I thought: it's not the OS update that triggers the bug, but merely restarting the device! If I schedule an alarm with the above code and then restart my device, the alarm triggers at the correct time, but the UI shows the localization keys instead of the strings. I just installed the iOS 26.1 beta (23B5044I) and it's still broken, so I've filed a bug report: FB20472264 As a temporary workaround, I will set my localization keys to English language strings.
Replies
Boosts
Views
Activity
Oct ’25
Reply to iOS 26 regression: Slider does not respect step parameter
Yes, the bug is present with or without UIDesignRequiresCompatibility=TRUE. In fact, the bug is even present in apps compiled with Xcode 16 but running on iOS 26 devices. So, presumably the bug is low level – lower than the iOS 18 compatibility layer. A lot of apps must be hitting this issue!
Topic: UI Frameworks SubTopic: SwiftUI
Replies
Boosts
Views
Activity
Oct ’25
Reply to AlarmKit plays system error tone instead of custom sound files (iOS 26.0)
For me, custom sounds do seem to be working but they do not loop, which effectively makes them useless as an alarm. For now, I've disabled the custom sound feature in my app and I just set the sound to .default. I plan to enable the feature if/when Apple fixes it.
Replies
Boosts
Views
Activity
Oct ’25
Reply to Safe areas ignored after navigating a WebView/WebPage back in a NavigationStack
I filed a bug report (FB20465338) but I also want to note some more details here in case this is useful to someone: When navigating back/forward in a WebView or WKWebView, the page suddenly jumps up. The reason appears to be that WebKit automatically adds some padding to the top of the webpage to account for the unsafe nav bar area, but it then forgets to account for this padding when navigating back/forward. The effect is especially pronounced if you swipe back/forward. When swiping you see a static preview of the incoming page, but when you release the swipe, the page suddenly jumps up. As far as I can tell, this has always been an issue, but before iOS 26 it wasn't really a problem because the WebView would usually be flush against a solid nav bar. However, in iOS 26, this bug is problematic because Apple is asking us to flow the web content behind the nav bar; indeed, this is the default behavior of a WebView. There's effectively no good solution in iOS 26 because you basically have two choices: Adopt the default behavior with the content flowing behind the nav bar; but then you get a janky back/forward experience. Set .ignoresSafeArea(.all, edges: .bottom) so that the content does not flow behind the top nav bar, but then the nav bar is plain white/black and it looks bad for the content to just disappear abruptly without some kind of border or fade effect. This can't simply be solved by making the nav bar a different color because then you get into issues with the glass buttons and the floating iPad sidebar. Would love to hear if someone figured out a workaround, even if it's just some styling to make Option 2 less bad.
Topic: Safari & Web SubTopic: General Tags:
Replies
Boosts
Views
Activity
Oct ’25