Post

Replies

Boosts

Views

Activity

Reply to Indicating premium content in screenshots / videos
I was not able to find any terminology that Apple would accept, so I have removed all the annotations from the videos. They have accepted this, despite it clearly not complying with the requirement to indicate where IAP is required (guideline 2.3.2), and being less informative for customers. Interaction with App Review has been poor. My guess is that this has come up now because they have some new automatic analysis of preview videos that is able to read the text of captions. Based on keywords that it finds, it sends cut-and-paste rejections. Attempts to reply to the rejection messages just trigger further repetitions of the same generic messages, with absolutely no effort to address the core question, how can I comply with both 2.3.2 and 2.3.7 at the same time. I did speak to someone on the phone. He was an actual human, and his feedback did seem at the time to be useful; he said that the specific issue was that I was not allowed to refer to a price, and "free" is a price, and that it would be OK if I used some other expression; I suggested "no in-app purchase required", which he seemed to agree was "not a price" and so would be OK. This was all reasonably friendly and seemed useful - except that it was wrong. I regenerated all the videos with different annotations based on this conversation and they were rejected again. This is a long-established app that has made Apple hundreds of thousands of dollars in commission over the years; it annoys me that I get treated this way. I didn't generally support the idea of e.g. third-party app stores or side-loading since they could be used to distribute cracked versions of my apps, but having to wait three weeks to submit a bug fix (remember this was all caused by Xcode 15.0 creating apps that don't work on iOS 12 due to the borked linker) makes me more supportive of them.
Topic: App & System Services SubTopic: StoreKit Tags:
Dec ’23
Reply to NDA on code-level support
No, quite the opposite. If they want, Apple can take your code and incorporate it into their own products. Or they can sell it to your competitors. This is why you must always create a minimal project that demonstrates your problem to send toe DTS, rather than submitting your real code. See section 9.3 of the developer agreement: 9.3 Information Submitted to Apple Not Deemed Confidential Apple works with many application and software developers and some of their products may be similar to or compete with Your Applications. Apple may also be developing its own similar or competing applications and products or may decide to do so in the future. To avoid potential misunderstandings and except as otherwise expressly set forth herein, Apple cannot agree, and expressly disclaims, any confidentiality obligations or use restrictions, express or implied, with respect to any information that You may provide in connection with this Agreement or the Program, including but not limited to information about Your Application, Licensed Application Information, and metadata (such disclosures will be referred to as “Licensee Disclosures”). You agree that any such Licensee Disclosures will be non-confidential. Except as otherwise expressly set forth herein, Apple will be free to use and disclose any Licensee Disclosures on an unrestricted basis without notifying or compensating You. You release Apple from all liability and obligations that may arise from the receipt, review, use, or disclosure of any portion of any Licensee Disclosures. Any physical materials You submit to Apple will become Apple property and Apple will have no obligation to return those materials to You or to certify their destruction.
Dec ’23
Reply to Decoding and parsing App Attest receipts
I did try using fromBER, but I wasn't sure what to do with the output: That does have a lot of boilerplate nonsense.... I guess it hasn't decoded it recursively, so now you need to call it again on the valueBlock. Or something. Does the ability for a device to produce a valid attestation (apart from the fraud metric) give you any insight into whether the app is running on a jailbroken device or is otherwise compromised? As I understand it, it certainly gives you some level of trust. Yet Apple still chose to implement the risk metric. I think it is related to non-cracking abuse, e.g. single App Store accounts shared between very large numbers of devices. Or something.
Topic: App & System Services SubTopic: General Tags:
Dec ’23
Reply to Decoding and parsing App Attest receipts
I tried with asn1.js, but it seems that I need to specify the schema. Maybe fromBER in parser.ts ? I did consider trying to use Node.js, but decided that the required crypto primitives were not available in the version of Node.js that was available in AWS Lambda functions at the time. Maybe that has changed. I'm really out of my depth here Beware, this is quite difficult to get right even once you have implemented it correctly. There are lots of edge cases, including: iOS apps running legitimately on Macs. Users who have replaced their devices and restored from a backup, getting the key ID from the old device. Users who have not used the app for a while and the App Store has discarded their risk information (you get 404 from the endpoint in this case). More things that I haven't debugged yet. Currently, I see far more failures than can be explained by people trying to crack the app, so the reported "risk metric" is of little use. You need to work out where the balance is between blocking access to a user with a cracked app versus blocking access to a genuine user who can write a bad review saying they can no longer access content that they have paid for. (And they will nearly always leave a bad app store review, rather than contacting you for support.) If your balance is 10 bad reviews = 1 cracked app, maybe App Attest is useful; if it's 1 bad review = 10 cracked apps, it's not the right solution IMO. You also need to decide what risk metric value is too risky, and Apple don't give us any advice on this. Currently my distribution is Risk metric : % of users 1 : ~99% 2 : 1% 3 : 0.2% 4 : 0 5 : 0.15% Device claims not to support App Attest : 0.25% Should I be blocking the 0.15% of users with a risk metric of 5? Or does that distribution mean that all my users are OK, and only a risk metric of 100 is serious? We have no way of knowing. Good luck, anyway.
Topic: App & System Services SubTopic: General Tags:
Dec ’23
Reply to Do I still need "iOS 17.0" support, now that my device is running 17.1.2?
it will work after reboot. That's an interesting suggestion - thanks for posting. I'll try and remember if I ever get in the mess again. Eventually I gave up and re-installed Xcode, and clicked on the "GET" button to install the SDK + simulator. Just another 3 hours of downloading. Once that was working I tried to do the same thing on my other Mac - and it worked in 10 minutes!!!! It seems that, by some magic, the second Mac copied the files over the local network from the first!!! Now if I had known that that were going to happen, I wouldn't have ever tried to download disk images and I would have just used the "GET" buttons from the beginning.
Dec ’23
Reply to "Required Reason" API - stat()
There has been an update to the reasons listed on the web page. Where it used to say "to access the timestamps of files inside the app container", it now says "to access the timestamps, size, or other metadata of files inside the app container" (emphasis added). So using stat() to check if a file exists, to read its size, etc. is now allowed, but you do need to declare the usage, and you can't explore outside your container (and group containers, your iCloud containers, etc.). Still no mention of C++ std::filesystem functions. I don't think the app store checking has been turned on yet, so we don't know if they will be detected or not. What was your final approach in this situation? I don't have a "final approach". As we can now see, it would have been a waste of time to remove all of my stat()-based std::filesystem calls when this was first announced!
Topic: Privacy & Security SubTopic: General Tags:
Dec ’23
Reply to Double value cannot be converted to UInt8 because the result would be less than UInt8.min
One more observation: always work with local copies of anything that should not be changed externally. I am surprised that this isn't what happens in the compiled code anyway. I.e. given your source code v -= d; if (v < 0) v = 0; if (v > 180) v = 180; f(v); I would expect the compiler to generate code that keeps v in a register through all of that and not read and write to the global variable location, i.e. in pseudo-assmbler: reg = load(v) reg = reg - d compare reg, 0 if less reg = 0 compare reg, 180 if greater reg = 180 store reg to v move from reg to function arg location (if different) call f In that case, there is no opportunity for the concurrent invocation of the function to modify the value of v between the clamping tests and the subsequent use. Maybe you have compiled with no optimisation? Maybe your real code is more complicated than what you've posted? Anyway, I suggest that you look at the generated code (if you can work out how to do that) and see if it is really doing what you think it is doing.
Topic: Programming Languages SubTopic: Swift Tags:
Dec ’23
Reply to C++ std::stable_sort crashes on iOS 12
Do we know if this is something that can be fixed in an iOS 12.x+1 release, or in an XCode 15.x+1 release? It seems that binaries created with Xcode 15.1 work OK on iOS 12 without the need to specify -ld_classic. I don't know if this is because the underlying problem has actually been fixed, or whether it now just uses ld_classic by default when the target is iOS 12.
Dec ’23
Reply to Double value cannot be converted to UInt8 because the result would be less than UInt8.min
The only case in which this could crash is if two instances of my function are ran concurrently, which does happen during heavy load Well done for debugging that. The traditional fix would be a mutex that protects value. I guess that the "modern Swift / Apple way" to do this would involve a serial queue. Moral of the story: always work with local copies of anything that should not be changed externally. That's not necessarily sufficient for correctness.
Topic: Programming Languages SubTopic: Swift Tags:
Dec ’23