Posts under App & System Services topic

Post

Replies

Boosts

Views

Activity

Issues with Opening iOS Settings from App
Hi there! We are working on our SkyElectric App which is being developed in Flutter framework, where we need user to connect with the Wifi of the the inverter. We are trying to direct user to WiFi Settings page of the iOS in general settings where all the available WiFi Networks are listed but unfortunately user is being directed to App's Settings page. We are using package of app_settings and launcher. I've read that Apple changed a policy in 2019 where it restricts Apps to navigate to OS pages. Question: Could you please verify if I APPLE allows us to access the General Settings or WiFi Settings through clicking a button in our App name "Open WiFi Settings", If not then Why?
2
0
89
Apr ’25
how to register listener to `NWConnectionGroup` for QUIC
I am trying to make http3 client with Network.framework on Apple platforms. Codes that implement NWConnectionGroup.start with NWListener don't always work with warning below. I assume NWConnectionGroup.newConnectionHandler or NWListener.newConnectionHandler will be called to start connection from the server if it works. nw_protocol_instance_add_new_flow [C1.1.1:2] No listener registered, cannot accept new flow quic_stream_add_new_flow [C1.1.1:2] [-fde1594b83caa9b7] failed to create new stream for received stream id 3 so I tried: create the NWListener -> not work check whether NWConnectionGroup has a member to register or not NWListener -> not work (it doesn't have). use NWConnection instead of NWConnectionGroup -> not work Is my understanding correct? How should I do to set or associate listener with NWConnection/Group for newConnectionHandler is called and to delete wanings? What is the best practice in the case? Sample codes are below. Thanks in advance. // http3 needs unidirectional stream by the server and client. // listener private let _listener: NWListener let option: NWProtocolQUIC.Options = .init(alpn:["h3"]) let param: NWParameters = .init(quic: option) _listener = try! .init(using: param) _listener.stateUpdateHandler = { state in print("listener state: \(state)") } _listener.newConnectionHandler = { newConnection in print("new connection added") } _listener.serviceRegistrationUpdateHandler = { registrationState in print("connection registrationstate") } // create connection private let _group: NWConnectionGroup let options: NWProtocolQUIC.Options = .init(alpn: ["h3"]) options.direction = .unidirectional options.isDatagram = false options.maxDatagramFrameSize = 65535 sec_protocol_options_set_verify_block(options.securityProtocolOptions, {(_: sec_protocol_metadata_t, _: sec_trust_t, completion: @escaping sec_protocol_verify_complete_t) in print("cert completion.") completion(true) }, .global()) let params: NWParameters = .init(quic: options) let group: NWMultiplexGroup = .init( to: .hostPort(host: NWEndpoint.Host("google.com"), port: NWEndpoint.Port(String(443))!)) _group = .init(with: group, using: params) _group.setReceiveHandler {message,content,isComplete in print("receive: \(message)") } _group.newConnectionHandler = {newConnection in print("newConnectionHandler: \(newConnection.state)") } _group.stateUpdateHandler = { state in print("state: \(state)") } _group.start(queue: .global()) _listener.start(queue: .global()) if let conn = _group.extract() { let data: Data = .init() let _ = _group.reinsert(connection: conn) conn.send(content: data, completion: .idempotent) }
4
0
220
Apr ’25
How to implement normal loading of web content when I intercept all request header information using the Swizzling method
I am developing a web application, I hope to be able to intercept all requests in the loaded web page, match the network request I want to specifically intercept the network request and then obtain the request header information (not the user's personal privacy data interception), if the use is the method of injection, the request header information is incomplete, such as the more important "content-type" field in the request header, so I try to use Swizzling method to intercept all http and https requests, and I can now intercept all the request information. But there is still a problem with my project, when loading x.com, logging in, appearing white screen after the successful landing, and not loading to the page after the successful landing, I don't know where the reason is。 Below is my core code implementation fragment. import WebKit // MARK: - WebViewController class WebViewController: UIViewController { fileprivate var webView: WKWebView! private var schemeHandler: WWKProxyWKURLSchemeHandler! override func viewDidLoad() { super.viewDidLoad() Self.initSwizzling setupWebView() loadInitialContent() } private func setupWebView() { let config = WKWebViewConfiguration() schemeHandler = WWKProxyWKURLSchemeHandler() config.setURLSchemeHandler(self.schemeHandler, forURLScheme: "https") config.setURLSchemeHandler(self.schemeHandler, forURLScheme: "http") webView = WKWebView(frame: view.bounds, configuration: config) webView.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(webView) } private func loadInitialContent() { if let url = URL(string: "https://x.com") { let request = URLRequest(url: url,cachePolicy:.reloadIgnoringLocalCacheData,timeoutInterval: 15) webView.load(request) } } func reloadWebView() { webView?.reloadFromOrigin() } } class WWKProxyWKURLSchemeHandler: NSObject, WKURLSchemeHandler { private let lock = NSLock() private var activeTasks = [ObjectIdentifier: URLSessionDataTask]() func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) { lock.lock() defer { lock.unlock() } let taskID = ObjectIdentifier(urlSchemeTask) guard !activeTasks.keys.contains(taskID) else { print("⚠️ Task already started: \(urlSchemeTask.request.url?.absoluteString ?? "")") return } print("Intercepted URL---:",urlSchemeTask.request.url?.absoluteString ?? "") print("All requests intercepted----:",urlSchemeTask.request.allHTTPHeaderFields) let request = urlSchemeTask.request let dataTask = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in guard let self = self else { return } self.lock.lock() let isActive = self.activeTasks[taskID] != nil self.lock.unlock() guard isActive else { print("🌀 Task already cancelled: \(urlSchemeTask.request.url?.absoluteString ?? "")") return } // Make sure it only handles once guard self.activeTasks.keys.contains(taskID) else { return } self.activeTasks.removeValue(forKey: taskID) DispatchQueue.main.async { if let error = error { urlSchemeTask.didFailWithError(error) print("🔴 Task failed: \(urlSchemeTask.request.url?.absoluteString ?? "") - \(error.localizedDescription)") return } guard let response = response, let data = data else { urlSchemeTask.didFailWithError(URLError(.unknown)) print("🔴 Invalid response: \(urlSchemeTask.request.url?.absoluteString ?? "")") return } urlSchemeTask.didReceive(response) urlSchemeTask.didReceive(data) urlSchemeTask.didFinish() print("🟢 Task completed: \(urlSchemeTask.request.url?.absoluteString ?? "")") } } self.activeTasks[taskID] = dataTask dataTask.resume() } func webView(_ webView: WKWebView, stop task: WKURLSchemeTask) {} private func finishTask(taskID: ObjectIdentifier ,task: WKURLSchemeTask, response: URLResponse?, data: Data?, error: Error?) { lock.lock() defer { lock.unlock() } guard activeTasks.keys.contains(taskID) else { return } activeTasks.removeValue(forKey: taskID) DispatchQueue.main.async { if let error = error { task.didFailWithError(error) print("🔴 Task failed: \(task.request.url?.absoluteString ?? "") - \(error.localizedDescription)")return} guard let response = response, let data = data else { task.didFailWithError(URLError(.unknown)) print("🔴 Invalid response: \(task.request.url?.absoluteString ?? "")") return } task.didReceive(response) task.didReceive(data) task.didFinish() print("🟢 Task completed: \(task.request.url?.absoluteString ?? "")") } } } extension WKWebView { @objc dynamic class func qm_handlesURLScheme(_ urlScheme: String) -> Bool { if urlScheme == "https" || urlScheme == "http" {return false} return self.qm_handlesURLScheme(urlScheme) } // Exchange of execution methods static func setupSwizzling() { let originalSelector = #selector(handlesURLScheme(_:)) let swizzledSelector = #selector(qm_handlesURLScheme(_:)) // Implemented by Runtime Get Method guard let originalMethod = class_getClassMethod(WKWebView.self, originalSelector), let swizzledMethod = class_getClassMethod(WKWebView.self, swizzledSelector) else { return } // Implementation of Exchange Methods method_exchangeImplementations(originalMethod, swizzledMethod) } } extension WebViewController { private static let initSwizzling: Void = { DispatchQueue.once(token: "com.webview.swizzling") { WKWebView.setupSwizzling() } }() } // GCD Once extension DispatchQueue { private static var tokens = Set<String>() class func once(token: String, block: () -> Void) { objc_sync_enter(self) defer { objc_sync_exit(self) } guard !tokens.contains(token) else { return } tokens.insert(token) block() } } extension WebViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { decisionHandler(.allow) } }
1
0
102
Apr ’25
On-demand rules
I've implemented a custom system extension VPN for macOS using Packet Tunnel Provider. The VPN is configured with on-demand, and a rule to always connect whenever there's traffic: onDemandRules = [NEOnDemandRuleConnect()] As expected, if the VPN isn't active, all traffic gets blocked until it is ready. Not expected: In the following scenario, there is some 'traffic leak': Use only WiFi (not wired cable) Connect the VPN Disable the WiFi and wait for the VPN to disconnect Enable the WiFi Some packets are routed outside the VPN, and aren't being blocked Some moments after, all traffic will be blocked, and the VPN will start the 'connecting' process. Is the above scenario a 'known' issue? Can it be a race condition in the OS, where some packets can be sent after the network is brought back before the VPN process starts? Is there any way to fix this problem? P.S: I'm not using flags such as 'capture all network'
3
1
202
Apr ’25
Working with Input/Output stream with Swift 6 and concurrency framework
Hello, I am developing an application which is communicating with external device using BLE and L2CAP. I wonder what are the best practices of using Input & Output streams that are established with L2CAP connection when working with Swift 6 concurrency model. I've been trying to find some examples and hints for some time now but unfortunately there isn't much available. One useful thread I've found is: https://developer.apple.com/forums/thread/756281 but it does not offer much insight into using eg. actor model with streams. I wonder if something has changed in this regards? Also, are there any plans to migrate eg. CoreBluetooth stack to new swift 6 concurrency ?
2
0
170
Apr ’25
Not Receiving Incoming VoIP Push Notifications on iOS 18.4 (React Native App)
Hi Apple Dev Team, We have a React Native application that includes call functionality using PushKit and VoIP notifications. We are using APNS to send the VoIP notifications, and everything has been working smoothly on iOS versions up to 18.3.1. However, after updating to iOS 18.4, we are no longer receiving incoming VoIP push notifications on the device. There have been no code changes related to our PushKit or notification logic — the exact same build continues to work correctly on devices running iOS 18.3.1 and earlier. We're trying to understand if anything has changed in iOS 18.4 that affects VoIP push delivery or registration behavior. Would appreciate any guidance, and happy to share code snippets or configuration if needed. Thanks in advance!
1
1
175
Apr ’25
Push payload is not present on notification tap
I am checking if the user taps on the firebase push notification and get the payload. override func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { let userInfo = response.notification.request.content.userInfo os_log("notification tapped %{public}@", log: OSLog.push, type: .info, userInfo) handleNotificationPayload(userInfo as! [String: AnyObject]) setFlutterLinkClickedVariable() } My use case is in app terminated state when push notification is tapped, get the link from payload and navigate to corresponding screen based on the link. This is working when there is only one push notification. When there are multiple push notifications with different links in the payload, only the first notification I tap works. Rest of the notifications just launches the app and does not navigate because the link is not set. I am getting the link from the payload and invoking flutter code which sets the link in the user defaults (shared preferences) and when the app launches in the home screen it checks for this variable and navigates accordingly. func handleNotificationPayload(_ payload: [String: AnyObject]) { if let link = payload["link"] as? String { setFlutterLinkVariable(link) } } override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { os_log("app did receive remote notification %{public}@", log: OSLog.push, type: .info, userInfo) handleNotificationPayload(userInfo as! [String : AnyObject]) completionHandler(.newData) } Currently when there is only one push notification it works because the link is set from the above method. The click delegate is not calling. I did set the delegate in application(:didFinishLaunchingWithOptions). UNUserNotificationCenter.current().delegate = self application.registerForRemoteNotifications() How to solve this issue? Thanks.
2
0
794
Apr ’25
How can you tick between live activities?
I have been watching the following moment from wwdc (Design dynamic Live Activities): https://developer.apple.com/videos/play/wwdc2023/10194/?time=728 It suggest that you should 'tick' between multiple live activities of your app: When you want to show multiple sessions for your app going on at once, consider ticking between the display of them to continue to give users an eye on everything that’s going on. How can I tick between them? More specifically how can I do that when my app is in the background?
1
1
250
Apr ’25
Background Push Notifications for Emergency App Delayed Despite Critical Alert Entitlement
I’m using Appnotic from my server to send notifications for an emergency service, where it is critical that notifications are delivered immediately. My payload looks like this: "aps": { "alert": "Test alert", "sound": { "critical": 1, "name": "sound.wav", "volume": 0.5 }, "content-available": 1, "category": "alert" }, "topic": "com.fireservicerota.FSR-Primary-Alerting", "custom_payload": { "id": "11", "type": "alert", "incident_id": 23434, "incident_response_id": 2652343, "expiration_time": "2024-06-06T16:59:05+01:00" } } I already have the critical alert entitlement and background processing enabled. Everything seems fine when debugging, but I’m experiencing issues: • Some notifications never arrive • Around 60% of notifications arrive with noticeable delay Since this is an emergency app, delivery speed is crucial. What could be causing this inconsistency?
1
0
154
Apr ’25
VZLinuxBootLoader failed to boot Aarch64 64K kernel
Works: runs-on: ubuntu-24.04-arm container: image: ubuntu:latest env: DEBIAN_FRONTEND: noninteractive steps: - uses: actions/checkout@v4 - run: | apt-get --assume-yes update apt-get --assume-yes install linux-image-generic dracut binutils - run: | dracut --conf $(mktemp) \ --confdir $(mktemp --directory) \ --verbose \ --modules "base bash" \ --add-drivers "virtio-rng bcachefs btrfs virtiofs overlay xfs" \ --kernel-cmdline "console=hvc0" \ --no-early-microcode \ --no-hostonly \ --no-compress \ --no-uefi \ initramfs \ $(ls /lib/modules/) - run: | cp /boot/vmlinuz-$(ls /lib/modules/) vmlinuz - uses: actions/upload-artifact@v4 with: path: | vmlinuz initramfs Will NOT work: runs-on: ubuntu-24.04-arm container: image: ubuntu:latest env: DEBIAN_FRONTEND: noninteractive steps: - uses: actions/checkout@v4 - run: | apt-get --assume-yes update apt-get --assume-yes install linux-image-generic-64k dracut binutils - run: | dracut --conf $(mktemp) \ --confdir $(mktemp --directory) \ --verbose \ --modules "base bash" \ --add-drivers "virtio-rng bcachefs btrfs virtiofs overlay xfs" \ --kernel-cmdline "console=hvc0" \ --no-early-microcode \ --no-hostonly \ --no-compress \ --no-uefi \ initramfs \ $(ls /lib/modules/) - run: | cp /boot/vmlinuz-$(ls /lib/modules/) vmlinuz - uses: actions/upload-artifact@v4 with: path: | vmlinuz initramfs You can try it on Github Actions
1
0
105
Apr ’25
Safe way to query for the existence of a CKRecordZone?
There's some logic in my app that first checks to see if a specific CloudKit record zone exists. If it doesn't, it creates the zone, and then my application continues on with its work. The way I've implemented this right now is by catching the zoneNotFound error when I call CKDatabase#recordZone(for:) (docs) and creating the zone when that happens: do { try await db.recordZone(for: zoneID) } catch let ckError as CKError where [.zoneNotFound, .userDeletedZone].contains(ckError.code) { // createZone is a helper function try await createZone(zoneID: zoneID, context: context) } This works great, but every time I do this, an error is logged in CloudKit Console, which creates a lot of noise and makes it harder to see real errors. Is there a way to do this without explicitly triggering a CloudKit error? I just found CKDatabase#recordZones(for:) (docs), which seems like it returns an empty array instead of throwing an error if the zone doesn't exist. Will calling that and looking for a non-empty array work just as well, but without logging lots of errors in the console?
1
0
173
Apr ’25
Network Push Provider Wifi Selection Behavior
In our App, we have a network extension with a NEAppPushProvider subclass running. We run the following steps Setup a dual-band wireless router per the following: Broadcasting 2.4 GHz and 5 GHz channels Same SSID names for both channels Connected to the production network to the router DHCP assigning addresses in the 10.1.x.x network Connect the mobile device to the 5 GHz network (if needed, turn off the 2.4 GHz network temporarily; once the device connects to the 5 GHz network, the 2.4 GHz network can be turned back on). Create a NEAppPushManager in the App, using the SSID from the above mentioned network and set it to the matchSSIDs property. Call saveToPreferences() on the push manager to save. A. We have UI that shows the extension has been started and it has connected to the server successfully. Walk out of the range of the 5 GHz channel of the router, but stay within range of the 2.4ghz channel. Wait for the mobile device to connect to the 2.4 GHz channel. Expected: The extension would reconnect to the 2.4ghz network. Observed: The extension does not reconnect. Checking the logs for the extension we see that the following was called in the push provider subclass. stop(with:completionHandler:) > PID: 808 | 🗒️🛑 Stopped with reason 3: "noNetworkAvailable" The expectation is that start() on the NEAppPushProvider subclass would be called. Is this an incorrect expectation? How does the NEAppPushProvider handle same network SSID roaming among various band frequencies? I looked at the documentation and did not find any settings targeting 2.4 or 5 ghz networks. Please advise on what to do.
5
1
145
Apr ’25
Core Data crash while trying to merge
I'm looking for guidance how to mitigate this crash. It seems super deep inside Core Data' FRC fetchedObjects management. In my code, it's initiated by this viewContext.perform { [unowned self] in self.viewContext.mergeChanges(fromContextDidSave: notification) } which is directly followed by the stack trace below. Basically merging data from .NSManagedObjectContextDidSave notification from another NSManagedObjectContext. Nothing special, it works great for years, apart from these rare occurrences. Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Reason: -[__NSCFArray objectAtIndex:]: index (235) beyond bounds (234) Termination Reason: SIGNAL 6 Abort trap: 6 Triggered by Thread: 0 Last Exception Backtrace: 0 CoreFoundation 0x199e947cc __exceptionPreprocess + 164 (NSException.m:249) 1 libobjc.A.dylib 0x1971672e4 objc_exception_throw + 88 (objc-exception.mm:356) 2 CoreFoundation 0x199fc4258 _NSArrayRaiseBoundException + 368 (NSCFArray.m:22) 3 CoreFoundation 0x199e288a4 -[__NSCFArray objectAtIndex:] + 200 (NSCFArray.m:42) 4 CoreData 0x1a1e17338 -[_PFMutableProxyArray objectAtIndex:] + 40 (_PFArray.m:1860) 5 CoreData 0x1a1e1673c -[NSFetchedResultsController _updateFetchedObjectsWithInsertChange:] + 380 (NSFetchedResultsController.m:1582) 6 CoreData 0x1a1e1426c __82-[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:]_block_invoke + 2240 (NSFetchedResultsController.m:2171) 7 CoreData 0x1a1dcdf80 developerSubmittedBlockToNSManagedObjectContextPerform + 156 (NSManagedObjectContext.m:4002) 8 CoreData 0x1a1e41a44 -[NSManagedObjectContext performBlockAndWait:] + 216 (NSManagedObjectContext.m:4113) 9 CoreData 0x1a1e41034 -[NSFetchedResultsController _core_managedObjectContextDidChange:] + 124 (NSFetchedResultsController.m:2379) 10 CoreFoundation 0x199e632f4 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 148 (CFNotificationCenter.c:701) 11 CoreFoundation 0x199e63210 ___CFXRegistrationPost_block_invoke + 88 (CFNotificationCenter.c:194) 12 CoreFoundation 0x199e63158 _CFXRegistrationPost + 436 (CFNotificationCenter.c:222) 13 CoreFoundation 0x199e6170c _CFXNotificationPost + 728 (CFNotificationCenter.c:1248) 14 Foundation 0x198a84ea4 -[NSNotificationCenter postNotificationName:object:userInfo:] + 92 (NSNotification.m:531) 15 CoreData 0x1a1e11650 -[NSManagedObjectContext _createAndPostChangeNotification:deletions:updates:refreshes:deferrals:wasMerge:] + 1736 (NSManagedObjectContext.m:8098) 16 CoreData 0x1a1e10e0c -[NSManagedObjectContext _postRefreshedObjectsNotificationAndClearList] + 164 (NSManagedObjectContext.m:7631) 17 CoreData 0x1a1e0fad8 -[NSManagedObjectContext _processRecentChanges:] + 100 (NSManagedObjectContext.m:7714) 18 CoreData 0x1a1e3563c -[NSManagedObjectContext _coreMergeChangesFromDidSaveDictionary:usingObjectIDs:withClientQueryGeneration:] + 3436 (NSManagedObjectContext.m:3723) 19 CoreData 0x1a1e34350 __116+[NSManagedObjectContext(_NSCoreDataSPI) _mergeChangesFromRemoteContextSave:intoContexts:withClientQueryGeneration:]_block_invoke_4 + 76 (NSManagedObjectContext.m:9531) 20 CoreData 0x1a1dcdf80 developerSubmittedBlockToNSManagedObjectContextPerform + 156 (NSManagedObjectContext.m:4002) 21 CoreData 0x1a1e41a44 -[NSManagedObjectContext performBlockAndWait:] + 216 (NSManagedObjectContext.m:4113) 22 CoreData 0x1a1e39880 +[NSManagedObjectContext _mergeChangesFromRemoteContextSave:intoContexts:withClientQueryGeneration:] + 2372 (NSManagedObjectContext.m:9537) 23 CoreData 0x1a1e344a0 -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:] + 292 (NSManagedObjectContext.m:0)
1
0
81
Apr ’25
HealthKit: Real-Time Sleep Tracking with Heart Rate Data
I am trying to track a user's real-time sleep state using heart rate data, but I have encountered several issues: When using HKSampleQuery on the phone to fetch heart rate data, I can only retrieve data recorded before the app comes to the foreground or before it is terminated and restarted (see related issue: https://developer.apple.com/forums/thread/774953). I attempted to get data on the Apple Watch and send updates to the phone via Watch Connectivity. However, if I use WKExtendedRuntimeSession, although I can obtain data on the watch, once the watch screen goes off, it can no longer transmit data via Watch Connectivity to the phone (since I cannot guarantee the app will remain in the foreground when lying in bed). On the other hand, using HKWorkoutSession results in interference with the activity rings and causes the heart rate sensor to run too frequently, which I worry may affect the battery life of the watch. Is there an elegant solution for tracking a user's heart rate data for sleep monitoring?
1
0
130
Apr ’25
Synchronization Timing Between Apple Watch HealthKit Store and iPhone HealthKit Store
Hi, I’m currently working on an app that utilizes sleep data from HealthKit to provide users with meaningful insights about their sleep. To ensure a smooth user experience, I’d like to understand when sleep data collected by the Apple Watch is saved to the HealthKit store and when it gets synced to the iPhone. Ideally, I want to fetch sleep data right after the user wakes up and opens our app. However, to do this reliably, I need to know the timing of how and when this data becomes available in the iPhone’s HealthKit store. I’ve looked through the official documentation and relevant WWDC sessions but couldn’t find clear information on this topic. If anyone has insights or experience with how and when the Apple Watch syncs HealthKit data—especially sleep records—to the iPhone, I’d greatly appreciate your input. Thanks!
1
0
141
Apr ’25
Detecting Sleep End Events and Sleep Data Sync Timing from Apple Watch to HealthKit on iPhone
Hello, I’m developing an iOS app that works with sleep data from Apple Watch via HealthKit. I would like to clarify the following: How can an iPhone app detect when a sleep session ends on the Apple Watch? When is sleep data typically written to the HealthKit store on iPhone after sleep ends? Is it immediately after wake-up, or does it depend on certain conditions (e.g., watch charging, connectivity)? Understanding the timing and mechanism of sleep data synchronization is crucial for our app to process accurate and timely health information. Thank you for your assistance.
1
0
101
Apr ’25
Can HKWorkoutSession be used for a lone worker protection app for the Apple Watch?
We are developing a mobile app focused on lone worker protection, which does not include any fitness tracking features. We require the use of HKWorkoutSession solely to enable background execution of critical safety-related code. Could you please confirm whether this use of HKWorkoutSession is permitted under App Store Review guidelines, given that our app does not offer fitness or workout-related functionality?
1
1
191
Apr ’25
NSPasteboard in System Extension
I am trying to access clipboard via NSPasteboard API from a System Extension. However, all of its get methods return empty arrays and nil objects. Is that expected? Is there some permission or entitlement required for a System Extension to access clipboard?
Replies
2
Boosts
0
Views
118
Activity
Apr ’25
Issues with Opening iOS Settings from App
Hi there! We are working on our SkyElectric App which is being developed in Flutter framework, where we need user to connect with the Wifi of the the inverter. We are trying to direct user to WiFi Settings page of the iOS in general settings where all the available WiFi Networks are listed but unfortunately user is being directed to App's Settings page. We are using package of app_settings and launcher. I've read that Apple changed a policy in 2019 where it restricts Apps to navigate to OS pages. Question: Could you please verify if I APPLE allows us to access the General Settings or WiFi Settings through clicking a button in our App name "Open WiFi Settings", If not then Why?
Replies
2
Boosts
0
Views
89
Activity
Apr ’25
how to register listener to `NWConnectionGroup` for QUIC
I am trying to make http3 client with Network.framework on Apple platforms. Codes that implement NWConnectionGroup.start with NWListener don't always work with warning below. I assume NWConnectionGroup.newConnectionHandler or NWListener.newConnectionHandler will be called to start connection from the server if it works. nw_protocol_instance_add_new_flow [C1.1.1:2] No listener registered, cannot accept new flow quic_stream_add_new_flow [C1.1.1:2] [-fde1594b83caa9b7] failed to create new stream for received stream id 3 so I tried: create the NWListener -> not work check whether NWConnectionGroup has a member to register or not NWListener -> not work (it doesn't have). use NWConnection instead of NWConnectionGroup -> not work Is my understanding correct? How should I do to set or associate listener with NWConnection/Group for newConnectionHandler is called and to delete wanings? What is the best practice in the case? Sample codes are below. Thanks in advance. // http3 needs unidirectional stream by the server and client. // listener private let _listener: NWListener let option: NWProtocolQUIC.Options = .init(alpn:["h3"]) let param: NWParameters = .init(quic: option) _listener = try! .init(using: param) _listener.stateUpdateHandler = { state in print("listener state: \(state)") } _listener.newConnectionHandler = { newConnection in print("new connection added") } _listener.serviceRegistrationUpdateHandler = { registrationState in print("connection registrationstate") } // create connection private let _group: NWConnectionGroup let options: NWProtocolQUIC.Options = .init(alpn: ["h3"]) options.direction = .unidirectional options.isDatagram = false options.maxDatagramFrameSize = 65535 sec_protocol_options_set_verify_block(options.securityProtocolOptions, {(_: sec_protocol_metadata_t, _: sec_trust_t, completion: @escaping sec_protocol_verify_complete_t) in print("cert completion.") completion(true) }, .global()) let params: NWParameters = .init(quic: options) let group: NWMultiplexGroup = .init( to: .hostPort(host: NWEndpoint.Host("google.com"), port: NWEndpoint.Port(String(443))!)) _group = .init(with: group, using: params) _group.setReceiveHandler {message,content,isComplete in print("receive: \(message)") } _group.newConnectionHandler = {newConnection in print("newConnectionHandler: \(newConnection.state)") } _group.stateUpdateHandler = { state in print("state: \(state)") } _group.start(queue: .global()) _listener.start(queue: .global()) if let conn = _group.extract() { let data: Data = .init() let _ = _group.reinsert(connection: conn) conn.send(content: data, completion: .idempotent) }
Replies
4
Boosts
0
Views
220
Activity
Apr ’25
How to implement normal loading of web content when I intercept all request header information using the Swizzling method
I am developing a web application, I hope to be able to intercept all requests in the loaded web page, match the network request I want to specifically intercept the network request and then obtain the request header information (not the user's personal privacy data interception), if the use is the method of injection, the request header information is incomplete, such as the more important "content-type" field in the request header, so I try to use Swizzling method to intercept all http and https requests, and I can now intercept all the request information. But there is still a problem with my project, when loading x.com, logging in, appearing white screen after the successful landing, and not loading to the page after the successful landing, I don't know where the reason is。 Below is my core code implementation fragment. import WebKit // MARK: - WebViewController class WebViewController: UIViewController { fileprivate var webView: WKWebView! private var schemeHandler: WWKProxyWKURLSchemeHandler! override func viewDidLoad() { super.viewDidLoad() Self.initSwizzling setupWebView() loadInitialContent() } private func setupWebView() { let config = WKWebViewConfiguration() schemeHandler = WWKProxyWKURLSchemeHandler() config.setURLSchemeHandler(self.schemeHandler, forURLScheme: "https") config.setURLSchemeHandler(self.schemeHandler, forURLScheme: "http") webView = WKWebView(frame: view.bounds, configuration: config) webView.autoresizingMask = [.flexibleWidth, .flexibleHeight] view.addSubview(webView) } private func loadInitialContent() { if let url = URL(string: "https://x.com") { let request = URLRequest(url: url,cachePolicy:.reloadIgnoringLocalCacheData,timeoutInterval: 15) webView.load(request) } } func reloadWebView() { webView?.reloadFromOrigin() } } class WWKProxyWKURLSchemeHandler: NSObject, WKURLSchemeHandler { private let lock = NSLock() private var activeTasks = [ObjectIdentifier: URLSessionDataTask]() func webView(_ webView: WKWebView, start urlSchemeTask: WKURLSchemeTask) { lock.lock() defer { lock.unlock() } let taskID = ObjectIdentifier(urlSchemeTask) guard !activeTasks.keys.contains(taskID) else { print("⚠️ Task already started: \(urlSchemeTask.request.url?.absoluteString ?? "")") return } print("Intercepted URL---:",urlSchemeTask.request.url?.absoluteString ?? "") print("All requests intercepted----:",urlSchemeTask.request.allHTTPHeaderFields) let request = urlSchemeTask.request let dataTask = URLSession.shared.dataTask(with: request) { [weak self] data, response, error in guard let self = self else { return } self.lock.lock() let isActive = self.activeTasks[taskID] != nil self.lock.unlock() guard isActive else { print("🌀 Task already cancelled: \(urlSchemeTask.request.url?.absoluteString ?? "")") return } // Make sure it only handles once guard self.activeTasks.keys.contains(taskID) else { return } self.activeTasks.removeValue(forKey: taskID) DispatchQueue.main.async { if let error = error { urlSchemeTask.didFailWithError(error) print("🔴 Task failed: \(urlSchemeTask.request.url?.absoluteString ?? "") - \(error.localizedDescription)") return } guard let response = response, let data = data else { urlSchemeTask.didFailWithError(URLError(.unknown)) print("🔴 Invalid response: \(urlSchemeTask.request.url?.absoluteString ?? "")") return } urlSchemeTask.didReceive(response) urlSchemeTask.didReceive(data) urlSchemeTask.didFinish() print("🟢 Task completed: \(urlSchemeTask.request.url?.absoluteString ?? "")") } } self.activeTasks[taskID] = dataTask dataTask.resume() } func webView(_ webView: WKWebView, stop task: WKURLSchemeTask) {} private func finishTask(taskID: ObjectIdentifier ,task: WKURLSchemeTask, response: URLResponse?, data: Data?, error: Error?) { lock.lock() defer { lock.unlock() } guard activeTasks.keys.contains(taskID) else { return } activeTasks.removeValue(forKey: taskID) DispatchQueue.main.async { if let error = error { task.didFailWithError(error) print("🔴 Task failed: \(task.request.url?.absoluteString ?? "") - \(error.localizedDescription)")return} guard let response = response, let data = data else { task.didFailWithError(URLError(.unknown)) print("🔴 Invalid response: \(task.request.url?.absoluteString ?? "")") return } task.didReceive(response) task.didReceive(data) task.didFinish() print("🟢 Task completed: \(task.request.url?.absoluteString ?? "")") } } } extension WKWebView { @objc dynamic class func qm_handlesURLScheme(_ urlScheme: String) -> Bool { if urlScheme == "https" || urlScheme == "http" {return false} return self.qm_handlesURLScheme(urlScheme) } // Exchange of execution methods static func setupSwizzling() { let originalSelector = #selector(handlesURLScheme(_:)) let swizzledSelector = #selector(qm_handlesURLScheme(_:)) // Implemented by Runtime Get Method guard let originalMethod = class_getClassMethod(WKWebView.self, originalSelector), let swizzledMethod = class_getClassMethod(WKWebView.self, swizzledSelector) else { return } // Implementation of Exchange Methods method_exchangeImplementations(originalMethod, swizzledMethod) } } extension WebViewController { private static let initSwizzling: Void = { DispatchQueue.once(token: "com.webview.swizzling") { WKWebView.setupSwizzling() } }() } // GCD Once extension DispatchQueue { private static var tokens = Set<String>() class func once(token: String, block: () -> Void) { objc_sync_enter(self) defer { objc_sync_exit(self) } guard !tokens.contains(token) else { return } tokens.insert(token) block() } } extension WebViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { decisionHandler(.allow) } }
Replies
1
Boosts
0
Views
102
Activity
Apr ’25
On-demand rules
I've implemented a custom system extension VPN for macOS using Packet Tunnel Provider. The VPN is configured with on-demand, and a rule to always connect whenever there's traffic: onDemandRules = [NEOnDemandRuleConnect()] As expected, if the VPN isn't active, all traffic gets blocked until it is ready. Not expected: In the following scenario, there is some 'traffic leak': Use only WiFi (not wired cable) Connect the VPN Disable the WiFi and wait for the VPN to disconnect Enable the WiFi Some packets are routed outside the VPN, and aren't being blocked Some moments after, all traffic will be blocked, and the VPN will start the 'connecting' process. Is the above scenario a 'known' issue? Can it be a race condition in the OS, where some packets can be sent after the network is brought back before the VPN process starts? Is there any way to fix this problem? P.S: I'm not using flags such as 'capture all network'
Replies
3
Boosts
1
Views
202
Activity
Apr ’25
Working with Input/Output stream with Swift 6 and concurrency framework
Hello, I am developing an application which is communicating with external device using BLE and L2CAP. I wonder what are the best practices of using Input & Output streams that are established with L2CAP connection when working with Swift 6 concurrency model. I've been trying to find some examples and hints for some time now but unfortunately there isn't much available. One useful thread I've found is: https://developer.apple.com/forums/thread/756281 but it does not offer much insight into using eg. actor model with streams. I wonder if something has changed in this regards? Also, are there any plans to migrate eg. CoreBluetooth stack to new swift 6 concurrency ?
Replies
2
Boosts
0
Views
170
Activity
Apr ’25
Decode Tool BaseSystem.chunklist
How can i decode all this message I found in File name BaseSystem.chunklist because I use all decode online tool not work at all?
Replies
2
Boosts
0
Views
68
Activity
Apr ’25
Swift MacOS-Check if a file at a URL is open
Hi Is there a way to check if a file at a specified URL is open and being edited by another application. Assuming that we have permission to access the file at the URL.
Replies
4
Boosts
0
Views
204
Activity
Apr ’25
Not Receiving Incoming VoIP Push Notifications on iOS 18.4 (React Native App)
Hi Apple Dev Team, We have a React Native application that includes call functionality using PushKit and VoIP notifications. We are using APNS to send the VoIP notifications, and everything has been working smoothly on iOS versions up to 18.3.1. However, after updating to iOS 18.4, we are no longer receiving incoming VoIP push notifications on the device. There have been no code changes related to our PushKit or notification logic — the exact same build continues to work correctly on devices running iOS 18.3.1 and earlier. We're trying to understand if anything has changed in iOS 18.4 that affects VoIP push delivery or registration behavior. Would appreciate any guidance, and happy to share code snippets or configuration if needed. Thanks in advance!
Replies
1
Boosts
1
Views
175
Activity
Apr ’25
Push payload is not present on notification tap
I am checking if the user taps on the firebase push notification and get the payload. override func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { let userInfo = response.notification.request.content.userInfo os_log("notification tapped %{public}@", log: OSLog.push, type: .info, userInfo) handleNotificationPayload(userInfo as! [String: AnyObject]) setFlutterLinkClickedVariable() } My use case is in app terminated state when push notification is tapped, get the link from payload and navigate to corresponding screen based on the link. This is working when there is only one push notification. When there are multiple push notifications with different links in the payload, only the first notification I tap works. Rest of the notifications just launches the app and does not navigate because the link is not set. I am getting the link from the payload and invoking flutter code which sets the link in the user defaults (shared preferences) and when the app launches in the home screen it checks for this variable and navigates accordingly. func handleNotificationPayload(_ payload: [String: AnyObject]) { if let link = payload["link"] as? String { setFlutterLinkVariable(link) } } override func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { os_log("app did receive remote notification %{public}@", log: OSLog.push, type: .info, userInfo) handleNotificationPayload(userInfo as! [String : AnyObject]) completionHandler(.newData) } Currently when there is only one push notification it works because the link is set from the above method. The click delegate is not calling. I did set the delegate in application(:didFinishLaunchingWithOptions). UNUserNotificationCenter.current().delegate = self application.registerForRemoteNotifications() How to solve this issue? Thanks.
Replies
2
Boosts
0
Views
794
Activity
Apr ’25
How can you tick between live activities?
I have been watching the following moment from wwdc (Design dynamic Live Activities): https://developer.apple.com/videos/play/wwdc2023/10194/?time=728 It suggest that you should 'tick' between multiple live activities of your app: When you want to show multiple sessions for your app going on at once, consider ticking between the display of them to continue to give users an eye on everything that’s going on. How can I tick between them? More specifically how can I do that when my app is in the background?
Replies
1
Boosts
1
Views
250
Activity
Apr ’25
Background Push Notifications for Emergency App Delayed Despite Critical Alert Entitlement
I’m using Appnotic from my server to send notifications for an emergency service, where it is critical that notifications are delivered immediately. My payload looks like this: "aps": { "alert": "Test alert", "sound": { "critical": 1, "name": "sound.wav", "volume": 0.5 }, "content-available": 1, "category": "alert" }, "topic": "com.fireservicerota.FSR-Primary-Alerting", "custom_payload": { "id": "11", "type": "alert", "incident_id": 23434, "incident_response_id": 2652343, "expiration_time": "2024-06-06T16:59:05+01:00" } } I already have the critical alert entitlement and background processing enabled. Everything seems fine when debugging, but I’m experiencing issues: • Some notifications never arrive • Around 60% of notifications arrive with noticeable delay Since this is an emergency app, delivery speed is crucial. What could be causing this inconsistency?
Replies
1
Boosts
0
Views
154
Activity
Apr ’25
VZLinuxBootLoader failed to boot Aarch64 64K kernel
Works: runs-on: ubuntu-24.04-arm container: image: ubuntu:latest env: DEBIAN_FRONTEND: noninteractive steps: - uses: actions/checkout@v4 - run: | apt-get --assume-yes update apt-get --assume-yes install linux-image-generic dracut binutils - run: | dracut --conf $(mktemp) \ --confdir $(mktemp --directory) \ --verbose \ --modules "base bash" \ --add-drivers "virtio-rng bcachefs btrfs virtiofs overlay xfs" \ --kernel-cmdline "console=hvc0" \ --no-early-microcode \ --no-hostonly \ --no-compress \ --no-uefi \ initramfs \ $(ls /lib/modules/) - run: | cp /boot/vmlinuz-$(ls /lib/modules/) vmlinuz - uses: actions/upload-artifact@v4 with: path: | vmlinuz initramfs Will NOT work: runs-on: ubuntu-24.04-arm container: image: ubuntu:latest env: DEBIAN_FRONTEND: noninteractive steps: - uses: actions/checkout@v4 - run: | apt-get --assume-yes update apt-get --assume-yes install linux-image-generic-64k dracut binutils - run: | dracut --conf $(mktemp) \ --confdir $(mktemp --directory) \ --verbose \ --modules "base bash" \ --add-drivers "virtio-rng bcachefs btrfs virtiofs overlay xfs" \ --kernel-cmdline "console=hvc0" \ --no-early-microcode \ --no-hostonly \ --no-compress \ --no-uefi \ initramfs \ $(ls /lib/modules/) - run: | cp /boot/vmlinuz-$(ls /lib/modules/) vmlinuz - uses: actions/upload-artifact@v4 with: path: | vmlinuz initramfs You can try it on Github Actions
Replies
1
Boosts
0
Views
105
Activity
Apr ’25
Safe way to query for the existence of a CKRecordZone?
There's some logic in my app that first checks to see if a specific CloudKit record zone exists. If it doesn't, it creates the zone, and then my application continues on with its work. The way I've implemented this right now is by catching the zoneNotFound error when I call CKDatabase#recordZone(for:) (docs) and creating the zone when that happens: do { try await db.recordZone(for: zoneID) } catch let ckError as CKError where [.zoneNotFound, .userDeletedZone].contains(ckError.code) { // createZone is a helper function try await createZone(zoneID: zoneID, context: context) } This works great, but every time I do this, an error is logged in CloudKit Console, which creates a lot of noise and makes it harder to see real errors. Is there a way to do this without explicitly triggering a CloudKit error? I just found CKDatabase#recordZones(for:) (docs), which seems like it returns an empty array instead of throwing an error if the zone doesn't exist. Will calling that and looking for a non-empty array work just as well, but without logging lots of errors in the console?
Replies
1
Boosts
0
Views
173
Activity
Apr ’25
Network Push Provider Wifi Selection Behavior
In our App, we have a network extension with a NEAppPushProvider subclass running. We run the following steps Setup a dual-band wireless router per the following: Broadcasting 2.4 GHz and 5 GHz channels Same SSID names for both channels Connected to the production network to the router DHCP assigning addresses in the 10.1.x.x network Connect the mobile device to the 5 GHz network (if needed, turn off the 2.4 GHz network temporarily; once the device connects to the 5 GHz network, the 2.4 GHz network can be turned back on). Create a NEAppPushManager in the App, using the SSID from the above mentioned network and set it to the matchSSIDs property. Call saveToPreferences() on the push manager to save. A. We have UI that shows the extension has been started and it has connected to the server successfully. Walk out of the range of the 5 GHz channel of the router, but stay within range of the 2.4ghz channel. Wait for the mobile device to connect to the 2.4 GHz channel. Expected: The extension would reconnect to the 2.4ghz network. Observed: The extension does not reconnect. Checking the logs for the extension we see that the following was called in the push provider subclass. stop(with:completionHandler:) > PID: 808 | 🗒️🛑 Stopped with reason 3: "noNetworkAvailable" The expectation is that start() on the NEAppPushProvider subclass would be called. Is this an incorrect expectation? How does the NEAppPushProvider handle same network SSID roaming among various band frequencies? I looked at the documentation and did not find any settings targeting 2.4 or 5 ghz networks. Please advise on what to do.
Replies
5
Boosts
1
Views
145
Activity
Apr ’25
Core Data crash while trying to merge
I'm looking for guidance how to mitigate this crash. It seems super deep inside Core Data' FRC fetchedObjects management. In my code, it's initiated by this viewContext.perform { [unowned self] in self.viewContext.mergeChanges(fromContextDidSave: notification) } which is directly followed by the stack trace below. Basically merging data from .NSManagedObjectContextDidSave notification from another NSManagedObjectContext. Nothing special, it works great for years, apart from these rare occurrences. Exception Type: EXC_CRASH (SIGABRT) Exception Codes: 0x0000000000000000, 0x0000000000000000 Exception Reason: -[__NSCFArray objectAtIndex:]: index (235) beyond bounds (234) Termination Reason: SIGNAL 6 Abort trap: 6 Triggered by Thread: 0 Last Exception Backtrace: 0 CoreFoundation 0x199e947cc __exceptionPreprocess + 164 (NSException.m:249) 1 libobjc.A.dylib 0x1971672e4 objc_exception_throw + 88 (objc-exception.mm:356) 2 CoreFoundation 0x199fc4258 _NSArrayRaiseBoundException + 368 (NSCFArray.m:22) 3 CoreFoundation 0x199e288a4 -[__NSCFArray objectAtIndex:] + 200 (NSCFArray.m:42) 4 CoreData 0x1a1e17338 -[_PFMutableProxyArray objectAtIndex:] + 40 (_PFArray.m:1860) 5 CoreData 0x1a1e1673c -[NSFetchedResultsController _updateFetchedObjectsWithInsertChange:] + 380 (NSFetchedResultsController.m:1582) 6 CoreData 0x1a1e1426c __82-[NSFetchedResultsController(PrivateMethods) _core_managedObjectContextDidChange:]_block_invoke + 2240 (NSFetchedResultsController.m:2171) 7 CoreData 0x1a1dcdf80 developerSubmittedBlockToNSManagedObjectContextPerform + 156 (NSManagedObjectContext.m:4002) 8 CoreData 0x1a1e41a44 -[NSManagedObjectContext performBlockAndWait:] + 216 (NSManagedObjectContext.m:4113) 9 CoreData 0x1a1e41034 -[NSFetchedResultsController _core_managedObjectContextDidChange:] + 124 (NSFetchedResultsController.m:2379) 10 CoreFoundation 0x199e632f4 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 148 (CFNotificationCenter.c:701) 11 CoreFoundation 0x199e63210 ___CFXRegistrationPost_block_invoke + 88 (CFNotificationCenter.c:194) 12 CoreFoundation 0x199e63158 _CFXRegistrationPost + 436 (CFNotificationCenter.c:222) 13 CoreFoundation 0x199e6170c _CFXNotificationPost + 728 (CFNotificationCenter.c:1248) 14 Foundation 0x198a84ea4 -[NSNotificationCenter postNotificationName:object:userInfo:] + 92 (NSNotification.m:531) 15 CoreData 0x1a1e11650 -[NSManagedObjectContext _createAndPostChangeNotification:deletions:updates:refreshes:deferrals:wasMerge:] + 1736 (NSManagedObjectContext.m:8098) 16 CoreData 0x1a1e10e0c -[NSManagedObjectContext _postRefreshedObjectsNotificationAndClearList] + 164 (NSManagedObjectContext.m:7631) 17 CoreData 0x1a1e0fad8 -[NSManagedObjectContext _processRecentChanges:] + 100 (NSManagedObjectContext.m:7714) 18 CoreData 0x1a1e3563c -[NSManagedObjectContext _coreMergeChangesFromDidSaveDictionary:usingObjectIDs:withClientQueryGeneration:] + 3436 (NSManagedObjectContext.m:3723) 19 CoreData 0x1a1e34350 __116+[NSManagedObjectContext(_NSCoreDataSPI) _mergeChangesFromRemoteContextSave:intoContexts:withClientQueryGeneration:]_block_invoke_4 + 76 (NSManagedObjectContext.m:9531) 20 CoreData 0x1a1dcdf80 developerSubmittedBlockToNSManagedObjectContextPerform + 156 (NSManagedObjectContext.m:4002) 21 CoreData 0x1a1e41a44 -[NSManagedObjectContext performBlockAndWait:] + 216 (NSManagedObjectContext.m:4113) 22 CoreData 0x1a1e39880 +[NSManagedObjectContext _mergeChangesFromRemoteContextSave:intoContexts:withClientQueryGeneration:] + 2372 (NSManagedObjectContext.m:9537) 23 CoreData 0x1a1e344a0 -[NSManagedObjectContext mergeChangesFromContextDidSaveNotification:] + 292 (NSManagedObjectContext.m:0)
Replies
1
Boosts
0
Views
81
Activity
Apr ’25
HealthKit: Real-Time Sleep Tracking with Heart Rate Data
I am trying to track a user's real-time sleep state using heart rate data, but I have encountered several issues: When using HKSampleQuery on the phone to fetch heart rate data, I can only retrieve data recorded before the app comes to the foreground or before it is terminated and restarted (see related issue: https://developer.apple.com/forums/thread/774953). I attempted to get data on the Apple Watch and send updates to the phone via Watch Connectivity. However, if I use WKExtendedRuntimeSession, although I can obtain data on the watch, once the watch screen goes off, it can no longer transmit data via Watch Connectivity to the phone (since I cannot guarantee the app will remain in the foreground when lying in bed). On the other hand, using HKWorkoutSession results in interference with the activity rings and causes the heart rate sensor to run too frequently, which I worry may affect the battery life of the watch. Is there an elegant solution for tracking a user's heart rate data for sleep monitoring?
Replies
1
Boosts
0
Views
130
Activity
Apr ’25
Synchronization Timing Between Apple Watch HealthKit Store and iPhone HealthKit Store
Hi, I’m currently working on an app that utilizes sleep data from HealthKit to provide users with meaningful insights about their sleep. To ensure a smooth user experience, I’d like to understand when sleep data collected by the Apple Watch is saved to the HealthKit store and when it gets synced to the iPhone. Ideally, I want to fetch sleep data right after the user wakes up and opens our app. However, to do this reliably, I need to know the timing of how and when this data becomes available in the iPhone’s HealthKit store. I’ve looked through the official documentation and relevant WWDC sessions but couldn’t find clear information on this topic. If anyone has insights or experience with how and when the Apple Watch syncs HealthKit data—especially sleep records—to the iPhone, I’d greatly appreciate your input. Thanks!
Replies
1
Boosts
0
Views
141
Activity
Apr ’25
Detecting Sleep End Events and Sleep Data Sync Timing from Apple Watch to HealthKit on iPhone
Hello, I’m developing an iOS app that works with sleep data from Apple Watch via HealthKit. I would like to clarify the following: How can an iPhone app detect when a sleep session ends on the Apple Watch? When is sleep data typically written to the HealthKit store on iPhone after sleep ends? Is it immediately after wake-up, or does it depend on certain conditions (e.g., watch charging, connectivity)? Understanding the timing and mechanism of sleep data synchronization is crucial for our app to process accurate and timely health information. Thank you for your assistance.
Replies
1
Boosts
0
Views
101
Activity
Apr ’25
Can HKWorkoutSession be used for a lone worker protection app for the Apple Watch?
We are developing a mobile app focused on lone worker protection, which does not include any fitness tracking features. We require the use of HKWorkoutSession solely to enable background execution of critical safety-related code. Could you please confirm whether this use of HKWorkoutSession is permitted under App Store Review guidelines, given that our app does not offer fitness or workout-related functionality?
Replies
1
Boosts
1
Views
191
Activity
Apr ’25