Posts

Post not yet marked as solved
0 Replies
312 Views
Hi, So I know an app will get rejected during App Store review if it includes the ability to open any Settings app URLs other than the main settings page or the app's own settings page, so you can't go directly to the Wi-Fi settings page for example. Wondering though if I create an iOS shortcut file via the Shortcuts app that includes the ability to open a "rejectable" URL (such as a sub-page of the Settings app) and include it in my app that the user can then open and install the shortcut to their device and use outside of my app, is that ok? I can share it via email, AirDrop, etc. no problem and it works on other devices. If the above is NOT ok, would it be ok if the app had a link to a web site that hosted the shortcut file so it wasn't actually embedded in my app itself? If it is ok, also wondering if shared shortcut files expire or have a validity period? I know the Settings app URLs can change at any time which would break the shortcut but not worried about updating the app if that happens with a new shortcut. Thanks! Colin
Posted Last updated
.
Post not yet marked as solved
1 Replies
471 Views
Detecting New WiFi Connection + WiFi Details What I want to accomplish: The app, including when backgrounded or suspended, creates a local notification (assuming the app has permission for notifications) when there is a new WiFi network being used and ideally being able to execute some small code to customize the notification. This code would also have access to SSID info, security type, etc., so the sort of info in NEHotspotNetwork. A number of apps seem able to do this but I am having trouble replicating what they are doing. What I’ve looked at or tried: Looking at “TN3111: iOS Wi-Fi API overview” https://developer.apple.com/documentation/technotes/tn3111-ios-wifi-api-overview Navigate an internet hotspot (NEHotspotHelper) Doesn’t look like NEHotspotHelper would provide the above functionality for detecting changes while backgrounded and it seems to indicate that the special entitlement com.apple.developer.networking.HotspotHelper would not be granted for this use case anyway. Add an accessory to the user’s network (Wireless Accessory Configuration (WAC) or HomeKit) Doesn’t seem relevant to my use case Peer-to-peer networking Doesn’t seem relevant to my use case Location tracking I don’t want to know my user’s location and Lookout and Norton 360 (just two of many examples) don’t request or have location permissions (or request any permissions for that matter except notifications) and are still able to obtain the WiFi network info without it as well as detect changes in the background. Current Wi-Fi network NEHotspotNetwork .fetchCurrent(completionHandler:) So this is the most obvious since it returns the info I want but it requires the following permissions or configurations that neither Lookout or Norton 360 are requesting and also I don’t see how this API would trigger a backgrounded app to run, more for when your app is in the foreground and able to run already. From Apple docs: “This method produces a non-nil NEHotspotNetwork object only when the current network environment meets all four of the following critieria: The app is using the Core Location API and has user’s authorization to access precise location. The app used the NEHotspotConfiguration API to configure the current Wi-Fi network. The app has active VPN configurations installed. The app has an active NEDNSSettingsManager configuration installed. This method also requires the app to have the Access Wi-Fi Information Entitlement, and produces nil if the app lacks this entitlement.” Once again, apps that are able to do what I want don't seem to have location permissions, no VPN profile, no DNS config, no hotspot config.... Additional things I’ve considered that are not mentioned in the above: Using NWPathMonitor works for identifying a change, doesn’t trigger when app backgrounded and no access to SSID or other WiFi info. What am I missing? Is there some API that I totally missed? Thank you! Colin
Posted Last updated
.
Post marked as solved
1 Replies
479 Views
Hi, My iOS app allows a user to perform a rather expensive cloud operation (costs me 10 cents per time) and I want to ensure they can only do it once a day across all of their iOS devices. The marketing will make it clear this is how it will work so users won't be surprised. While most will only have one iPhone in practice, with my subscription pricing I'd lose money the second someone started doing it on a second device. I could solve this using Sign in with Apple to ensure there is a 1:1 correlation between Apple ID with paid subscription and a user account in my system that I could track usage against but I'd like to avoid users having to sign in at all since it would serve no purpose from a user perspective. identifierForVendor won't work since it's different across every device the same user has Is there something in StoreKit v2 receipts or transaction data that would be stable longterm and have the same result across all devices using the same Apple ID? I don't actually want any info about the user, just a stable anonymized identifier to see they are the same user on different devices. I could also go with a consumable in-app purchase but I don't think users would like this pricing model for this app. Thanks! Colin
Posted Last updated
.
Post not yet marked as solved
2 Replies
738 Views
Hi, calls to URLSession for an IPv6 only domain (i.e. only an AAAA DNS record) within my app are failing even though the same domain name works in Safari. This is on a device with both an IPv4 and IPv6 connection when iCloud Private Relay is enabled and when it is not. I'm trying to obtain the external IPv4 and IPv6 addresses of the user's device from my app using ipify.org's api4.ipify.org (IPv4), api64 (6 to 4) and api6 (IPv6) addresses. The issue I am having is within my app the api64 call always returns an IPv4 address and the api6 call just fails outright, resulting in a throw "A server with the specified hostname could not be found." api6.ipify.org only has an AAAA DNS record. But everything works right on the same device in Safari. In Safari: api4.ipify.org -> IPv4 api64.ipify.org -> IPv6 (since device has IPv6 connectivity) api6.ipify.org -> IPv6 In my app though: api4.ipify.org -> IPv4 api64.ipify.org -> IPv4 (but should return an IPv6 address, like for Safari) api6.ipify.org -> IPv6 (fails...domain name not found) Tried with cellular only connection (device has two public IPv6 addresses assigned) and from WiFi (device has both a private IPv4 and a private IPv6 address) and same results. Happening in both iOS 17.03 and 16.7.1. I am having the exact same results when using other sites similar to ipify.org. 6to4 only returns an IPv4 address and AAAA record only domains fail, so not something specific to ipify.org. Here's the code block that is failing within my app when api6.ipify.org is used and returns the wrong answer when api64 is used. Thank you! Task { do { let (data, _) = try await URLSession.shared.data(from: URL(string: "https://api<insert 4, 64 or 6>.ipify.org")!) self.statusPublicIPv6 = String(data: data, encoding: .utf8) ?? "" } catch { print(error.localizedDescription) } }
Posted Last updated
.
Post not yet marked as solved
11 Replies
6.1k Views
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)       }     }   } }
Posted Last updated
.
Post not yet marked as solved
1 Replies
986 Views
Hi, The "Siri & Search" option is listed in my app's settings and I'd like to know how to remove it. I'm pretty sure it wasn't listed when I first started developing my app over a year ago and I never added any Siri related entitlements to my app, not sure when it started being there. It seems half of the apps on my device (from other developers) have this listed, other half do not, so it's not there by default. I've checked my entitlements file, nothing related to Siri. Checked capabilities, nothing there either related to Siri. I know my users could go and manually block the app's data from being accessible but I'd rather remove the option entirely and definitely don't want it on by default. Shows up on at least iOS 15 and iOS 16. Thanks! Colin
Posted Last updated
.