Posts under App & System Services topic

Post

Replies

Boosts

Views

Created

NWListener, P2P and awdl interfaces
I'm attempting to create a service that: Listens on iOS device A using NWListener Broadcasts the NWService ( using NWListener(service:using:)) ) on Bonjour Allows a separate device, iOS device B, to receive information about that service via an NWBrowser Connect to that service using the information contained in NWBrowser.Result 's NWEndpoint I've been able to successfully do this using a SwiftNIO service, in the following environments: iOS device A and iOS device B are physical iOS devices on the same WiFi network. This works. iOS device A and iOS device B are iOS simulators on the same machine. This works. iOS device A is a physical device, and iOS device B is a simulator. iOS device A is not connected to a WiFi network, iOS device B is connected to a WiFi network. This works. However, when iOS device A and iOS device B are physical devices that are not connected to a WiFi network, I encounter the following behavior: The Bonjour service is correctly advertised, and iOS device A and iOS device B are able to observe the advertisement of the service. In both cases, iOS device A and iOS device B, while able to resolve an NWEndpoint for the Bonjour service, are not able to connect to each other, and the connection attempt hangs. My setup for the listener side of things looks roughly like: let opts: NWParameters = .tcp opts.includePeerToPeer = true opts.allowLocalEndpointReuse = true let service = NWListener.Service(name: "aux", type: BONJOUR_SERVICE_TYPE, domain: "") try bootstrap.withNWListener(NWListener(service: service, using: opts)).wait() // bootstrap is an artifact of using SwiftNIO Similarly, my setup on the discovery side of things looks like: let params: NWParameters = .tcp params.includePeerToPeer = true let browser = NWBrowser(for: .bonjour(type: BONJOUR_SERVICE_TYPE, domain: BONJOUR_SERVICE_DOMAIN), using: params) browser.browseResultsChangedHandler =  { (searchResults, changed) in // save the result to pass on its NWEndpoint later } and finally, where I have an NWEndpoint, I use SwiftNIO's NIOTSConnectionBootstrap.connect(endpoint:) to initialize a connection to my TCP service ( a web socket server ). The fact that I am able to get P2P networking (presumably over an awdl interface?) between the simulator and the iOS device suggests to me that I haven't done anything obviously wrong in my setup. Similarly, the fact that it works over the same WiFi network and that, in P2P, I am able to at least observe the Bonjour advertisement, strikes me that I'm somewhere in the right neighborhood of getting this to work. I've also ensured that my Info.plist for the app has a NSLocalNetworkUsageDescription and NSBonjourServices for the Bonjour service type I'm browsing for. I've even attempted to exercise the "Local Network Permission" dialog by using a hacky attempt that sends data to a local IP in order to trigger a permissions dialog, though the hack does not appear to actually force the dialog to appear. Is there some trick or other piece of knowledge regarding allowing the use of P2P w/ Network.framework and TCP connections to services?
7
0
2.1k
Oct ’22
HKAnchoredObjectQuery updateHandler stops working with error
Hi! I am using the HKAnchoredObjectQuery to first get a snapshot of the initial results, and then trigger an updateHandler. I need to handle the initial results and the updates separately, which is why I implemented two completions. When I test the code, it works for a while. New and deleted samples trigger the updateHandler. However, after a while there appears an error: [connection] nw_read_request_report [C2] Receive failed with error "Software caused connection abort" Followingly, the updateHandler will stop getting triggered when I add updates in Apple health. Anyone have experience with this? func getMostRecentSample(for sampleType: HKSampleType, anchorKey: String, completion: @escaping (HKQuantitySample?, Error?) -> Swift.Void, updateHandler: @escaping (HKQuantitySample, Error?) -> Swift.Void) {     // If it is the first initialization, anchor is passed as nil     var anchor: HKQueryAnchor? = nil // Check for previous saved anchor in userdefaults     if UserDefaults.standard.object(forKey: anchorKey) != nil {       let data = UserDefaults.standard.object(forKey: anchorKey) as! Data       do {         guard let newAnchor = try NSKeyedUnarchiver.unarchivedObject(ofClass: HKQueryAnchor.self, from: data) else {           print("Could not parse anchor to HKQueryAnchor type")           return         }         anchor = newAnchor       } catch {         print("Error retreiving anchor from UserDefaults")       }     }     let query = HKAnchoredObjectQuery(type: sampleType,                      predicate: nil,                      anchor: anchor,                      limit: HKObjectQueryNoLimit                       ) { (query, samplesOrNil, _, newAnchor, errorOrNil) in       guard let samples = samplesOrNil as? [HKQuantitySample] else {         fatalError("*** An error occurred during the initial query: \(errorOrNil!.localizedDescription) ***")       }       if let anchor = newAnchor {         do {           let data = try NSKeyedArchiver.archivedData(withRootObject: anchor as Any, requiringSecureCoding: false)           UserDefaults.standard.set(data, forKey: anchorKey)         } catch {           print("Error retreiving anchor from UserDefaults")         }       }       completion(samples.last, nil)     }           // Setting up long-running query     query.updateHandler = { (query, samplesOrNil, _, newAnchor, errorOrNil) in       guard let samples = samplesOrNil as? [HKQuantitySample] else {         fatalError("*** An error occurred during an update: \(errorOrNil!.localizedDescription) ***")       }       if let anchor = newAnchor {         do {           let data = try NSKeyedArchiver.archivedData(withRootObject: anchor as Any, requiringSecureCoding: false)           UserDefaults.standard.set(data, forKey: anchorKey)         } catch {           print("Error retreiving anchor from UserDefaults")         }       }       if let sample = samples.last {         updateHandler(sample, nil)       }     }     self.healthStore.execute(query)   }
2
0
1.1k
Oct ’22
CGColorRef is NOT a struct
The documentation for CGColorRef (https://developer.apple.com/documentation/coregraphics/cgcolorref?language=objc) clearly shows that it is a struct. However, when I try to store a cell's border color using CGColorRef originalColor = self.bg.layer.borderColor and inspect what happens in the debugger, both that property and its copy have the same address. And later when I try to restore the border color the copy still has the same address but is no longer valid and causes a crash on assignment (originalColor is actually an instance variable...) This is all object behavior, not struct behavior. If CGColorRef really was a struct, the contents would have been copied, the instance variable would have had its own address that would never have changed, and the value would have remained valid indefinitely and let me copy it back without a problem. Why is this documented wrong? Was this a recent change? I actually had this code working at some point, and now it's broken.
9
0
1k
Oct ’22
Is a 3-way merge possible when resolving CloudKit conflicts?
I'm trying to handle the serverRecordChanged return code you get in CKError when you have a conflict and your using the savePolicy of ifServerRecordUnchanged. According to the CKError.Code.serverRecordChanged documentation, I should be receiving all three records that I need to do a 3-way merge. The problem is that the ancestorRecord (CKRecordChangedErrorAncestorRecordKey can also be used to look it up in the userInfo) doesn't actually contain a record. It only contains the record metadata. Is there something I need to be doing to get the full ancestorRecord in the CKError? If not is it possible to query iCloud for the ancestorRecord? Given that iCloud has the change history (as I understand it), then it is theoretically possible. I just don't know how to do it if it is possible. Are 3-way merges even possible? The design of the serverRecordChanged looks like that is the intent, but I can't see how to do it with the data that CloudKit is providing.
2
2
768
Nov ’22
DriverKit: Check that driver is enabled on iPadOS
Apple Docs mentions that driver should be approved(enabled) in Settings app. I wonder is there any API available to check that driver is not enabled? To my mind, App with driver should have a following flow: Run App Check that driver is(not) enabled Display message(alert) and ask to enable driver in Settings. Optionally: provide shortcut to exact Settings page Unfortunately, it's not obvious how to check that driver is enabled.
3
0
1.3k
Nov ’22
Unknown Error when Trying to Add New Offer Codes
Hi there! Whenever I try to add a new Offer Code for my app's subscription, I get an unknown error. When I get to the last step of the "Create Offer for Codes" flow, I get an error that error reads "An error has occurred. Try again later." I have been getting this same error for over a week now, so any help figuring out how to add new offer codes would be greatly appreciated!
2
1
547
Nov ’22
Open parent app from ShieldAction extension in iOS
When I tap on one of the buttons in the ShieldAction extension I want to close the shield and open the parent app instead of the shielded app. Is there any way of doing this using the Screen Time API? class ShieldActionExtension: ShieldActionDelegate {      override func handle(action: ShieldAction, for application: ApplicationToken, completionHandler: @escaping (ShieldActionResponse) -> Void) {     // Handle the action as needed.           let store = ManagedSettingsStore()               switch action {     case .primaryButtonPressed:       //TODO - open parent app       completionHandler(.defer)     case .secondaryButtonPressed:       //remove shield       store.shield.applications?.remove(application)       completionHandler(.defer)         @unknown default:       fatalError()     }   }   }
10
7
5k
Nov ’22
iOS 16 recurring payment configuration not reflecting in UI
We are integrating iOS 16 recurring payments in our app, everything works fine but we have a few questions Question 1 let recurringPaymentRequest = PKRecurringPaymentRequest(         paymentDescription: "Pro Membership",         regularBilling: regularBilling,         managementURL: url       ) we assume managementURL is supposed to come in the user's wallet where he/she can tap to change the recurring payment option to our backend, but in the wallet, the transaction appears without this URL and have no indication that it is a recurring payment, Can someone guide what we missed Question 2 For apps that only have apple pay on mobile, managementURL can open the app as a deep link from the Wallet app and the user can update or delete the payment method for the automatic reload payment from the app directly, Question 3 For cancellation, the recurring payment app should have some UI where the user can tap which hit our backend and remove the apple pay merchant token from our system and apply cancellation business logic, no apple API involves in the cancellation of recurring payment
2
0
1.3k
Nov ’22
How to whitelist Apple to access AASA file?
We have implemented Universal Links for iOS. We have deployed the following file as per the documentation: /.well-known/apple-app-site-association Everything works fine until my organization applied domain-level block on traffic out side my country. We need to whitelist Apple servers but we cannot find their IPs or domains used to access this file.
3
0
2.2k
Nov ’22
iOS Network Signal Strength
This issue has cropped up many times here on DevForums. Someone recently opened a DTS tech support incident about it, and I used that as an opportunity to post a definitive response here. If you have questions or comments about this, start a new thread and tag it with Network so that I see it. Share and Enjoy — Quinn “The Eskimo!” @ Developer Technical Support @ Apple let myEmail = "eskimo" + "1" + "@" + "apple.com" iOS Network Signal Strength The iOS SDK has no general-purpose API that returns Wi-Fi or cellular signal strength in real time. Given that this has been the case for more than 10 years, it’s safe to assume that it’s not an accidental omission but a deliberate design choice. For information about the Wi-Fi APIs that are available on iOS, see TN3111 iOS Wi-Fi API overview. Network performance Most folks who ask about this are trying to use the signal strength to estimate network performance. This is a technique that I specifically recommend against. That’s because it produces both false positives and false negatives: The network signal might be weak and yet your app has excellent connectivity. For example, an iOS device on stage at WWDC might have terrible WWAN and Wi-Fi signal but that doesn’t matter because it’s connected to the Ethernet. The network signal might be strong and yet your app has very poor connectivity. For example, if you’re on a train, Wi-Fi signal might be strong in each carriage but the overall connection to the Internet is poor because it’s provided by a single over-stretched WWAN. The only good way to determine whether connectivity is good is to run a network request and see how it performs. If you’re issuing a lot of requests, use the performance of those requests to build a running estimate of how well the network is doing. Indeed, Apple practices what we preach here: This is exactly how HTTP Live Streaming works. Remember that network performance can change from moment to moment. The user’s train might enter or leave a tunnel, the user might step into a lift, and so on. If you build code to estimate the network performance, make sure it reacts to such changes. Keeping all of the above in mind, iOS 26 beta has two new APIs related to this issue: Network framework now offers a linkQuality property. See this post for my take on how to use this effectively. The WirelessInsights framework can notify you of anticipated WWAN condition changes. But what about this code I found on the ’net? Over the years various folks have used various unsupported techniques to get around this limitation. If you find code on the ’net that, say, uses KVC to read undocumented properties, or grovels through system logs, or walks the view hierarchy of the status bar, don’t use it. Such techniques are unsupported and, assuming they haven’t broken yet, are likely to break in the future. But what about Hotspot Helper? Hotspot Helper does have an API to read Wi-Fi signal strength, namely, the signalStrength property. However, this is not a general-purpose API. Like the rest of Hotspot Helper, this is tied to the specific use case for which it was designed. This value only updates in real time for networks that your hotspot helper is managing, as indicated by the isChosenHelper property. But what about MetricKit? MetricKit is so cool. Amongst other things, it supports the MXCellularConditionMetric payload, which holds a summary of the cellular conditions while your app was running. However, this is not a real-time signal strength value. But what if I’m working for a carrier? This post is about APIs in the iOS SDK. If you’re working for a carrier, discuss your requirements with your carrier’s contact at Apple. Revision History 2025-07-02 Updated to cover new features in the iOS 16 beta. Made other minor editorial changes. 2022-12-01 First posted.
0
0
4.3k
Dec ’22
NSPersistentCloudKitContainer - Import failed with error: Error Domain=NSCocoaErrorDomain Code=4864
The NSPersistentCloudKitContainer synchronization between core data and iCloud was working fine with phone 15.1. Connected a new iPhone iOS 15.5, it gives error: CoreData: debug: CoreData+CloudKit: -[NSCloudKitMirroringDelegate managedObjectContextSaved:](2504): <NSCloudKitMirroringDelegate: 0x28198c000>: Observed context save: <NSPersistentStoreCoordinator: 0x2809c9420> - <NSManagedObjectContext: 0x2819ad520> 2022-12-05 13:32:28.377000-0600 r2nr[340:6373] [error] error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _importFinishedWithResult:importer:](1245): <PFCloudKitImporter: 0x2837dd740>: Import failed with error: Error Domain=NSCocoaErrorDomain Code=4864 "*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x61)" UserInfo={NSDebugDescription=*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x61)} CoreData: error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _importFinishedWithResult:importer:](1245): <PFCloudKitImporter: 0x2837dd740>: Import failed with error: Error Domain=NSCocoaErrorDomain Code=4864 "*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x61)" UserInfo={NSDebugDescription=*** -[NSKeyedUnarchiver _initForReadingFromData:error:throwLegacyExceptions:]: incomprehensible archive (0x53, 0x6f, 0x6d, 0x65, 0x20, 0x65, 0x78, 0x61)} I go back and try with my old iPhone iOS 15.1, gives same error.
2
1
1k
Dec ’22
Implementing a virtual serial port using DriverKit/SerialDriverKit
I'm trying to implement a virtual serial port driver for my ham radio projects which require emulating some serial port devices and I need to have a "backend" to translate the commands received by the virtual serial port into some network-based communications. I think the best way to do that is to subclass IOUserSerial? Based on the available docs on this class (https://developer.apple.com/documentation/serialdriverkit/iouserserial), I've done the basic implementation below. When the driver gets loaded, I can see sth like tty.serial-1000008DD in /dev and I can use picocom to do I/O on the virtual serial port. And I see TxDataAvailable() gets called every time I type a character in picocom. The problems are however, firstly, when TxDataAvailable() is called, the TX buffer is all-zero so although the driver knows there is some incoming data received from picocom, it cannot actually see the data in neither Tx/Rx buffers. Secondly, I couldn't figure out how to notify the system that there are data available for sending back to picocom. I call RxDataAvailable(), but nothing appears on picocom, and RxFreeSpaceAvailable() never gets called back. So I think I must be doing something wrong somewhere. Really appreciate it if anyone could point out how should I fix it, many thanks! VirtualSerialPortDriver.cpp: constexpr int bufferSize = 2048; using SerialPortInterface = driverkit::serial::SerialPortInterface; struct VirtualSerialPortDriver_IVars {     IOBufferMemoryDescriptor *ifmd, *rxq, *txq;     SerialPortInterface *interface;     uint64_t rx_buf, tx_buf;     bool dtr, rts; }; bool VirtualSerialPortDriver::init() {     bool result = false;     result = super::init();     if (result != true)     {         goto Exit;     }     ivars = IONewZero(VirtualSerialPortDriver_IVars, 1);     if (ivars == nullptr)     {         goto Exit;     }     kern_return_t ret;     ret = ivars->rxq->Create(kIOMemoryDirectionInOut, bufferSize, 0, &ivars->rxq);     if (ret != kIOReturnSuccess) {         goto Exit;     }     ret = ivars->txq->Create(kIOMemoryDirectionInOut, bufferSize, 0, &ivars->txq);     if (ret != kIOReturnSuccess) {         goto Exit;     }     IOAddressSegment ioaddrseg;     ivars->rxq->GetAddressRange(&ioaddrseg);     ivars->rx_buf = ioaddrseg.address;     ivars->txq->GetAddressRange(&ioaddrseg);     ivars->tx_buf = ioaddrseg.address;     return true; Exit:     return false; } kern_return_t IMPL(VirtualSerialPortDriver, HwActivate) {     kern_return_t ret;     ret = HwActivate(SUPERDISPATCH);     if (ret != kIOReturnSuccess) {         goto Exit;     }     // Loopback, set CTS to RTS, set DSR and DCD to DTR     ret = SetModemStatus(ivars->rts, ivars->dtr, false, ivars->dtr);     if (ret != kIOReturnSuccess) {         goto Exit;     } Exit:     return ret; } kern_return_t IMPL(VirtualSerialPortDriver, HwDeactivate) {     kern_return_t ret;     ret = HwDeactivate(SUPERDISPATCH);     if (ret != kIOReturnSuccess) {         goto Exit;     } Exit:     return ret; } kern_return_t IMPL(VirtualSerialPortDriver, Start) {     kern_return_t ret;   ret = Start(provider, SUPERDISPATCH);     if (ret != kIOReturnSuccess) {         return ret;     }     IOMemoryDescriptor *rxq_, *txq_;     ret = ConnectQueues(&ivars->ifmd, &rxq_, &txq_, ivars->rxq, ivars->txq, 0, 0, 11, 11);     if (ret != kIOReturnSuccess) {         return ret;     }     IOAddressSegment ioaddrseg;     ivars->ifmd->GetAddressRange(&ioaddrseg);     ivars->interface = reinterpret_cast<SerialPortInterface*>(ioaddrseg.address);     SerialPortInterface &intf = *ivars->interface;     ret = RegisterService();     if (ret != kIOReturnSuccess) {         goto Exit;     }     TxFreeSpaceAvailable(); Exit:     return ret; } void IMPL(VirtualSerialPortDriver, TxDataAvailable) {     SerialPortInterface &intf = *ivars->interface;     // Loopback     // FIXME consider wrapped case     size_t tx_buf_sz = intf.txPI - intf.txCI;     void *src = reinterpret_cast<void *>(ivars->tx_buf + intf.txCI); //    char src[] = "Hello, World!";     void *dest = reinterpret_cast<void *>(ivars->rx_buf + intf.rxPI);     memcpy(dest, src, tx_buf_sz);     intf.rxPI += tx_buf_sz;     RxDataAvailable();     intf.txCI = intf.txPI;     TxFreeSpaceAvailable();     Log("[TX Buf]: %{public}s", reinterpret_cast<char *>(ivars->tx_buf));     Log("[RX Buf]: %{public}s", reinterpret_cast<char *>(ivars->rx_buf)); // dmesg confirms both buffers are all-zero     Log("[TX] txPI: %d, txCI: %d, rxPI: %d, rxCI: %d, txqoffset: %d, rxqoffset: %d, txlogsz: %d, rxlogsz: %d",         intf.txPI, intf.txCI, intf.rxPI, intf.rxCI, intf.txqoffset, intf.rxqoffset, intf.txqlogsz, intf.rxqlogsz); } void IMPL(VirtualSerialPortDriver, RxFreeSpaceAvailable) {     Log("RxFreeSpaceAvailable() called!"); } kern_return_t   IMPL(VirtualSerialPortDriver,HwResetFIFO){     Log("HwResetFIFO() called with tx: %d, rx: %d!", tx, rx);     kern_return_t ret = kIOReturnSuccess;     return ret; } kern_return_t   IMPL(VirtualSerialPortDriver,HwSendBreak){     Log("HwSendBreak() called!");     kern_return_t ret = kIOReturnSuccess;     return ret; } kern_return_t   IMPL(VirtualSerialPortDriver,HwProgramUART){     Log("HwProgramUART() called, BaudRate: %u, nD: %d, nS: %d, P: %d!", baudRate, nDataBits, nHalfStopBits, parity);     kern_return_t ret = kIOReturnSuccess;     return ret; }      kern_return_t   IMPL(VirtualSerialPortDriver,HwProgramBaudRate){     Log("HwProgramBaudRate() called, BaudRate = %d!", baudRate);     kern_return_t ret = kIOReturnSuccess;     return ret; } kern_return_t   IMPL(VirtualSerialPortDriver,HwProgramMCR){     Log("HwProgramMCR() called, DTR: %d, RTS: %d!", dtr, rts);     ivars->dtr = dtr;     ivars->rts = rts;     kern_return_t ret = kIOReturnSuccess; Exit:     return ret; } kern_return_t  IMPL(VirtualSerialPortDriver, HwGetModemStatus){     *cts = ivars->rts;     *dsr = ivars->dtr;     *ri = false;     *dcd = ivars->dtr;     Log("HwGetModemStatus() called, returning CTS=%d, DSR=%d, RI=%d, DCD=%d!", *cts, *dsr, *ri, *dcd);     kern_return_t ret = kIOReturnSuccess;     return ret; } kern_return_t   IMPL(VirtualSerialPortDriver,HwProgramLatencyTimer){     Log("HwProgramLatencyTimer() called!");     kern_return_t ret = kIOReturnSuccess;     return ret; } kern_return_t   IMPL(VirtualSerialPortDriver,HwProgramFlowControl){     Log("HwProgramFlowControl() called! arg: %u, xon: %d, xoff: %d", arg, xon, xoff);     kern_return_t ret = kIOReturnSuccess; Exit:     return ret; }
1
0
2.1k
Dec ’22
Hourly precipitation amounts seem drastically low
Hello. I took a closer look at the data I'm getting back for hourly forecasts and I'm baffled by results I'm seeing. For example, it's Dec 19, 2022 8:00am PT and I'm asking for the weather for Orchard Park NY (lat 42.766437 long -78.743855) for Dec 23, 2022. The daily forecast tells me they're expected to have 5.9" of snow. However, the hourly forecast with the most snow that day is reported as 0.071" (1.8mm). The Apple Weather app on iOS shows that hour as having 0.6". I wrote a 'for' loop to print the results of my call to WeatherService.shared.weather.         print(oneHour.precipitationAmount.formatted())         print(oneHour.precipitationAmount.description)         print(oneHour.precipitationAmount.unit)         print(oneHour.precipitationAmount.value) 0.071 in 1.8 mm <_NSStatic_NSUnitLength: 0x2010b0178> mm 1.8
9
0
2.5k
Dec ’22
Unfinished transactions not being emitted on start of app
I'm using the iOS simulator with a StoreKit configuration file. I can see that there have been transactions while the app has been closed, but my StoreKit 2 listener is never called with those updates to be able to finish them When I open my app from a cold start. I've added a listener on application(_:didFinishLaunching:launchOptions:) like this: func startObservingTransactions() { task = Task(priority: .background) { for await result in Transaction.updates { if case .verified(let transaction) = result { await transaction.finish() } } } } But the Transaction.updates loop never gets called (have added breakpoints to check). It's only ever called when a purchase is made, or subsequent transaction renewals when the app is open. Only then it will get the previously unfinished transactions. Steps to reproduce: Create an app with a StoreKit config file (with sped up transactions) to purchase an item Make a purchase then quit the app Wait for a bit for more transactions to be made while the app is closed. Open the app from a cold start and none of the transactions will be finished by the listener in your app. Cancel the subscription via the transaction manager. Close and open the app from a cold start. The first transaction will be finished by the listener but none of the others will be. In Apple's docs it says If your app has unfinished transactions, the listener receives them immediately after the app launches Why is this not the case?
15
2
5.5k
Dec ’22
SimpleFirewall sample application not working
I can build the SimpleFirewall application (https://developer.apple.com/documentation/networkextension/filtering_network_traffic ) using xcode: After I run the application, seems can't block any traffic. I find there is some logs from network extension process: networkd_settings_read_from_file Sandbox is preventing this process from reading networkd settings file at "/Library/Preferences/com.apple.networkd.plist", please add an exception. Any step I am missing ?
3
0
922
Dec ’22
URLSessionDownloadTaskDelegate functions not called when using URLSession.download(for:), but works when using URLSession.downloadTask(with:)
I'm struggling to understand why the async-await version of URLSession download task APIs do not call the delegate functions, whereas the old non-async version that returns a reference to the download task works just fine. Here is my sample code: class DownloadDelegate: NSObject, URLSessionDownloadDelegate { func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) { // This only prints the percentage of the download progress. let calculatedProgress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite) let formatter = NumberFormatter() formatter.numberStyle = .percent print(formatter.string(from: NSNumber(value: calculatedProgress))!) } } // Here's the VC. final class DownloadsViewController: UIViewController { private let url = URL(string: "https://pixabay.com/get/g0b9fa2936ff6a5078ea607398665e8151fc0c10df7db5c093e543314b883755ecd43eda2b7b5178a7e613a35541be6486885fb4a55d0777ba949aedccc807d8c_1280.jpg")! private let delegate = DownloadDelegate() private lazy var session = URLSession(configuration: .default, delegate: delegate, delegateQueue: nil) // for the async-await version private var task: Task&lt;Void, Never&gt;? // for the old version private var downloadTask: URLSessionDownloadTask? override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) task?.cancel() task = nil task = Task { let (_, _) = try! await session.download(for: URLRequest(url: url)) self.task = nil } // If I uncomment this, the progress listener delegate function above is called. // downloadTask?.cancel() // downloadTask = nil // downloadTask = session.downloadTask(with: URLRequest(url: url)) // downloadTask?.resume() } } What am I missing here?
5
1
2k
Jan ’23
StoreKit2: .purchase() not working after expiry of subscription in app, but renewing in AppStore sandbox does...
Hi, thanks for reading my question. I need help with some odd behaviour with product.purchase() not triggering a confirmation dialog after a subscription has expired and trying to purchase it again. Seeing this in iOS 16.2 and 15.7.2 (haven't tried any other versions) on actual devices, not in simulator. I'm using a sandbox user on the sandbox environment (not using the local store kit config file testing option). Using a newly created sandbox user, first subscription purchase goes through just fine, dialog box pops up, login with sandbox user, get confirmation of purchase and then Transaction.currentEntitlements has one item as expected. It auto renews for 12 times (each time Transaction.currentEntitlements contains the correct results) and then expires, as expected for sandbox. Transaction.currentEntitlements is then also empty, as expected. All good so far. Now I want to test purchasing it again...Call product.purchase() again to renew/start a new subscription and nothing happens, no confirm purchase dialog box pops up at all. The purchase function simply exits BUT returns success (as in the following gets called) but in self.updatePurchasedProducts(), Transaction.currentEntitlements is empty. case let .success(.verified(transaction)):      // Successful purchase       await transaction.finish()      await self.updatePurchasedProducts() if I instead go to Settings->App Store->Sandbox User-> Manage Subscriptions and renew the subscription there, instead of in my app, then Transaction.currentEntitlements has a new entry and all is good again. Alternatively, if I create yet another new sandbox user and logout of the old one I was using, I am once again able to purchase from within the app, so .purchase() once again works as normal. Is there something I am missing about expired subscriptions and trying to purchase them again in the app? Is this a sandbox issue and in production I'll have no problem? The sandbox user has purchasing enabled in Settings->App Store. I've also tried calling AppStore.sync() (which is in my "Restore Purchase" button) before calling product.purchase() after the subscription stops renewing, expires and this issue comes up, doesn't resolve it. Also have a less important question, the initial call to product.purchase(), the one that works as expected, has a bit of a delay before the confirmation dialog pops up, a few seconds, which will probably result in the user clicking the buy button again thinking it didn't work. Is a bit of a delay normal for sandbox? Will it be ok in production? When it fails, and I have to renew in Settings->AppStore->Sandbox user, there's also a bit of a delay after I return to my app, 5-15 or so seconds, before the transaction observer fires and currentEntitlements is checked again, is there a way to reduce this delay? Thank you! Colin @MainActor class IAPManager: NSObject, ObservableObject {  // removed other functions.....   func purchase(_ product: Product) async throws {    let result = try await product.purchase()     switch result {    case let .success(.verified(transaction)):      // Successful purchase       await transaction.finish()      await self.updatePurchasedProducts()    case let .success(.unverified(_, error)):       break     case .pending:       break     case .userCancelled:       break     @unknown default:       break   } }  func updatePurchasedProducts() async {     for await result in Transaction.currentEntitlements {       guard case .verified(let transaction) = result else {         continue       }       if transaction.revocationDate == nil {         self.purchasedProductIDs.insert(transaction.productID)       } else {         self.purchasedProductIDs.remove(transaction.productID)       }     }   } }
14
8
11k
Jan ’23
IntentDonationManager not donating Shortcuts
if #available(iOS 16.0, *) {       print("donated")       let intent = BasicIntent()       IntentDonationManager.shared.donate(intent: intent)    } Trying to test if donations work with the new App Intents framework. Donating the shortcut once a user taps a button. The shortcut is not appearing on the lock screen. Everything else is working as expected. The Shortcut is appearing in the Shortcuts App and is working via Siri. In developer settings I have Display Recent Shortcuts -> On Display Donations on Lock Screen -> On Allow Any domain -> On Allow Unverified sources -> On Running iOS 16.2, iPhone 11.
8
2
2.5k
Jan ’23
DeviceActivityReport inconsistencies
Hello, I want to echo the DeviceActivityReport "concurrency" problems flagged in https://developer.apple.com/forums/thread/720549, and ask a related question. (Thanks to Kmart and other Apple dev support folks who have been monitoring these forums and responding diligently.) I would like to display daily and weekly stats in the same view, broken down by specific apps (as in the native Screen Time). However, instantiating multiple DeviceActivityReport objects with different filters and/or different contexts leads to confusion, where the two views will incorrectly and intermittently swap data or duplicate data where it shouldn't (seemingly upon some interval when the extension provides fresh data). There isn't documentation on how to display multiple reports at once. Is the idea that logic for multiple reports should be embedded within the extension itself in the makeConfiguration() function and there should only be a single DeviceActivityReport in the main App, or is this a bug? Even with a single DeviceActivityReport, I run into inconsistencies where the View provided by the extension takes multiple seconds to load or fails to load altogether. The behavior seems random...I will build the application with the same code multiple times and see different behavior each time. Finally, a plug for better support in the Simulator for the entire set of Screen Time APIs. Thanks!
3
1
1.5k
Jan ’23