Delve into the world of built-in app and system services available to developers. Discuss leveraging these services to enhance your app's functionality and user experience.

Posts under General subtopic

Post

Replies

Boosts

Views

Activity

Problems with SensorKit data calls
The Deligate 'didFetchResult' method of fetching data past 24 hours from SensorKit is not being called. It is confirmed that you have already granted full access to the SensorKit and that data on the Ambient value in the device's personal information -> research sensor & usage data are recorded. It is possible to export to an lz4 file. I want to have the data after 24 hours called to the app, but other Deligate methods are called, but only Deligate that gets the illumination value is not called. Is it understood that only data past 24 hours can be imported after startRecoding() is called? If so, in order to receive data past 24 hours, do I have to continue to receive the illumination data value in the background for more than 24 hours to receive the Ambient value afterwards? import Foundation import SensorKit import UIKit final class SensorKitManager: NSObject, ObservableObject, SRSensorReaderDelegate { static let shared = SensorKitManager() private let ambientReader = SRSensorReader(sensor: .ambientLightSensor) var availableDevices: [SRDevice] = [] @Published var ambientLightData: [AmbientLightDataPoint] = [] var isFetching = false var isRecordingAmbientLight = false private override init() { super.init() setupReaders() checkAndRequestAuthorization() } private func setupReaders() { ambientReader.delegate = self } // MARK: - Permission Request func requestAuthorization() { SRSensorReader.requestAuthorization(sensors: [.ambientLightSensor]) { [weak self] error in DispatchQueue.main.async { guard let self = self else { print("Permission request aborted") return } if let error = error { print("Permission request failed: \(error.localizedDescription)") } else { print("Permission request succeeded") self.startRecordingAmbientLightData() } } } } func checkAndRequestAuthorization() { let status = ambientReader.authorizationStatus switch status { case .authorized: print("Ambient light sensor access granted") startRecordingAmbientLightData() case .notDetermined: print("Ambient light sensor access undetermined, requesting permission") requestAuthorization() case .denied: print("Ambient light sensor access denied or restricted") @unknown default: print("Unknown authorization status") } } // MARK: - Ambient Light Data Logic func startRecordingAmbientLightData() { guard !isRecordingAmbientLight else { print("Already recording ambient light data.") return } print("Starting ambient light data recording") isRecordingAmbientLight = true ambientReader.startRecording() fetchAmbientLightData() fetchAmbientDeviceData() } func fetchAmbientLightData() { print("Fetching ambient light data") let request = SRFetchRequest() let now = Date() let fromTime = now.addingTimeInterval(-72 * 60 * 60) let toTime = now.addingTimeInterval(-25 * 60 * 60) request.from = SRAbsoluteTime(fromTime.timeIntervalSinceReferenceDate) request.to = SRAbsoluteTime(toTime.timeIntervalSinceReferenceDate) print("Fetch request: \(fromTime) ~ \(toTime)") ambientReader.fetch(request) } private func displayAmbientLightData(sample: SRAmbientLightSample) { print("Ambient light: \(sample.lux.value) lux") print("Current ambientLightData content:") for data in ambientLightData { print("Timestamp: \(data.timestamp), Lux: \(data.lux)") } } // MARK: - Device Data Logic private func fetchAmbientDeviceData() { print("Fetching device information") let request = SRFetchRequest() let now = Date() let fromDate = now.addingTimeInterval(-72 * 60 * 60) let toDate = now.addingTimeInterval(-24 * 60 * 60) request.from = SRAbsoluteTime(fromDate.timeIntervalSinceReferenceDate) request.to = SRAbsoluteTime(toDate.timeIntervalSinceReferenceDate) if availableDevices.isEmpty { print("No devices available") ambientReader.fetchDevices() } else { for device in availableDevices { print("Starting data fetch (Device: \(device))") request.device = device ambientReader.fetch(request) print("Fetch request sent (Device: \(device))") } } } // MARK: - SRSensorReaderDelegate Methods func sensorReader(_ reader: SRSensorReader, didFetch devices: [SRDevice]) { availableDevices = devices for device in devices { print("Fetched device: \(device)") } if !devices.isEmpty { fetchAmbientDeviceData() } } func sensorReader(_ reader: SRSensorReader, fetching fetchRequest: SRFetchRequest, didFetchResult result: SRFetchResult<AnyObject>) -> Bool { print("sensorReader(_:fetching:didFetchResult:) method called") if let ambientSample = result.sample as? SRAmbientLightSample { let luxValue = ambientSample.lux.value let timestamp = Date(timeIntervalSinceReferenceDate: result.timestamp.rawValue) // Check for duplicate data and add it if !ambientLightData.contains(where: { $0.timestamp == timestamp }) { let dataPoint = AmbientLightDataPoint(timestamp: timestamp, lux: Float(luxValue)) ambientLightData.append(dataPoint) print("Added ambient light data: \(luxValue) lux, Timestamp: \(timestamp)") } else { print("Duplicate data, not adding: Timestamp: \(timestamp)") } // Output data self.displayAmbientLightData(sample: ambientSample) } return true } func sensorReader(_ reader: SRSensorReader, didCompleteFetch fetchRequest: SRFetchRequest) { print("Data fetch complete") if ambientLightData.isEmpty { print("No ambient light data within 24 hours.") } else { print("ambientLightData updated") for dataPoint in ambientLightData { print("Added ambient light data: \(dataPoint.lux) lux, Timestamp: \(dataPoint.timestamp)") } } } }
1
0
874
Jul ’26
SensorKit: didFetchResult not being called
Hello, I have an app for a research study that has been approved and authorized to use SensorKit. All my permissions, entitlements and authorizations are in order, but I still can't get any data. The didFetchResult is not being called even though didCompleteFetch is called. I have waited for over 24 hours, but it still returns no samples. Please, I would appreciate any help on this issue. Thank you func sensorReader( _ reader: SRSensorReader, fetchingRequest: SRFetchRequest, didFetchResult result: SRFetchResult<AnyObject> ) { receivedResultsInCurrentFetch = true print("✅ SensorKit fetch result received for: \(sensorKey)") AppLogger.shared.log("SensorKit fetch result received for \(sensorKey)") if let sample = result.sample as? T { print("✅ SensorKit sample matched expected type for \(sensorKey): \(T.self)") AppLogger.shared.log("SensorKit sample matched expected type for \(sensorKey): \(T.self)") processSample(sample) } else { print("❌ SensorKit sample did not match expected type for \(sensorKey): \(T.self)") AppLogger.shared.log("SensorKit sample did not match expected type for \(sensorKey): \(T.self)") } } func sensorReader(_ reader: SRSensorReader, didCompleteFetch request: SRFetchRequest) { if receivedResultsInCurrentFetch, let lastRequestedUpperBound { session.setSensorKitLastFetchTime(lastRequestedUpperBound, for: sensorKey) print("✅ SensorKit fetch completed with samples for \(sensorKey). Checkpoint updated.") } else { print("⚠️ SensorKit fetch completed for \(sensorKey) with no samples.") AppLogger.shared.log("SensorKit fetch completed for \(sensorKey) with no samples. Keeping previous checkpoint so delayed SensorKit data is not skipped.") } isFetchInFlight = false completePendingFetches(success: true) print("✅ SensorKit fetch completed for: \(sensorKey)") AppLogger.shared.log("Fetch request completed for sensor type: \(T.self)") }
1
0
390
Jul ’26
What is supposed to be listed in the Extensions list for File Providers?
In the System Settings > General > Login Items & Extensions - Extensions pane, when I select the By App tab, I can see multiple instances of extensions for different applications and sub-types. e.g. Books (from Apple) is listed twice with the Sharing subtype. For the specific extension I'm checking, I can see multiple instances listed for the File Provider sub-type. The number of instances does not seem to correspond to anything. There are 5 instances listed and it seems like these are not exact duplicates because when I disable one using the (i) dialog, the others are still enabled. This number (5) corresponds to nothing obvious: at one time, there is only 1 instance of the File Provider (a Finder Extension) installed. if I use the pluginkit command line tool to list the extensions, it only reports 3 known versions of this extension. As a developer I'm puzzled by this list with duplicates. As an end user, I'm totally puzzled by this list with duplicates. macOS Tahoe 26.5 (25F71) [Q] What is this list in the Login Items & Extensions pane supposed to represent? Is it known to be buggy when it comes to its contents?
1
0
306
Jul ’26
provider(_:didActivate:) callback intermittently not triggered, causing widespread audio loss for users
Hi everyone, I am facing a critical issue where the CallKit provider delegate method provider(_:didActivate:) is intermittently not triggered. This occasionally results in a total loss of audio during some VoIP calls, while other calls work perfectly fine. Here is the sequence of steps I am currently implementing: Report Incoming Call: The app receives a VoIP push notification and reports the call using reportNewIncomingCall(with:update:completion:). Answer Action: The user taps the answer button, and the app processes the CXAnswerCallAction. Configure Audio Session: Inside the provider delegate, I configure the AVAudioSession category and mode (e.g., setting category to .playAndRecord and mode to .voiceChat). Note: As per Apple's guidelines, I do not call setActive(true) manually, expecting CallKit to activate it automatically. Despite following this standard flow, there are times when provider(_:didActivate:) is skipped entirely, meaning the audio engine fails to initialize for that specific call session. We are currently receiving a large volume of user complaints regarding this issue, as it heavily impacts the core calling experience in production. Could an Apple engineer or anyone from the community look into this? Any insights into what might be causing CallKit to occasionally fail to activate the audio session or how to work around this would be highly appreciated. Thank you!
4
0
594
Jul ’26
Using main.swift entry point for iOS, iPadOS and tvOS platforms
The context is partially expressed in an earlier post. In summary: There is an iOS App target that contains minimal code, only to load a Framework explicitly at runtime using dlopen and dlsym, instead of the usual load-time imports in Apple platforms. For iOS app (C++ (primary) and Swift), the entry point is a UIApplicationDelegate conformer class - AppDelegate, marked with @main. But the problem is, the AppDelegate class cannot remain in the App target, which has barely any logic. The App target is a thin loader. The AppDelegate contains some methods such as application(_:didRegisterForRemoteNotificationsWithDeviceToken:) that needs some logical processing, which is not present in the App target. Instead of using dlsym (to hand over to the Framework) for every AppDelegate event that doesn't have a broadcast notification, the thought was to move the AppDelegate class into the Framework, and the entry point in App target is now main.swift. This keeps the Framework clean and minimal with the following steps: Interop to C++ Explicitly loading the MachO binary inside the Framework using dlopen Loading the symbol using dlsym Invoking the Framework entry point Then, the Framework entry point in C++ creates the UIApplication class and the UIApplicationDelegate using UIApplicationMain(_:_:_:_:) method, which doesn't return as it transfers control to the UIApplicationDelegate. This is against the recommended @main entry point, but based on research, @main seems like syntactic sugar to avoid writing boilerplate code. But in my case, which needs to avoid instantiating the UIApplicationDelegate in the App target, using main.swift, even for an iOS app, is the best fit. I understand that main thread has to be returned back to the OS asap for processing user events etc., and the intent is to not execute the entire startup logic of the app in main thread. Wanted to confirm if this approach of using main.swift entry point is valid for iOS, iPadOS and tvOS apps too and in which case, these flows can converge to macOS, which is already using main.swift approach.
3
0
520
Jul ’26
CMWaterSubmersionManager returns CMErrorDomain code 105
Dear All, I am developing a watchOS app for Apple Watch Ultra that needs to use the Apple depth / water submersion APIs with the entitlement. The app is configured with the shallow depth and pressure entitlement right now, and I have verified that the entitlement is present both in the signed Watch app and in the embedded provisioning profile. App configuration: Platform: watchOS Device: Apple Watch Ultra Entitlement used: com.apple.developer.submerged-shallow-depth-and-pressure = true Info.plist contains: WKSupportsAutomaticDepthLaunch = true WKBackgroundModes includes underwater-depth I verified the built Watch app with: codesign -d --entitlements :- /path/to/WatchApp.app The output contains: com.apple.developer.submerged-shallow-depth-and-pressure I also verified the embedded provisioning profile with: security cms -D -i /path/to/WatchApp.app/embedded.mobileprovision The embedded profile also contains: com.apple.developer.submerged-shallow-depth-and-pressure The built Watch app Info.plist also confirms: WKSupportsAutomaticDepthLaunch = true WKBackgroundModes includes underwater-depth At runtime, my diagnostics show: Requested source: Automatic or Apple Sensor Runtime source: Automatic / Apple Sensor Capability resolved by the app: Shallow Resolved provider: Apple Sensor — Shallow Sample source: Apple Shallow CMWaterSubmersionManager.waterSubmersionAvailable: true Depth automation: available Provider start is called First provider event is received Submersion state: unknown No submersion event is received No depth measurement is received No temperature sample is received Provider state: error Raw error: Domain: CMErrorDomain Code: 105 Description: The operation couldn’t be completed. The relevant runtime failure is: CMErrorDomain 105 The app also does not appear in: Apple Watch Settings → General → Auto-Launch → When Submerged This is the key point that I cannot clarify from the documentation. My questions are: Is the entitlement com.apple.developer.submerged-shallow-depth-and-pressure sufficient for a watchOS app to appear in: Apple Watch Settings → General → Auto-Launch → When Submerged? Is the shallow depth entitlement sufficient to receive runtime events from CMWaterSubmersionManager, including submersion and depth measurements? Or is the full submerged depth entitlement required for: appearing in the “When Submerged” auto-launch list; receiving CMWaterSubmersionManager submersion events; receiving CMWaterSubmersionManager depth measurements? What does CMErrorDomain code 105 mean in the context of CMWaterSubmersionManager? If the shallow entitlement is sufficient, what other conditions could cause CMWaterSubmersionManager to return CMErrorDomain 105 before delivering any submersion or depth samples? To summarize: The shallow entitlement is present in the source entitlements file. The shallow entitlement is present in the signed Watch app. The shallow entitlement is present in the embedded provisioning profile. The built Info.plist contains WKSupportsAutomaticDepthLaunch = true. The built Info.plist contains WKBackgroundModes = underwater-depth. CMWaterSubmersionManager.waterSubmersionAvailable returns true. The app does not appear in the Watch “When Submerged” list. CMWaterSubmersionManager fails with CMErrorDomain 105 before delivering submersion/depth samples. Any help will be strongly appreciated. Thank you.
0
0
296
Jul ’26
I want to measure the time my smartphone has been turned off.
These days, we live our lives completely surrounded by and immersed in smartphones. It seems there isn't a single person among us who isn't. This is because we can find all kinds of information, meet friends, and enjoy our leisure time on our smartphones. However, there is one thing we are overlooking. It is the emotion you will feel toward the people around you as you die on the day you come to pass away. What is that emotion? It is regret. That regret is likely the longing to enjoy physical intimacy, conversation, travel, and everyday life more. That is why I am developing an app with a special feature. I am developing an app that helps users self-regulate and maintain moderation in their smartphone usage—something we are addicted to and love so much, yet often fail to realize that it is poison. This app is designed to encourage mutual moderation and provide rewards. Ironically, this app is designed to operate on the smartphone itself. The reason is that if the smartphone is a tiger's den, then to catch the tiger, one must enter the tiger's den. While conceptualizing and proceeding with development, I encountered a completely insurmountable wall. This is because the iPhone cannot accurately measure the screen-off time. I earnestly hope that if there is a team or developer working on the iPhone framework, you can resolve this issue. If you can extend the extension or take measures to allow access to that data within the SDK, I believe I will be able to complete this app. I look forward to your help.
0
0
262
Jul ’26
WeatherKit REST API returns 401 NOT_ENABLED although App ID and Key are enabled
Title: WeatherKit REST API returns 401 NOT_ENABLED although App ID and WeatherKit key are enabled Body: I am integrating WeatherKit REST API for an iOS app, but every request returns: HTTP 401 {"reason":"NOT_ENABLED"} Configuration summary: The App ID has WeatherKit enabled in App Services. The App ID also has WeatherKit enabled in Capabilities. The WeatherKit key shows WeatherKit enabled in the Keys page. A Service ID has been created. The backend generates an ES256 JWT using the .p8 private key. The decoded JWT header and payload have been verified. I have redacted the actual Team ID, Key ID, Bundle ID, and Service ID here for security reasons. Test A: JWT header.id = TEAM_ID.SERVICE_ID JWT payload.iss = TEAM_ID JWT payload.sub = SERVICE_ID kid = WEATHERKIT_KEY_ID exp - iat = 3600 seconds Result: HTTP 401 {"reason":"NOT_ENABLED"} Test B: JWT header.id = TEAM_ID.BUNDLE_ID JWT payload.iss = TEAM_ID JWT payload.sub = BUNDLE_ID kid = WEATHERKIT_KEY_ID exp - iat = 3600 seconds Result: HTTP 401 {"reason":"NOT_ENABLED"} Since Apple returns NOT_ENABLED instead of INVALID_AUTH_TOKEN, the JWT appears to be structurally accepted, but WeatherKit is not enabled for the authenticated identifier/key combination. Questions: For WeatherKit REST API, should the JWT sub claim use the Service ID or the App Bundle ID? What exactly causes HTTP 401 NOT_ENABLED? Is there any additional WeatherKit REST API enablement required besides enabling WeatherKit on the App ID and creating a WeatherKit key? Could this be an account-side entitlement propagation issue?
1
0
251
Jul ’26
Changing extension name of the Framework bundle
I'm working on a suite of apps supporting macOS, iOS and iPadOS (potentially tvOS, watchOS and visionOS in the future). Each of these App targets contain minimal code to only load the framework dynamically instead of the recommended load-time imports for Apple platforms. The rationales for runtime loading of framework (using dlopen and dlsym) is expressed in earlier post - fyi. Each app can load multiple frameworks at runtime. Instead of naming the frameworks like this - AppName_purpose1.framework, AppName_purpose2.framework, AppName_purpose3.framework, can it be named as AppName.purpose1, AppName.purpose2, AppName.purpose3 etc? Basically, change the Framework bundle extension name from .framework to a custom name based on purpose. The folder's extension name is changed, but it's still a framework bundle. The advantage of this approach is, in my project, Frameworks belonging to each of the apps cleanly distinguish themselves with a concise name. While this post is about Apple platforms, I'm also checking if other platforms allow to change the names of dynamic libraries (windows allows change). Using my custom extension can standardize the dynamic library's extension name across all platforms. Easy framework name construction - The Framework name is now the same as the App bundle name, which can be queried and this string can be appended with an appropriate extension to load all the Frameworks. Is it possible to change the extension name of the Framework bundle from the default .framework? If yes, how?
3
0
477
Jul ’26
Using wildcard for applinks in iOS stopped working
Hi everyone, I've been working on an application that provides different subdomains for different customers, so we need to support app linking with all of them. However, using wildcard notation like applinks:*.domain.com doesn't work, while hardcoding applinks:subdomain.domain.com works fine. The association file is being served from both the main domain and subdomains. It used to work fine about a month ago, and I can't find any recent breaking changes on Apple's side . Any ideas why this could happen. ?
4
0
1.2k
Jul ’26
Applinks for any subdomain not opening the app
My Entitlements file contains the following (removed some non related entries): <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.developer.associated-domains</key> <array> <string>webcredentials:app.mydomain.org</string> <string>applinks:*.mydomain.org</string> </array> </dict> </plist> Now when I tap on a link such as abc.mydomain.org, the app is not opened. If I change the generic applinks key from *.mydomain.org to a specific domain, this works correctly and it opens the app as expected. (This makes me think the website part of the AASA file is correct). Since I need to support a lot of subdomains (think about hundreds in the near future), I really need the wildcard to work. Do you have any tips on how to make this work?
1
0
454
Jul ’26
AASA file on CDN not found more than one week
Last week our Universal Links stopped working. We made some changes and uploaded a new AASA file, but https://app-site-association.cdn-apple.com/a/v1/(domain) still returns 404 Not Found for all our domains. When I query directly from our server like domain/.well-known/apple-app-site-association, it returns 200 and the file is accessible. Could you help us resolve this issue? Our app relies on working Universal Links (deep links). Thank you!
1
0
379
Jul ’26
Declared Age Range API – Clarification on checkEligibility() behavior (eligibility vs region)
Hello, While reviewing the latest FAQ and documentation for the Declared Age Range API, we have some questions regarding the behavior of checkEligibility()—specifically how it relates to user eligibility, geographic jurisdiction, and regulatory requirements. Context From the documentation, it appears that checkEligibility() indicates whether a user is eligible to share their declared age range. However, it is unclear whether this eligibility also incorporates jurisdiction-specific requirements (e.g., certain U.S. states with age assurance regulations). We would appreciate clarification on the following points: Eligibility vs Region: Does checkEligibility() return true based on the user’s eligibility to share age information only, or does it also depend on the user’s geographic region (e.g., specific U.S. states like Texas)? Region-Specific Laws (Texas Example): In scenarios where certain jurisdictions (such as Texas) require age assurance features, while other U.S. states may not, how does checkEligibility() behave? User Consent vs Regulatory Requirement: If a user denies age sharing, but they are located in a region where age-related regulatory features are mandated, how does checkEligibility() behave? Will it return false because the user denied consent? Or will it still return true due to regulatory requirements overriding user preference? Source of Region Determination: Does the Declared Age Range API internally determine the user’s applicable region (e.g., based on IP address, Apple ID region, or device settings) when evaluating checkEligibility()? Should developers independently determine jurisdiction (e.g., using IP-based geolocation) to apply region-specific rules, or is checkEligibility() intended to fully abstract both eligibility and jurisdiction requirements?
1
1
439
Jul ’26
DeclaredAgeRange API not triggering in regulated regions (Brazil, Utah) — Is it functioning in production?
Hi, We've implemented age assurance logic in our app using the DeclaredAgeRange framework to comply with regulations in Brazil (Digital ECA, effective March 17, 2026) and Utah (App Store Accountability Act, effective May 6, 2026). Our implementation calls AgeRangeService.shared.isEligibleForAgeFeatures on app launch to determine whether the current user is subject to age assurance requirements, and proceeds to call requestAgeRange(ageGates:) accordingly. However, after monitoring in production since the Brazil enforcement date, we've consistently observed isEligibleForAgeFeatures returning false for users in regulated regions, with no age range data being returned. What we'd like to clarify: Is isEligibleForAgeFeatures currently returning true for users in Brazil in production (not sandbox)? For Utah — given that HB 498 pushed the developer compliance deadline to May 6, 2027, will isEligibleForAgeFeatures reflect the original May 6, 2026 activation date or the revised 2027 date? Is there a known rollout schedule or gradual activation plan for these regions that would explain why the flag remains false even after the legal enforcement dates have passed? We've seen similar reports from other developers on these forums, so it seems this may be a widespread issue rather than an implementation problem on our end. Any official guidance on the current status of the API in regulated regions would be greatly appreciated. Thanks.
1
1
740
Jul ’26
Shallow Depth Entitlement and Underwater Auto-Launch: App Not Appearing in "When Submerged"
I've a question for you maybe you can help me. My watchOS app has: WKSupportsAutomaticDepthLaunch = true WKBackgroundModes = underwater-depth com.apple.developer.submerged-shallow-depth-and-pressure = true entitlement present in codesign and embedded provisioning profile The app uses the shallow depth entitlement, but it does not appear in: Settings → General → Auto-Launch → When Submerged. Is the shallow depth entitlement sufficient for appearing in the system underwater auto-launch app list, or is the full submerged depth entitlement required?
0
0
270
Jul ’26
PushToTalk session sometimes returns silence data after activation
Hello! Thank you for bringing the new iPhone experience with the PushToTalk framework. I have a working walkie talkie app based on the PushToTalk framework. Everything works fine except for an intermittent bug that I face from time to time on different devices with different iOS versions, from iOS 18 to iOS 26.2 Beta. Sometimes the app goes into a state where the AVAudioInputNode input node tap returns buffers with a constant size that contain only silence. Leaving and rejoining a channel helps, but relaunching or reinstalling (from Xcode) the app does not. Rebooting the device or deleting and reinstalling the app also helps. I do not activate the audio session in my app. I only configure it on launch using setCategory(.playAndRecord, options: [.defaultToSpeaker, .allowBluetooth]) So the flow is: channelManager?.requestBeginTransmitting(channelUUID: globalChannelUUID) func channelManager( _ channelManager: PTChannelManager, channelUUID: UUID, didBeginTransmittingFrom source: PTChannelTransmitRequestSource ) func channelManager( _ channelManager: PTChannelManager, didActivate audioSession: AVAudioSession ) { /// ... installTapAndStart() } private func installTapAndStart() { let inputNode = audioEngine.inputNode let hardwareFormat = inputNode.outputFormat(forBus: 0) guard let targetFormat = AVAudioFormat( commonFormat: .pcmFormatFloat32, sampleRate: configuration.audioSampleRate, channels: configuration.audioChannelsCount, interleaved: true ) else { handleError(RecorderError.invalidAudioFormat) return } let converter = AVAudioConverter(from: hardwareFormat, to: targetFormat)! print("[QUICOpusRecorder]: installTap") inputNode.installTap(onBus: 0, bufferSize: tapBufferSize, format: hardwareFormat) { [weak self] buffer, _ in guard let self else { return } // Here I handle audio data and sometimes get silence } //... do { audioEngine.prepare() try audioEngine.start() } catch { print(" ⚠️ Audio engine start error: \(error)") handleError(error) } } Moreover, if the app is in the foreground and PushToTalk gets stuck in this “silence bug”, I can avoid relying on the PushToTalk flow and simulate audio session activation manually in code. In this case I do not request a transmission and do not use any PushToTalk related code, and the app captures audio data perfectly. Once I leave the channel and rejoin it again, the issue is fixed and I start to receive non silent buffers of varying size, as expected. It works for a while. It can work fine for a day or more, communicating without launching the app, or with the app in the foreground. But it can also go into the “silence” state 30 minutes after working normally. I have no clue why this happens. The only thing I notice is that when the app is in this “stuck silence bug” state, iOS does not play its “chirp” system sound when audio recording starts. P.S. Channel descriptor restoration code: extension PushToTalkEngine: PTChannelRestorationDelegate { public func channelDescriptor(restoredChannelUUID channelUUID: UUID) -> PTChannelDescriptor { print("☀️ \(#function) channelUUID: \(channelUUID)") Task { @MainActor in // Here I fetch more detailed channel data asynchronously do { await initChannelManagerIfNeeded(channelUUID: channelUUID) let channelDescriptor = currentChannelDescriptor() lastChannelDescriptorName = channelDescriptor.name try await channelManager?.setChannelDescriptor( channelDescriptor, channelUUID: channelUUID ) } catch { handleError(error) } } return PTChannelDescriptor(name: "Loading...", image: nil) } } private func initChannelManagerIfNeeded(channelUUID: UUID? = nil) async { guard let channelUUID = channelUUID ?? currentUser?.globalChannelUUID else { print("❌ No global channel uuid found") return } do { guard channelManager == nil else { try await channelManager?.setTransmissionMode(.halfDuplex, channelUUID: channelUUID) return } channelManager = try await PTChannelManager.channelManager( delegate: self, restorationDelegate: self ) try await channelManager?.setTransmissionMode(.halfDuplex, channelUUID: channelUUID) } catch { handleError(error) } }
3
0
1.1k
Jul ’26
Understanding Crash Reporter Extension lifecycle and debugging behavior
Hi! I have a few questions about the lifecycle and capabilities of the Crash Reporter Extension. Besides using the corpsePort to inspect the crashed process through Mach APIs, is it safe/supported/recommended for the extension to access files in a shared App Group container? Are there any caveats or exceptions we should be aware of, for example around memory-mapped files, file coordination, or filesystem access after the host app has crashed? Shall we use some particular APIs for this kind of shared resource or not? While debugging the extension, I noticed that when I trigger a crash in the app I am debugging, LLDB does not stop inside the extension (it also ends up stopping the debugging session). However, I can observe that the extension does run, because it writes data into a shared App Group directory related to the crash. Is this expected behavior? Is there a recommended way to debug the Crash Reporter Extension reliably (with lldb, or other way)? More generally, I would like to better understand the extension lifecycle: When exactly does the extension start running? How long can it live after the app crashes? Is there a time limit for operating on the corpse process? Is the extension subject to resource limits similar to other app extensions, such as memory, disk, CPU, watchdog, or jetsam constraints? If the Crash Reporter Extension itself crashes, how can we detect that? Would those crashes appear in Xcode Organizer, or is there another recommended way to observe them? Any clarification around the supported lifecycle, debugging model, and resource limits would be very useful.
4
1
604
Jun ’26
AlertConfiguration.AlertSound.named plays system default despite CAF in main bundle (AlarmKit, iOS 26.5)
We need an official answer: wrong wiring, known bug on 26.5, or unsupported? AlertConfiguration.AlertSound.default works. AlertConfiguration.AlertSound.named("lifeloop_alarm_silent") schedules successfully (Stop/Snooze UI, no API error) but playback is always system default — never our bundled CAF. OFFICIAL API WE FOLLOW Documentation: AlertConfiguration.AlertSound.named(:) https://developer.apple.com/documentation/activitykit/alertconfiguration/alertsound/named(:) "The name of the sound file to use for the alert. Choose a file that's in your app's main bundle or the Library/Sounds folder of your app's data container." WWDC25 session 230 shows: let sound = AlertConfiguration.AlertSound.named("Chime") with the file in the main bundle. We use: AlertConfiguration.AlertSound.named("lifeloop_alarm_silent") Our Swift schedules with AlarmManager.AlarmConfiguration.alarm(..., sound: alertSound). REFERENCES WE ALREADY READ AlarmConfiguration overview: https://developer.apple.com/documentation/alarmkit/alarmmanager/alarmconfiguration Albert Pascual DTS reply (Feb 2026) on this thread pointed at nested alertConfiguration with sound AlarmKit FAQ: https://developer.apple.com/forums/thread/797158 Older forum reply (~2025): claimed .named("Glass Drum.caf") worked — not verified on 26.5 today On iOS 26.5: Bundle.main finds our file with AND without ".caf" in the lookup string; playback still system default OUR WIRING (please confirm correct or tell us what to change) We schedule fixed-time dose alarms with: AlarmManager.AlarmConfiguration.alarm( schedule: .fixed(fireDate), attributes: attributes, stopIntent: stopIntent, secondaryIntent: snoozeIntent, sound: alertSound) .default on this parameter works. .named("lifeloop_alarm_silent") does not — despite Bundle.main finding the file (proof below). Question: Is sound: on .alarm(...) correct for custom AlertSound.named, or must sound go in nested AlertConfiguration(title:body:sound:) as in the overview example? WHAT WE HEAR ON DEVICE sound = .default → loud system alarm (works) sound = .named("lifeloop_alarm_silent") → same loud system/default every time No API error — silent fallback to default PROOF 1 — FILE IN SHIPPED IPA $ find Payload -name "lifeloop_alarm_*.caf" Payload/LifeLoop.app/lifeloop_alarm_silent.caf PROOF 2 — RUNTIME ON DEVICE (2026-06-30, iOS 26.5) Bundle.main.url(forResource:withExtension:): FOUND Bundle.main.url(full filename in name): FOUND Path: .../LifeLoop.app/lifeloop_alarm_silent.caf All .caf in main bundle: lifeloop_alarm_silent.caf Library/Sounds: (none) Widget .appex .caf: (none) Native log at schedule: [alarmkit] build_config · soundModeRaw=silent alertSound=named:lifeloop_alarm_silent silentCafInBundle=true [alarmkit] schedule_ok · alarmID=FBDF2082-61F1-4C93-8B20-094A60EA8626 CAF: lifeloop_alarm_silent.caf — mono, 44100 Hz, 16-bit PCM, ~0.5 s QUESTIONS FOR DTS Main app bundle only, or must CAF also be in widget .appex? Must named(_:) include ".caf" or base name only? Bundle.main FOUND at schedule time but playback is default — known bug on 26.5? Please answer: (A) wrong wiring + correct recipe, (B) known bug + fix version, or (C) not supported — please document. Thank you. Same problem as tonny00 — custom CAF never plays, always the loud system/default alarm. App: LifeLoop (com.stujacks.lifeloop) on iOS 26.5 (physical device). https://developer.apple.com/forums/thread/814732
1
0
216
Jun ’26
Clarification on Screen Time API capabilities for per-child and per-device activity reports
Hello, I am developing a parental control app using FamilyControls, DeviceActivity, and DeviceActivityReport. My current setup is: The child device requests FamilyControls authorization with .child The parent device requests FamilyControls authorization with .individual The parent app displays reports through a DeviceActivityReportExtension The report filter uses users: .children and devices: .all I would like to clarify two questions: Can a third-party app use the Screen Time API to retrieve or display screen time activity per child or per child device from the parent app? For example: Child A's total screen time today Child A's iPhone screen time today Child A's iPad screen time today At the moment, I can only display an aggregated report using users: .children and devices: .all. I do not see a public API for selecting a specific child or a specific child device. Is this a current limitation of the public Screen Time API, or is there a recommended approach to implement this? Can the Screen Time API report activity data for family members aged 14-17? Specifically, if a family member is between 14 and 17 years old and their device has completed .child authorization, can the parent app still display their Screen Time data using DeviceActivityReport(users: .children)? Or are there restrictions related to Apple ID age, Family Sharing, or Screen Time permissions that prevent third-party apps from retrieving or displaying activity data for users in this age range? My goal is to understand what third-party apps can implement in a compliant way using the public APIs, without attempting to bypass any system limitations. Thank you.
0
0
205
Jun ’26
iOS 26.4 — How to return from main app to host app after a keyboard-extension dictation round-trip, without private APIs?
I'm building a custom keyboard extension that offers voice dictation. Because keyboard extensions are constrained (memory cap ~30–48 MB, restricted audio session access), I delegate recording to my container app: User in a host app (e.g., Safari) taps the mic in my keyboard extension. The keyboard calls extensionContext.open(URL("myapp://dictation")) to launch the container app. The container app records audio via AVAudioEngine + SFSpeechRecognizer, writes the final transcript to the App Group, and signals completion via a Darwin notification. 4. The user is expected to be returned to the original host app (Safari) automatically so they can keep typing. The problem (step 4): On iOS 26.4 I can no longer identify which app was the host. Every previously-known path returns nil for the keyboard extension's host: parent.value(forKey: "_hostBundleID") → returns the literal string parent.value(forKey: "_hostApplicationBundleIdentifier") → returns NSNull xpc_connection_copy_bundle_id on the underlying XPC connection (via PKService.defaultService.personalities[…]) → returns NULL NSXPCConnection.processBundleIdentifier on extensionContext._extensionHostProxy._connection → returns nil proc_pidpath(hostPID, …) → EPERM from the keyboard sandbox LSApplicationWorkspace.frontmostApplication → selector unavailable from the extension RBSProcessHandle.handleForIdentifier:error: → returns an RBSServiceErrorDomain error Without the host's bundle ID, the container app has no way to call LSApplicationWorkspace.openApplicationWithBundleID: (the technique that worked on iOS 25 and earlier). UIApplication.suspend() correctly sends the container to background, but iOS treats us as a "fresh launch" — it returns the user to the Home Screen instead of Safari, because the container app was launched by an extension, not directly by Safari. KeyboardKit's maintainer reached the same conclusion (issue #1014) and shipped 10.4 without the feature. My questions: Is there a public, App-Store-safe API in iOS 26+ for a custom keyboard extension to identify its host application, or for the container app (launched via the extension's openURL) to identify which app initially hosted the extension that opened it? UIOpenURLContext.options.sourceApplication reports the extension's own container, not the actual host. 2. Is there a public mechanism for "return to source app" when the container app was launched by an extension's openURL? Equivalent to the ← Source affordance iOS shows for normal inter-app openURL, but triggered programmatically by the launched app. 3. Some popular keyboards (e.g., 微信输入法 / WeChat Keyboard) still appear to round-trip through their container app on iOS 26.4 and return the user to the original host — including the iOS ← WeChat back affordance in the host's status bar afterward. What's the recommended approach to achieve this? If it requires a specific scene-activation flow, NSUserActivity pattern, or extension-context configuration, please point at the relevant docs. 4. If there is no public path today, is FB22247647 (or a related radar) the right place to track this? Should developers in this position migrate to in-extension audio capture (which has its own significant constraints in keyboard extensions)? I'd much rather not rely on private APIs. Concrete guidance — or even an acknowledgment of which direction Apple intends — would help thousands of custom-keyboard developers who currently have a degraded voice-input experience on iOS 26.4+. Tested on iPhone 12 Pro Max running iOS 26.4.2 (build 23E261), Xcode 26.x, Swift 5. Thanks!
3
0
950
Jun ’26
Problems with SensorKit data calls
The Deligate 'didFetchResult' method of fetching data past 24 hours from SensorKit is not being called. It is confirmed that you have already granted full access to the SensorKit and that data on the Ambient value in the device's personal information -> research sensor & usage data are recorded. It is possible to export to an lz4 file. I want to have the data after 24 hours called to the app, but other Deligate methods are called, but only Deligate that gets the illumination value is not called. Is it understood that only data past 24 hours can be imported after startRecoding() is called? If so, in order to receive data past 24 hours, do I have to continue to receive the illumination data value in the background for more than 24 hours to receive the Ambient value afterwards? import Foundation import SensorKit import UIKit final class SensorKitManager: NSObject, ObservableObject, SRSensorReaderDelegate { static let shared = SensorKitManager() private let ambientReader = SRSensorReader(sensor: .ambientLightSensor) var availableDevices: [SRDevice] = [] @Published var ambientLightData: [AmbientLightDataPoint] = [] var isFetching = false var isRecordingAmbientLight = false private override init() { super.init() setupReaders() checkAndRequestAuthorization() } private func setupReaders() { ambientReader.delegate = self } // MARK: - Permission Request func requestAuthorization() { SRSensorReader.requestAuthorization(sensors: [.ambientLightSensor]) { [weak self] error in DispatchQueue.main.async { guard let self = self else { print("Permission request aborted") return } if let error = error { print("Permission request failed: \(error.localizedDescription)") } else { print("Permission request succeeded") self.startRecordingAmbientLightData() } } } } func checkAndRequestAuthorization() { let status = ambientReader.authorizationStatus switch status { case .authorized: print("Ambient light sensor access granted") startRecordingAmbientLightData() case .notDetermined: print("Ambient light sensor access undetermined, requesting permission") requestAuthorization() case .denied: print("Ambient light sensor access denied or restricted") @unknown default: print("Unknown authorization status") } } // MARK: - Ambient Light Data Logic func startRecordingAmbientLightData() { guard !isRecordingAmbientLight else { print("Already recording ambient light data.") return } print("Starting ambient light data recording") isRecordingAmbientLight = true ambientReader.startRecording() fetchAmbientLightData() fetchAmbientDeviceData() } func fetchAmbientLightData() { print("Fetching ambient light data") let request = SRFetchRequest() let now = Date() let fromTime = now.addingTimeInterval(-72 * 60 * 60) let toTime = now.addingTimeInterval(-25 * 60 * 60) request.from = SRAbsoluteTime(fromTime.timeIntervalSinceReferenceDate) request.to = SRAbsoluteTime(toTime.timeIntervalSinceReferenceDate) print("Fetch request: \(fromTime) ~ \(toTime)") ambientReader.fetch(request) } private func displayAmbientLightData(sample: SRAmbientLightSample) { print("Ambient light: \(sample.lux.value) lux") print("Current ambientLightData content:") for data in ambientLightData { print("Timestamp: \(data.timestamp), Lux: \(data.lux)") } } // MARK: - Device Data Logic private func fetchAmbientDeviceData() { print("Fetching device information") let request = SRFetchRequest() let now = Date() let fromDate = now.addingTimeInterval(-72 * 60 * 60) let toDate = now.addingTimeInterval(-24 * 60 * 60) request.from = SRAbsoluteTime(fromDate.timeIntervalSinceReferenceDate) request.to = SRAbsoluteTime(toDate.timeIntervalSinceReferenceDate) if availableDevices.isEmpty { print("No devices available") ambientReader.fetchDevices() } else { for device in availableDevices { print("Starting data fetch (Device: \(device))") request.device = device ambientReader.fetch(request) print("Fetch request sent (Device: \(device))") } } } // MARK: - SRSensorReaderDelegate Methods func sensorReader(_ reader: SRSensorReader, didFetch devices: [SRDevice]) { availableDevices = devices for device in devices { print("Fetched device: \(device)") } if !devices.isEmpty { fetchAmbientDeviceData() } } func sensorReader(_ reader: SRSensorReader, fetching fetchRequest: SRFetchRequest, didFetchResult result: SRFetchResult<AnyObject>) -> Bool { print("sensorReader(_:fetching:didFetchResult:) method called") if let ambientSample = result.sample as? SRAmbientLightSample { let luxValue = ambientSample.lux.value let timestamp = Date(timeIntervalSinceReferenceDate: result.timestamp.rawValue) // Check for duplicate data and add it if !ambientLightData.contains(where: { $0.timestamp == timestamp }) { let dataPoint = AmbientLightDataPoint(timestamp: timestamp, lux: Float(luxValue)) ambientLightData.append(dataPoint) print("Added ambient light data: \(luxValue) lux, Timestamp: \(timestamp)") } else { print("Duplicate data, not adding: Timestamp: \(timestamp)") } // Output data self.displayAmbientLightData(sample: ambientSample) } return true } func sensorReader(_ reader: SRSensorReader, didCompleteFetch fetchRequest: SRFetchRequest) { print("Data fetch complete") if ambientLightData.isEmpty { print("No ambient light data within 24 hours.") } else { print("ambientLightData updated") for dataPoint in ambientLightData { print("Added ambient light data: \(dataPoint.lux) lux, Timestamp: \(dataPoint.timestamp)") } } } }
Replies
1
Boosts
0
Views
874
Activity
Jul ’26
SensorKit: didFetchResult not being called
Hello, I have an app for a research study that has been approved and authorized to use SensorKit. All my permissions, entitlements and authorizations are in order, but I still can't get any data. The didFetchResult is not being called even though didCompleteFetch is called. I have waited for over 24 hours, but it still returns no samples. Please, I would appreciate any help on this issue. Thank you func sensorReader( _ reader: SRSensorReader, fetchingRequest: SRFetchRequest, didFetchResult result: SRFetchResult<AnyObject> ) { receivedResultsInCurrentFetch = true print("✅ SensorKit fetch result received for: \(sensorKey)") AppLogger.shared.log("SensorKit fetch result received for \(sensorKey)") if let sample = result.sample as? T { print("✅ SensorKit sample matched expected type for \(sensorKey): \(T.self)") AppLogger.shared.log("SensorKit sample matched expected type for \(sensorKey): \(T.self)") processSample(sample) } else { print("❌ SensorKit sample did not match expected type for \(sensorKey): \(T.self)") AppLogger.shared.log("SensorKit sample did not match expected type for \(sensorKey): \(T.self)") } } func sensorReader(_ reader: SRSensorReader, didCompleteFetch request: SRFetchRequest) { if receivedResultsInCurrentFetch, let lastRequestedUpperBound { session.setSensorKitLastFetchTime(lastRequestedUpperBound, for: sensorKey) print("✅ SensorKit fetch completed with samples for \(sensorKey). Checkpoint updated.") } else { print("⚠️ SensorKit fetch completed for \(sensorKey) with no samples.") AppLogger.shared.log("SensorKit fetch completed for \(sensorKey) with no samples. Keeping previous checkpoint so delayed SensorKit data is not skipped.") } isFetchInFlight = false completePendingFetches(success: true) print("✅ SensorKit fetch completed for: \(sensorKey)") AppLogger.shared.log("Fetch request completed for sensor type: \(T.self)") }
Replies
1
Boosts
0
Views
390
Activity
Jul ’26
What is supposed to be listed in the Extensions list for File Providers?
In the System Settings > General > Login Items & Extensions - Extensions pane, when I select the By App tab, I can see multiple instances of extensions for different applications and sub-types. e.g. Books (from Apple) is listed twice with the Sharing subtype. For the specific extension I'm checking, I can see multiple instances listed for the File Provider sub-type. The number of instances does not seem to correspond to anything. There are 5 instances listed and it seems like these are not exact duplicates because when I disable one using the (i) dialog, the others are still enabled. This number (5) corresponds to nothing obvious: at one time, there is only 1 instance of the File Provider (a Finder Extension) installed. if I use the pluginkit command line tool to list the extensions, it only reports 3 known versions of this extension. As a developer I'm puzzled by this list with duplicates. As an end user, I'm totally puzzled by this list with duplicates. macOS Tahoe 26.5 (25F71) [Q] What is this list in the Login Items & Extensions pane supposed to represent? Is it known to be buggy when it comes to its contents?
Replies
1
Boosts
0
Views
306
Activity
Jul ’26
provider(_:didActivate:) callback intermittently not triggered, causing widespread audio loss for users
Hi everyone, I am facing a critical issue where the CallKit provider delegate method provider(_:didActivate:) is intermittently not triggered. This occasionally results in a total loss of audio during some VoIP calls, while other calls work perfectly fine. Here is the sequence of steps I am currently implementing: Report Incoming Call: The app receives a VoIP push notification and reports the call using reportNewIncomingCall(with:update:completion:). Answer Action: The user taps the answer button, and the app processes the CXAnswerCallAction. Configure Audio Session: Inside the provider delegate, I configure the AVAudioSession category and mode (e.g., setting category to .playAndRecord and mode to .voiceChat). Note: As per Apple's guidelines, I do not call setActive(true) manually, expecting CallKit to activate it automatically. Despite following this standard flow, there are times when provider(_:didActivate:) is skipped entirely, meaning the audio engine fails to initialize for that specific call session. We are currently receiving a large volume of user complaints regarding this issue, as it heavily impacts the core calling experience in production. Could an Apple engineer or anyone from the community look into this? Any insights into what might be causing CallKit to occasionally fail to activate the audio session or how to work around this would be highly appreciated. Thank you!
Replies
4
Boosts
0
Views
594
Activity
Jul ’26
Using main.swift entry point for iOS, iPadOS and tvOS platforms
The context is partially expressed in an earlier post. In summary: There is an iOS App target that contains minimal code, only to load a Framework explicitly at runtime using dlopen and dlsym, instead of the usual load-time imports in Apple platforms. For iOS app (C++ (primary) and Swift), the entry point is a UIApplicationDelegate conformer class - AppDelegate, marked with @main. But the problem is, the AppDelegate class cannot remain in the App target, which has barely any logic. The App target is a thin loader. The AppDelegate contains some methods such as application(_:didRegisterForRemoteNotificationsWithDeviceToken:) that needs some logical processing, which is not present in the App target. Instead of using dlsym (to hand over to the Framework) for every AppDelegate event that doesn't have a broadcast notification, the thought was to move the AppDelegate class into the Framework, and the entry point in App target is now main.swift. This keeps the Framework clean and minimal with the following steps: Interop to C++ Explicitly loading the MachO binary inside the Framework using dlopen Loading the symbol using dlsym Invoking the Framework entry point Then, the Framework entry point in C++ creates the UIApplication class and the UIApplicationDelegate using UIApplicationMain(_:_:_:_:) method, which doesn't return as it transfers control to the UIApplicationDelegate. This is against the recommended @main entry point, but based on research, @main seems like syntactic sugar to avoid writing boilerplate code. But in my case, which needs to avoid instantiating the UIApplicationDelegate in the App target, using main.swift, even for an iOS app, is the best fit. I understand that main thread has to be returned back to the OS asap for processing user events etc., and the intent is to not execute the entire startup logic of the app in main thread. Wanted to confirm if this approach of using main.swift entry point is valid for iOS, iPadOS and tvOS apps too and in which case, these flows can converge to macOS, which is already using main.swift approach.
Replies
3
Boosts
0
Views
520
Activity
Jul ’26
CMWaterSubmersionManager returns CMErrorDomain code 105
Dear All, I am developing a watchOS app for Apple Watch Ultra that needs to use the Apple depth / water submersion APIs with the entitlement. The app is configured with the shallow depth and pressure entitlement right now, and I have verified that the entitlement is present both in the signed Watch app and in the embedded provisioning profile. App configuration: Platform: watchOS Device: Apple Watch Ultra Entitlement used: com.apple.developer.submerged-shallow-depth-and-pressure = true Info.plist contains: WKSupportsAutomaticDepthLaunch = true WKBackgroundModes includes underwater-depth I verified the built Watch app with: codesign -d --entitlements :- /path/to/WatchApp.app The output contains: com.apple.developer.submerged-shallow-depth-and-pressure I also verified the embedded provisioning profile with: security cms -D -i /path/to/WatchApp.app/embedded.mobileprovision The embedded profile also contains: com.apple.developer.submerged-shallow-depth-and-pressure The built Watch app Info.plist also confirms: WKSupportsAutomaticDepthLaunch = true WKBackgroundModes includes underwater-depth At runtime, my diagnostics show: Requested source: Automatic or Apple Sensor Runtime source: Automatic / Apple Sensor Capability resolved by the app: Shallow Resolved provider: Apple Sensor — Shallow Sample source: Apple Shallow CMWaterSubmersionManager.waterSubmersionAvailable: true Depth automation: available Provider start is called First provider event is received Submersion state: unknown No submersion event is received No depth measurement is received No temperature sample is received Provider state: error Raw error: Domain: CMErrorDomain Code: 105 Description: The operation couldn’t be completed. The relevant runtime failure is: CMErrorDomain 105 The app also does not appear in: Apple Watch Settings → General → Auto-Launch → When Submerged This is the key point that I cannot clarify from the documentation. My questions are: Is the entitlement com.apple.developer.submerged-shallow-depth-and-pressure sufficient for a watchOS app to appear in: Apple Watch Settings → General → Auto-Launch → When Submerged? Is the shallow depth entitlement sufficient to receive runtime events from CMWaterSubmersionManager, including submersion and depth measurements? Or is the full submerged depth entitlement required for: appearing in the “When Submerged” auto-launch list; receiving CMWaterSubmersionManager submersion events; receiving CMWaterSubmersionManager depth measurements? What does CMErrorDomain code 105 mean in the context of CMWaterSubmersionManager? If the shallow entitlement is sufficient, what other conditions could cause CMWaterSubmersionManager to return CMErrorDomain 105 before delivering any submersion or depth samples? To summarize: The shallow entitlement is present in the source entitlements file. The shallow entitlement is present in the signed Watch app. The shallow entitlement is present in the embedded provisioning profile. The built Info.plist contains WKSupportsAutomaticDepthLaunch = true. The built Info.plist contains WKBackgroundModes = underwater-depth. CMWaterSubmersionManager.waterSubmersionAvailable returns true. The app does not appear in the Watch “When Submerged” list. CMWaterSubmersionManager fails with CMErrorDomain 105 before delivering submersion/depth samples. Any help will be strongly appreciated. Thank you.
Replies
0
Boosts
0
Views
296
Activity
Jul ’26
I want to measure the time my smartphone has been turned off.
These days, we live our lives completely surrounded by and immersed in smartphones. It seems there isn't a single person among us who isn't. This is because we can find all kinds of information, meet friends, and enjoy our leisure time on our smartphones. However, there is one thing we are overlooking. It is the emotion you will feel toward the people around you as you die on the day you come to pass away. What is that emotion? It is regret. That regret is likely the longing to enjoy physical intimacy, conversation, travel, and everyday life more. That is why I am developing an app with a special feature. I am developing an app that helps users self-regulate and maintain moderation in their smartphone usage—something we are addicted to and love so much, yet often fail to realize that it is poison. This app is designed to encourage mutual moderation and provide rewards. Ironically, this app is designed to operate on the smartphone itself. The reason is that if the smartphone is a tiger's den, then to catch the tiger, one must enter the tiger's den. While conceptualizing and proceeding with development, I encountered a completely insurmountable wall. This is because the iPhone cannot accurately measure the screen-off time. I earnestly hope that if there is a team or developer working on the iPhone framework, you can resolve this issue. If you can extend the extension or take measures to allow access to that data within the SDK, I believe I will be able to complete this app. I look forward to your help.
Replies
0
Boosts
0
Views
262
Activity
Jul ’26
WeatherKit REST API returns 401 NOT_ENABLED although App ID and Key are enabled
Title: WeatherKit REST API returns 401 NOT_ENABLED although App ID and WeatherKit key are enabled Body: I am integrating WeatherKit REST API for an iOS app, but every request returns: HTTP 401 {"reason":"NOT_ENABLED"} Configuration summary: The App ID has WeatherKit enabled in App Services. The App ID also has WeatherKit enabled in Capabilities. The WeatherKit key shows WeatherKit enabled in the Keys page. A Service ID has been created. The backend generates an ES256 JWT using the .p8 private key. The decoded JWT header and payload have been verified. I have redacted the actual Team ID, Key ID, Bundle ID, and Service ID here for security reasons. Test A: JWT header.id = TEAM_ID.SERVICE_ID JWT payload.iss = TEAM_ID JWT payload.sub = SERVICE_ID kid = WEATHERKIT_KEY_ID exp - iat = 3600 seconds Result: HTTP 401 {"reason":"NOT_ENABLED"} Test B: JWT header.id = TEAM_ID.BUNDLE_ID JWT payload.iss = TEAM_ID JWT payload.sub = BUNDLE_ID kid = WEATHERKIT_KEY_ID exp - iat = 3600 seconds Result: HTTP 401 {"reason":"NOT_ENABLED"} Since Apple returns NOT_ENABLED instead of INVALID_AUTH_TOKEN, the JWT appears to be structurally accepted, but WeatherKit is not enabled for the authenticated identifier/key combination. Questions: For WeatherKit REST API, should the JWT sub claim use the Service ID or the App Bundle ID? What exactly causes HTTP 401 NOT_ENABLED? Is there any additional WeatherKit REST API enablement required besides enabling WeatherKit on the App ID and creating a WeatherKit key? Could this be an account-side entitlement propagation issue?
Replies
1
Boosts
0
Views
251
Activity
Jul ’26
Changing extension name of the Framework bundle
I'm working on a suite of apps supporting macOS, iOS and iPadOS (potentially tvOS, watchOS and visionOS in the future). Each of these App targets contain minimal code to only load the framework dynamically instead of the recommended load-time imports for Apple platforms. The rationales for runtime loading of framework (using dlopen and dlsym) is expressed in earlier post - fyi. Each app can load multiple frameworks at runtime. Instead of naming the frameworks like this - AppName_purpose1.framework, AppName_purpose2.framework, AppName_purpose3.framework, can it be named as AppName.purpose1, AppName.purpose2, AppName.purpose3 etc? Basically, change the Framework bundle extension name from .framework to a custom name based on purpose. The folder's extension name is changed, but it's still a framework bundle. The advantage of this approach is, in my project, Frameworks belonging to each of the apps cleanly distinguish themselves with a concise name. While this post is about Apple platforms, I'm also checking if other platforms allow to change the names of dynamic libraries (windows allows change). Using my custom extension can standardize the dynamic library's extension name across all platforms. Easy framework name construction - The Framework name is now the same as the App bundle name, which can be queried and this string can be appended with an appropriate extension to load all the Frameworks. Is it possible to change the extension name of the Framework bundle from the default .framework? If yes, how?
Replies
3
Boosts
0
Views
477
Activity
Jul ’26
Using wildcard for applinks in iOS stopped working
Hi everyone, I've been working on an application that provides different subdomains for different customers, so we need to support app linking with all of them. However, using wildcard notation like applinks:*.domain.com doesn't work, while hardcoding applinks:subdomain.domain.com works fine. The association file is being served from both the main domain and subdomains. It used to work fine about a month ago, and I can't find any recent breaking changes on Apple's side . Any ideas why this could happen. ?
Replies
4
Boosts
0
Views
1.2k
Activity
Jul ’26
Applinks for any subdomain not opening the app
My Entitlements file contains the following (removed some non related entries): <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>com.apple.developer.associated-domains</key> <array> <string>webcredentials:app.mydomain.org</string> <string>applinks:*.mydomain.org</string> </array> </dict> </plist> Now when I tap on a link such as abc.mydomain.org, the app is not opened. If I change the generic applinks key from *.mydomain.org to a specific domain, this works correctly and it opens the app as expected. (This makes me think the website part of the AASA file is correct). Since I need to support a lot of subdomains (think about hundreds in the near future), I really need the wildcard to work. Do you have any tips on how to make this work?
Replies
1
Boosts
0
Views
454
Activity
Jul ’26
AASA file on CDN not found more than one week
Last week our Universal Links stopped working. We made some changes and uploaded a new AASA file, but https://app-site-association.cdn-apple.com/a/v1/(domain) still returns 404 Not Found for all our domains. When I query directly from our server like domain/.well-known/apple-app-site-association, it returns 200 and the file is accessible. Could you help us resolve this issue? Our app relies on working Universal Links (deep links). Thank you!
Replies
1
Boosts
0
Views
379
Activity
Jul ’26
Declared Age Range API – Clarification on checkEligibility() behavior (eligibility vs region)
Hello, While reviewing the latest FAQ and documentation for the Declared Age Range API, we have some questions regarding the behavior of checkEligibility()—specifically how it relates to user eligibility, geographic jurisdiction, and regulatory requirements. Context From the documentation, it appears that checkEligibility() indicates whether a user is eligible to share their declared age range. However, it is unclear whether this eligibility also incorporates jurisdiction-specific requirements (e.g., certain U.S. states with age assurance regulations). We would appreciate clarification on the following points: Eligibility vs Region: Does checkEligibility() return true based on the user’s eligibility to share age information only, or does it also depend on the user’s geographic region (e.g., specific U.S. states like Texas)? Region-Specific Laws (Texas Example): In scenarios where certain jurisdictions (such as Texas) require age assurance features, while other U.S. states may not, how does checkEligibility() behave? User Consent vs Regulatory Requirement: If a user denies age sharing, but they are located in a region where age-related regulatory features are mandated, how does checkEligibility() behave? Will it return false because the user denied consent? Or will it still return true due to regulatory requirements overriding user preference? Source of Region Determination: Does the Declared Age Range API internally determine the user’s applicable region (e.g., based on IP address, Apple ID region, or device settings) when evaluating checkEligibility()? Should developers independently determine jurisdiction (e.g., using IP-based geolocation) to apply region-specific rules, or is checkEligibility() intended to fully abstract both eligibility and jurisdiction requirements?
Replies
1
Boosts
1
Views
439
Activity
Jul ’26
DeclaredAgeRange API not triggering in regulated regions (Brazil, Utah) — Is it functioning in production?
Hi, We've implemented age assurance logic in our app using the DeclaredAgeRange framework to comply with regulations in Brazil (Digital ECA, effective March 17, 2026) and Utah (App Store Accountability Act, effective May 6, 2026). Our implementation calls AgeRangeService.shared.isEligibleForAgeFeatures on app launch to determine whether the current user is subject to age assurance requirements, and proceeds to call requestAgeRange(ageGates:) accordingly. However, after monitoring in production since the Brazil enforcement date, we've consistently observed isEligibleForAgeFeatures returning false for users in regulated regions, with no age range data being returned. What we'd like to clarify: Is isEligibleForAgeFeatures currently returning true for users in Brazil in production (not sandbox)? For Utah — given that HB 498 pushed the developer compliance deadline to May 6, 2027, will isEligibleForAgeFeatures reflect the original May 6, 2026 activation date or the revised 2027 date? Is there a known rollout schedule or gradual activation plan for these regions that would explain why the flag remains false even after the legal enforcement dates have passed? We've seen similar reports from other developers on these forums, so it seems this may be a widespread issue rather than an implementation problem on our end. Any official guidance on the current status of the API in regulated regions would be greatly appreciated. Thanks.
Replies
1
Boosts
1
Views
740
Activity
Jul ’26
Shallow Depth Entitlement and Underwater Auto-Launch: App Not Appearing in "When Submerged"
I've a question for you maybe you can help me. My watchOS app has: WKSupportsAutomaticDepthLaunch = true WKBackgroundModes = underwater-depth com.apple.developer.submerged-shallow-depth-and-pressure = true entitlement present in codesign and embedded provisioning profile The app uses the shallow depth entitlement, but it does not appear in: Settings → General → Auto-Launch → When Submerged. Is the shallow depth entitlement sufficient for appearing in the system underwater auto-launch app list, or is the full submerged depth entitlement required?
Replies
0
Boosts
0
Views
270
Activity
Jul ’26
PushToTalk session sometimes returns silence data after activation
Hello! Thank you for bringing the new iPhone experience with the PushToTalk framework. I have a working walkie talkie app based on the PushToTalk framework. Everything works fine except for an intermittent bug that I face from time to time on different devices with different iOS versions, from iOS 18 to iOS 26.2 Beta. Sometimes the app goes into a state where the AVAudioInputNode input node tap returns buffers with a constant size that contain only silence. Leaving and rejoining a channel helps, but relaunching or reinstalling (from Xcode) the app does not. Rebooting the device or deleting and reinstalling the app also helps. I do not activate the audio session in my app. I only configure it on launch using setCategory(.playAndRecord, options: [.defaultToSpeaker, .allowBluetooth]) So the flow is: channelManager?.requestBeginTransmitting(channelUUID: globalChannelUUID) func channelManager( _ channelManager: PTChannelManager, channelUUID: UUID, didBeginTransmittingFrom source: PTChannelTransmitRequestSource ) func channelManager( _ channelManager: PTChannelManager, didActivate audioSession: AVAudioSession ) { /// ... installTapAndStart() } private func installTapAndStart() { let inputNode = audioEngine.inputNode let hardwareFormat = inputNode.outputFormat(forBus: 0) guard let targetFormat = AVAudioFormat( commonFormat: .pcmFormatFloat32, sampleRate: configuration.audioSampleRate, channels: configuration.audioChannelsCount, interleaved: true ) else { handleError(RecorderError.invalidAudioFormat) return } let converter = AVAudioConverter(from: hardwareFormat, to: targetFormat)! print("[QUICOpusRecorder]: installTap") inputNode.installTap(onBus: 0, bufferSize: tapBufferSize, format: hardwareFormat) { [weak self] buffer, _ in guard let self else { return } // Here I handle audio data and sometimes get silence } //... do { audioEngine.prepare() try audioEngine.start() } catch { print(" ⚠️ Audio engine start error: \(error)") handleError(error) } } Moreover, if the app is in the foreground and PushToTalk gets stuck in this “silence bug”, I can avoid relying on the PushToTalk flow and simulate audio session activation manually in code. In this case I do not request a transmission and do not use any PushToTalk related code, and the app captures audio data perfectly. Once I leave the channel and rejoin it again, the issue is fixed and I start to receive non silent buffers of varying size, as expected. It works for a while. It can work fine for a day or more, communicating without launching the app, or with the app in the foreground. But it can also go into the “silence” state 30 minutes after working normally. I have no clue why this happens. The only thing I notice is that when the app is in this “stuck silence bug” state, iOS does not play its “chirp” system sound when audio recording starts. P.S. Channel descriptor restoration code: extension PushToTalkEngine: PTChannelRestorationDelegate { public func channelDescriptor(restoredChannelUUID channelUUID: UUID) -> PTChannelDescriptor { print("☀️ \(#function) channelUUID: \(channelUUID)") Task { @MainActor in // Here I fetch more detailed channel data asynchronously do { await initChannelManagerIfNeeded(channelUUID: channelUUID) let channelDescriptor = currentChannelDescriptor() lastChannelDescriptorName = channelDescriptor.name try await channelManager?.setChannelDescriptor( channelDescriptor, channelUUID: channelUUID ) } catch { handleError(error) } } return PTChannelDescriptor(name: "Loading...", image: nil) } } private func initChannelManagerIfNeeded(channelUUID: UUID? = nil) async { guard let channelUUID = channelUUID ?? currentUser?.globalChannelUUID else { print("❌ No global channel uuid found") return } do { guard channelManager == nil else { try await channelManager?.setTransmissionMode(.halfDuplex, channelUUID: channelUUID) return } channelManager = try await PTChannelManager.channelManager( delegate: self, restorationDelegate: self ) try await channelManager?.setTransmissionMode(.halfDuplex, channelUUID: channelUUID) } catch { handleError(error) } }
Replies
3
Boosts
0
Views
1.1k
Activity
Jul ’26
Understanding Crash Reporter Extension lifecycle and debugging behavior
Hi! I have a few questions about the lifecycle and capabilities of the Crash Reporter Extension. Besides using the corpsePort to inspect the crashed process through Mach APIs, is it safe/supported/recommended for the extension to access files in a shared App Group container? Are there any caveats or exceptions we should be aware of, for example around memory-mapped files, file coordination, or filesystem access after the host app has crashed? Shall we use some particular APIs for this kind of shared resource or not? While debugging the extension, I noticed that when I trigger a crash in the app I am debugging, LLDB does not stop inside the extension (it also ends up stopping the debugging session). However, I can observe that the extension does run, because it writes data into a shared App Group directory related to the crash. Is this expected behavior? Is there a recommended way to debug the Crash Reporter Extension reliably (with lldb, or other way)? More generally, I would like to better understand the extension lifecycle: When exactly does the extension start running? How long can it live after the app crashes? Is there a time limit for operating on the corpse process? Is the extension subject to resource limits similar to other app extensions, such as memory, disk, CPU, watchdog, or jetsam constraints? If the Crash Reporter Extension itself crashes, how can we detect that? Would those crashes appear in Xcode Organizer, or is there another recommended way to observe them? Any clarification around the supported lifecycle, debugging model, and resource limits would be very useful.
Replies
4
Boosts
1
Views
604
Activity
Jun ’26
AlertConfiguration.AlertSound.named plays system default despite CAF in main bundle (AlarmKit, iOS 26.5)
We need an official answer: wrong wiring, known bug on 26.5, or unsupported? AlertConfiguration.AlertSound.default works. AlertConfiguration.AlertSound.named("lifeloop_alarm_silent") schedules successfully (Stop/Snooze UI, no API error) but playback is always system default — never our bundled CAF. OFFICIAL API WE FOLLOW Documentation: AlertConfiguration.AlertSound.named(:) https://developer.apple.com/documentation/activitykit/alertconfiguration/alertsound/named(:) "The name of the sound file to use for the alert. Choose a file that's in your app's main bundle or the Library/Sounds folder of your app's data container." WWDC25 session 230 shows: let sound = AlertConfiguration.AlertSound.named("Chime") with the file in the main bundle. We use: AlertConfiguration.AlertSound.named("lifeloop_alarm_silent") Our Swift schedules with AlarmManager.AlarmConfiguration.alarm(..., sound: alertSound). REFERENCES WE ALREADY READ AlarmConfiguration overview: https://developer.apple.com/documentation/alarmkit/alarmmanager/alarmconfiguration Albert Pascual DTS reply (Feb 2026) on this thread pointed at nested alertConfiguration with sound AlarmKit FAQ: https://developer.apple.com/forums/thread/797158 Older forum reply (~2025): claimed .named("Glass Drum.caf") worked — not verified on 26.5 today On iOS 26.5: Bundle.main finds our file with AND without ".caf" in the lookup string; playback still system default OUR WIRING (please confirm correct or tell us what to change) We schedule fixed-time dose alarms with: AlarmManager.AlarmConfiguration.alarm( schedule: .fixed(fireDate), attributes: attributes, stopIntent: stopIntent, secondaryIntent: snoozeIntent, sound: alertSound) .default on this parameter works. .named("lifeloop_alarm_silent") does not — despite Bundle.main finding the file (proof below). Question: Is sound: on .alarm(...) correct for custom AlertSound.named, or must sound go in nested AlertConfiguration(title:body:sound:) as in the overview example? WHAT WE HEAR ON DEVICE sound = .default → loud system alarm (works) sound = .named("lifeloop_alarm_silent") → same loud system/default every time No API error — silent fallback to default PROOF 1 — FILE IN SHIPPED IPA $ find Payload -name "lifeloop_alarm_*.caf" Payload/LifeLoop.app/lifeloop_alarm_silent.caf PROOF 2 — RUNTIME ON DEVICE (2026-06-30, iOS 26.5) Bundle.main.url(forResource:withExtension:): FOUND Bundle.main.url(full filename in name): FOUND Path: .../LifeLoop.app/lifeloop_alarm_silent.caf All .caf in main bundle: lifeloop_alarm_silent.caf Library/Sounds: (none) Widget .appex .caf: (none) Native log at schedule: [alarmkit] build_config · soundModeRaw=silent alertSound=named:lifeloop_alarm_silent silentCafInBundle=true [alarmkit] schedule_ok · alarmID=FBDF2082-61F1-4C93-8B20-094A60EA8626 CAF: lifeloop_alarm_silent.caf — mono, 44100 Hz, 16-bit PCM, ~0.5 s QUESTIONS FOR DTS Main app bundle only, or must CAF also be in widget .appex? Must named(_:) include ".caf" or base name only? Bundle.main FOUND at schedule time but playback is default — known bug on 26.5? Please answer: (A) wrong wiring + correct recipe, (B) known bug + fix version, or (C) not supported — please document. Thank you. Same problem as tonny00 — custom CAF never plays, always the loud system/default alarm. App: LifeLoop (com.stujacks.lifeloop) on iOS 26.5 (physical device). https://developer.apple.com/forums/thread/814732
Replies
1
Boosts
0
Views
216
Activity
Jun ’26
Clarification on Screen Time API capabilities for per-child and per-device activity reports
Hello, I am developing a parental control app using FamilyControls, DeviceActivity, and DeviceActivityReport. My current setup is: The child device requests FamilyControls authorization with .child The parent device requests FamilyControls authorization with .individual The parent app displays reports through a DeviceActivityReportExtension The report filter uses users: .children and devices: .all I would like to clarify two questions: Can a third-party app use the Screen Time API to retrieve or display screen time activity per child or per child device from the parent app? For example: Child A's total screen time today Child A's iPhone screen time today Child A's iPad screen time today At the moment, I can only display an aggregated report using users: .children and devices: .all. I do not see a public API for selecting a specific child or a specific child device. Is this a current limitation of the public Screen Time API, or is there a recommended approach to implement this? Can the Screen Time API report activity data for family members aged 14-17? Specifically, if a family member is between 14 and 17 years old and their device has completed .child authorization, can the parent app still display their Screen Time data using DeviceActivityReport(users: .children)? Or are there restrictions related to Apple ID age, Family Sharing, or Screen Time permissions that prevent third-party apps from retrieving or displaying activity data for users in this age range? My goal is to understand what third-party apps can implement in a compliant way using the public APIs, without attempting to bypass any system limitations. Thank you.
Replies
0
Boosts
0
Views
205
Activity
Jun ’26
iOS 26.4 — How to return from main app to host app after a keyboard-extension dictation round-trip, without private APIs?
I'm building a custom keyboard extension that offers voice dictation. Because keyboard extensions are constrained (memory cap ~30–48 MB, restricted audio session access), I delegate recording to my container app: User in a host app (e.g., Safari) taps the mic in my keyboard extension. The keyboard calls extensionContext.open(URL("myapp://dictation")) to launch the container app. The container app records audio via AVAudioEngine + SFSpeechRecognizer, writes the final transcript to the App Group, and signals completion via a Darwin notification. 4. The user is expected to be returned to the original host app (Safari) automatically so they can keep typing. The problem (step 4): On iOS 26.4 I can no longer identify which app was the host. Every previously-known path returns nil for the keyboard extension's host: parent.value(forKey: "_hostBundleID") → returns the literal string parent.value(forKey: "_hostApplicationBundleIdentifier") → returns NSNull xpc_connection_copy_bundle_id on the underlying XPC connection (via PKService.defaultService.personalities[…]) → returns NULL NSXPCConnection.processBundleIdentifier on extensionContext._extensionHostProxy._connection → returns nil proc_pidpath(hostPID, …) → EPERM from the keyboard sandbox LSApplicationWorkspace.frontmostApplication → selector unavailable from the extension RBSProcessHandle.handleForIdentifier:error: → returns an RBSServiceErrorDomain error Without the host's bundle ID, the container app has no way to call LSApplicationWorkspace.openApplicationWithBundleID: (the technique that worked on iOS 25 and earlier). UIApplication.suspend() correctly sends the container to background, but iOS treats us as a "fresh launch" — it returns the user to the Home Screen instead of Safari, because the container app was launched by an extension, not directly by Safari. KeyboardKit's maintainer reached the same conclusion (issue #1014) and shipped 10.4 without the feature. My questions: Is there a public, App-Store-safe API in iOS 26+ for a custom keyboard extension to identify its host application, or for the container app (launched via the extension's openURL) to identify which app initially hosted the extension that opened it? UIOpenURLContext.options.sourceApplication reports the extension's own container, not the actual host. 2. Is there a public mechanism for "return to source app" when the container app was launched by an extension's openURL? Equivalent to the ← Source affordance iOS shows for normal inter-app openURL, but triggered programmatically by the launched app. 3. Some popular keyboards (e.g., 微信输入法 / WeChat Keyboard) still appear to round-trip through their container app on iOS 26.4 and return the user to the original host — including the iOS ← WeChat back affordance in the host's status bar afterward. What's the recommended approach to achieve this? If it requires a specific scene-activation flow, NSUserActivity pattern, or extension-context configuration, please point at the relevant docs. 4. If there is no public path today, is FB22247647 (or a related radar) the right place to track this? Should developers in this position migrate to in-extension audio capture (which has its own significant constraints in keyboard extensions)? I'd much rather not rely on private APIs. Concrete guidance — or even an acknowledgment of which direction Apple intends — would help thousands of custom-keyboard developers who currently have a degraded voice-input experience on iOS 26.4+. Tested on iPhone 12 Pro Max running iOS 26.4.2 (build 23E261), Xcode 26.x, Swift 5. Thanks!
Replies
3
Boosts
0
Views
950
Activity
Jun ’26