Post

Replies

Boosts

Views

Activity

iOS-on-macOS app receipt not saved in recent macOS versions
Dear All, My iOS app used to work OK on macOS, but since a macOS update in-app purchases have stopped working. It seems that the storekitagent process is no longer able to save the receipt to the filesystem. Here is what I see in the system log after I do a "refresh receipt": default 22:03:47.822657+0100 storekitagent [58C16E76_SK1] Writing receipt (83905 bytes) to file:///Users/phil/Library/Containers/0407ACA7-9EE2-4E32-AA3E-101A1B38EE70/Data/StoreKit/sandboxReceipt error 22:03:47.823539+0100 kernel Sandbox: storekitagent(1382) deny(1) file-write-unlink /Users/phil/Library/Containers/0407ACA7-9EE2-4E32-AA3E-101A1B38EE70/Data/StoreKit/sandboxReceipt error 22:03:47.824306+0100 storekitagent [58C16E76_SK1] Error writing receipt (83905 bytes) to file:///Users/phil/Library/Containers/0407ACA7-9EE2-4E32-AA3E-101A1B38EE70/Data/StoreKit/sandboxReceipt: Error Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “sandboxReceipt” in the folder “StoreKit”." UserInfo={NSFilePath=/Users/phil/Library/Containers/0407ACA7-9EE2-4E32-AA3E-101A1B38EE70/Data/StoreKit/sandboxReceipt, NSUnderlyingError=0x145c19f80 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}} Note that is a sandboxReceipt on my development system, but I have a report from a user who seems to be suffering the same problem with the app store version of the app. Is anyone else seeing this? Is there a "quick hack" I can do to grant the storekitagent process permission to write to that folder?
3
0
946
Jun ’23
Debugging API JWT authorization problems - any suggestions?
Dear All, I have working code that talks to the App Attest receipt refresh API using JWT authorization. I'm now trying to talk to the App Store Connect API, and I'm trying to use essentially the same code for the JWT generation - but it doesn't work. It's frustrating that the API just returns a non-specific 401 "Not Authorized" response, without giving any further clue about what's wrong. I am creating a JWT as follows for App Store Connect; yes I'm aware that the required fields are slightly different for the two APIs: header = {"alg":"ES256","kid":"12345YZSX8","typ":"JWT"} payload = {"iss":"1234567-1234-1234-1234-123456789012","iat":1687379230,"exp":1687379530,"aud":"appstoreconnect-v1"} Using the resulting encoded token, with my own code or with curl, fails with a 401 error: Status: 401 { "errors": [{ "status": "401", "code": "NOT_AUTHORIZED", "title": "Authentication credentials are missing or invalid.", "detail": "Provide a properly configured and signed bearer token, and make sure that it has not expired. Learn more about Generating Tokens for API Requests https://developer.apple.com/go/?id=api-generating-tokens" }] } Doing essentially the same thing, with the slightly different JSON fields and a different .p8 key file, does work with the App Attest API - so I'm probably not creating complete garbage. I've wasted hours on this now. Does anyone have any debugging hints?
1
0
1.5k
Jun ’23
How to update in-app purchase prices using the app store connect API
Documentation for the App Store Connect API is poor, especially in comparison to the good documentation for the now-defunct XML-based "transporter" API. In the hope that it will be useful to others trying to do this in the future, here is how I was able to do a bulk update of my in-app purchases' prices using the API. Step 1: get the IDs for the IAPs, if you don't already know them: GET v1/apps/$app/inAppPurchasesV2 If you have a lot of IAPs, follow any links/next URL to get subsequent pages. The ids are in data/id . Step 2: get the current prices, if you don't already know them. I believe you need to do a separate request for each IAP (right?). GET v1/inAppPurchasePriceSchedules/$iap/manualPrices?include=inAppPurchasePricePoint,territory The price and currency are in included/attributes/customerPrice and included/attributes/currency (I generally only have one "manual" price). Step 3: look up the available price points: GET v2/inAppPurchases/$iap/pricePoints?filter[territory]=$territory The prices and IDs are in data/attributes/customerPrice and data/id. Note this query takes the specific IAP ID. I don't know why. Are the price points specific to the IAPs? Can I reuse a price point ID that I've looked up for one IAP with another IAP for the same app? Step 4: choose your new prices. Step 5: Submit the new prices: POST v1/inAppPurchasePriceSchedules { "data" : { "relationships" : { "baseTerritory" : { "data" : { "id" : "$territory", "type" : "territories" } }, "inAppPurchase" : { "data" : { "id" : "$iap", "type" : "inAppPurchases" } }, "manualPrices" : { "data" : [ { "id" : "$random_id", "type" : "inAppPurchasePrices" } ] } }, "type" : "inAppPurchasePriceSchedules" }, "included" : [ { "attributes" : { "startDate" : null, "endDate" : null }, "id" : "$random_id", "relationships" : { "inAppPurchasePricePoint" : { "data" : { "id" : "$price_point_id", "type" : "inAppPurchasePricePoints" } }, "inAppPurchaseV2" : { "data" : { "id" : "$iap", "type" : "inAppPurchases" } } }, "type" : "inAppPurchasePrices" } ] } In that, $iap is the IAP ID from step 1, $territory is probably a three-letter string like GBR, $random_id is a random identifier that you generate (using the same value in the two places) (I'm not sure what the scope of this is; do I have to check that I don't accidentally send the same value in the future, or does it only exist while this submission is processed?), and $price_point_id is the ID for the price point from step 3. I believe it is necessary to send a separate submission for each IAP (right?) That example makes the change immediately (start and end dates are both null). Note that if you want to schedule a future change, you need to include both the current period and price and the future period and price in the submission. I would like to thank @Efun whose posts in this thread: https://developer.apple.com/forums/thread/727159 helped a lot with understanding this.
0
2
2k
Jun ’23
Make a new Xcode target that's a copy of an existing one
Dear Experts, Is there a way to create a new target in Xcode that is a copy of an existing target? Specifically, I have a standard iOS app target in the project. I'd like to build a second iOS app by adding a second target to the same project. I'd like it to start as a copy of the first target, and then I'll add and remove source files and frameworks, change assets and settings etc. It seems to me that I have to create a new target and then add all the source files etc to it, and then replicate all the settings. I've tried to do this, but it isn't working - bizarrely I just see a black screen, though log messages suggest that the app is running. I am unsure about whether the two targets are sharing e.g. the Info.plist file, etc. Any advice? Thanks.
2
0
2.7k
Jun ’23
Thread QOS class
I see this warning when my app runs: Thread running at QOS_CLASS_USER_INTERACTIVE waiting on a lower QoS thread running at QOS_CLASS_DEFAULT. Investigate ways to avoid priority inversions This is true; I know what is going on. I'd like this other thread to have a higher priority. But how do I set the "QOS class" for a thread? Searching developer.apple.com for QOS_CLASS_USER_INTERACTIVE doesn't find much. It seems that dispatch queues have priorities, but in this case I have a thread, not a dispatch queue. Any ideas?
8
0
5.5k
Jul ’23
App is terminated when user changes language
Dear Experts, NSLocale has a notification NSCurrentLocaleDidChangeNotification and a property autoupdatingCurrentLocale ("A locale which tracks the user’s current preferences"). These suggest that an app should be able to detect when the user changes their language preference while running, or when it is resumed from the background. In practice, when I change language in the Settings app (either globally or just for my app), the app is terminated by iOS and restarts with new locale. Is this the expected behaviour? I am wondering if there is something I need to do to advertise that the app can adopt language changes without restarting, or something. Maybe only date-time formats, etc., trigger the notification but language changes don't?
2
0
1.5k
Jul ’23
US Govt Agency asking to pay for app "outside the Apple payment process"
Dear All, I've just received an email from a user of my paid app who says he is no longer able to use it on his work phone. He works for a US government agency which I'll abbreviate to GOV below. Apparently they have started using Microsoft Intune for device management and as a result they need the following work-around: This app is not free to download, so it cannot be added to Intune app catalog through this tool. Reach out to the app developer and explain that GOV uses Apple Business Manager (ABM) and MDM for delivering managed apps to devices. Payment through ABM is not supported by GOV, so the app developer will need to provide a version of the app that's free to download but take payment outside of the Apple ID payment process. GOV's Custom App Store can be access by developers by advertising their app to Organization ID 12345678. I don't know much about MDM, ABM and Intune, and I would more or less consider this a scam except that I am confident that the person who has sent it really does work for this government agency and does use my app on his personal device. Is there any possibility that what they are asking for is legitimate? I suspect that the crucial part is: "Payment through ABM is not supported by GOV", i.e. fundamentally ABM/MDM/Intune can support paid apps, but the financial people at GOV AGENCY have chosen not to support that. Has anyone else experienced anything like this?
0
0
748
Aug ’23
CFBundleTypeIconFiles or UTTypeIconFiles?
Dear Experts, I'm attempting to make a custom icon appear in the iOS Files app, etc., for my file type. I've found a couple of bits of documentation for Info.plist keys: https://developer.apple.com/documentation/bundleresources/information_property_list/utexportedtypedeclarations/uttypeiconfiles describes UTTypeIconFiles, to be included in UTImportedTypeDeclarations. This documentation is very sparse! Older document https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html#//apple_ref/doc/uid/TP40009249-SW9 describes CFBundleTypeIconFiles, to be included in CFBundleDocumentTypes. Which of these should I be using? (Both? Neither?) Nothing I've tried so far has worked. I wonder if I need to, for example, power-cycle to make the Files app pick up the new icons. Also, in Xcode, I've found the Imported Type Identifiers section of the Info settings which has a box labelled "Add imported type identifiers here" - but clicking + and choosing a file does nothing; the box remains empty. Anyone else have that problem? What size should the icons be? The older document suggests some rather small sizes, e.g. 22x29; the newer doc says nothing. Suggestions anyone?
3
1
1.9k
Aug ’23
Punctuation missing from system font when Chinese language is selected
Dear experts, I get glyphs from the system font using CTFontGetGlyphsForCharacters, something like this: UIFont* uifont = [UIFont monospacedDigitSystemFontOfSize: s weight: w]; CTFontRef font = (__bridge CTFontRef)uifont; CTFontGetGlyphsForCharacters(font, ....); The characters that I ask for are basically latin-1 plus a few others. The app is not localised for Chinese. When I change the phone's default language to Chinese, this code gets glyphs for most characters OK but it fails for a few punctuation symbols: 91 = [ 93 = ] 183 = middle dot 8220 = left double curly quote 8221 = right double curly quote Can anyone guess what's going on here? What's special about those characters? Thanks, Phil.
0
0
802
Sep ’23
Can I not download the iOS simulator?
I've just downloaded Xcode 15 (3.18 GB), and when I start it it downloads "additional components". It's currently downloading "iOS 17.0 Simulator" (7.56 GB). I don't need the simulator, but I do need to compile for iOS and run on devices. Do I need this "simulator" download? I note that while the small download progress window says "iOS 17.0 Simulator (21A328)", the main Xcode window won't let me compile/run the project because it is "Downloading iOS 17.0..." - though I'm not sure if the "..." at the end of that is a truncation eliding the word "Simulator".
4
0
1.8k
Oct ’23