In TestFlight crash reports, all I see is the stack trace.
Is there any other information hidden in there, such as the specific signal (etc) that caused the app to terminate?
Thanks.
Post
Replies
Boosts
Views
Activity
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".
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.
Has anyone paid a graphics designer to produce custom SF Symbols for them? Would you care to share your experiences?
I paid for some custom graphics a decade ago; the results were OK but not amazing. I forget how I found that guy. No doubt everything has changed since then.
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?
I've just been looking at this list of APIs for which we will be soon be required to declare a "required reason" in the app's privacy manifest:
https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api
One of the listed functions is stat().
The rationale seems to be that a malicious app can use stat to get the timestamps of files outside the app container, thereby "fingerprinting" the device.
The allowed reasons that we can declare are :
To get timestamps that are displayed to the user.
To get timestamps of files that are within the app's container.
To get timestamps of files that the user has granted access to.
I am concerned that this does not include many of the legitimate non-timestamp uses of stat(). For example, it can be used simply to test if a file exists, or to test whether a path refers to a file or a directory, or to check if two paths refer to the same file (e.g. via different symlinks), or to get the size of a file.
Some of these things can be achieved in other ways; for example, I can check if a file exists by trying to open() it and checking for an error, and I can get the file size by opening it and calling lseek(SEEK_END). Maybe I can check if two paths are equivalent by using readlink() to form canonical paths for both and comparing them. But I bet there are other things that can't be done.
I could probably fix all of my code to not call stat() for non-timestamp reasons in a few hours. It would be more difficult to fix the various open-source libraries that I use.
What do you think we should all be doing?:
"File a bug" asking for an additional reason for using stat(), i.e. to get non-timestamp information about files in the app's container.
Deliberately mis-read allowed reason C617.1, "to access the timestamps of files inside the app container", as " to access the timestamps and other metadata of files inside the app container", and declare that in the privacy manifest.
Change code to not call stat().
Any other suggestions?
P.S. I guess that libc++ std::filesystem calls stat(). What is the status of using that? The std::filesystem functions that access file timestamps are not listed on the page linked above. If I call std::exists() to check if a file exists, and assuming that is implemented using stat(), will that trigger the new filter?
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?
Is it possible to change the date formats used in the App Store Connect web interface?
It seems to me that things like the date range selection widget on the Sales & Trends page use only the US-style MM/DD/YYYY format. Is there some way to change this to YYYY-MM-DD or DD/MM/YYYY that I have missed?
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?
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.
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.
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?
I've been getting 500 error responses from the https://data.appattest.apple.com/v1/attestationData server for the last few hours. About half of requests complete OK and half fail.
Anyone else seeing this?
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?
Dear Experts,
Where do memory-mapped files appear in the Allocations instrument, if at all?
In the screenshot below, the green "all anonymous VM" graph is almost completely explained by the purple "IO Accelerator" graph (GPU buffers, textures etc) - but there are periods at the start of each cycle (such as at the cursor position) where there is some other contribution. I have not been able to find this in the other more-specific graphs.
Any ideas anyone? I have been trying to make this app better behaved memory-wise and have made a lot of progress, in particular by removing periods when two large memory allocations co-exist, and by breaking work up into chunks. It now bothers me that there is 150 MB of "anonymous VM" that I cannot explain!