As I can't edit my original post, here's a follow-up observation:
Under iOS 14, the SKDownload content appears to download to:
/private/var/mobile/Library/OnDemandResources/AssetPacks/StoreKit/… and not to the app's /Library/Caches/ directory which has been the case on iOS 13 and prior.
The former directory is not in the app sandbox, and it makes sense we don't have permission to mess with it. If I change my code to copy instead of move items, everything works as expected again.
Why the change? Apple documentation (at developer. apple. com/documentation/storekit/in-apppurchase/unlockingpurchased_content?language=objc) states:
In iOS, your app can manage the downloaded files. The StoreKit framework saves these files for you in the Caches directory with the backup flag unset. After the download completes, your app is responsible for moving these files to the appropriate location. For content that can be deleted if the device runs out of disk space (and downloaded again later by your app), keep the files in the Caches directory. Otherwise, move the files to the Documents folder and set the flag to exclude them from user backups. Therefore iOS 14 downloading to a different directory from which there is no permission to move files will break all apps that try to move files instead of copy them.
My guess is that the files are downloading there because of the SKDownload sandboxing error previously stated, and not because this is a wider change of behaviour under iOS 14. I couldn't see any mention of this anywhere in the release notes or documentation.
Can anyone official comment on whether this is an iOS 14 bug, a temporary scenario or whether this is set in stone from iOS 14 onwards?
Post
Replies
Boosts
Views
Activity
I'm glad to see this is not an issue isolated to our code. I filed feedback with Apple as of August 4th but have received no response as yet. I'll post here if and when I do.
I've just updated to iPadOS 14 beta 7 and can confirm that both of these issues seem to have been fixed:
paymentQueue:updatedDownloads: is called with SKDownloads in SKDownloadStateActive
'Sandboxing' errors have disappeared and Apple hosted content is downloaded to the app ~/Library/Caches/Storekit/ directory
I haven't confirmed on iOS yet - can anyone else say? Let's hope it's fixed across the board and stays that way into production. I'm leaving defensive code in my app which will fall back to copying files if moving them does not work. Lack of download progress would still be a problem but at least content would install if these issues reared their ugly heads again.
We don't see the crashes you're reporting, but it does seem like there are still download issues.
Now users are intermittently seeing:
"mzafbenc.15091114977934116907" couldn't be moved to "StoreKit" because an item with the same name already exists. To save the file, either provide a different name, or move aside or delete the existing file, and try again.
This is not due to any file management on our part - it seems to be StoreKit failing to deal with the possibility that it already downloaded certain content and that it wasn't moved.
We are also seeing -[NSURL initFileURLWithPath:]: nil string parameter exceptions when using content file paths from finished SKDownloads.
Beta 8 is still showing these same problems - we can receive SKDownloads in the SKDownloadStateFinished state with a 'nil' contentURL property (prior to finishing the associated transactions).
I must say it's getting a bit uncomfortable now!
I've just been doing some more analysis. I don't see the crash you're experiencing, but as of beta 7 and 8 I see:
Some finished SKDownloads work as expected - a valid contentURL in the current app caches/StoreKit directory is provided and the content can be moved from there.
Some finished downloads arrive with a nil download.contentURL and there is sometimes an associated 'StoreKit' alert implying that the downloaded files couldn't be moved to the caches 'StoreKit' directory (~Library/Caches/StoreKit/) because there are existing files that should be moved or deleted. It is StoreKit that is managing the download of these files - we are intended to install the files from this location later on but how can we do it if StoreKit doesn't give us a valid download.contentURL? It seems as if StoreKit should be responsible for clearing the download path in the event that content exists there.
Some finished downloads arrive with the wrong content path - an app UUID in the folder path which does not correspond to the current home directory - and no content in that directory (not even when replacing the home directory UUID with the correct one).
A real example of the latter is a download that was started fresh in a current app session, and reported a contentURL.path of:
/private/var/mobile/Containers/Data/Application/D135A96C-9991-4BB6-BF98-87B52CD2B25D/Library/Caches/StoreKit/3968122711419134656/Contents when the current app home directory is different:
/var/mobile/Containers/Data/Application/E06F9149-D287-4D5A-BA08-6EA7DD469590/ No content can be found at the prior location, nor if we 'fix' the path by replacing the home directory UUID with the correct one for the current launch. You will see that kind of UUID mismatch for downloads started in previous app sessions, and actually updating the UUID will let you install the content if there is any, but in this case it just seems like the download finishes but there is no content whatsoever.
Out of interest, can I ask what your code does in response to SKDownloadStateWaiting? We do nothing for SKDownloadStateWaiting in the paymentQueue:updatedDownloads: method - in the switch we simply break for that case.
As I'm sure you do, we call [[SKPaymentQueue defaultQueue] startDownloads:] elsewhere based on the transactions we receive in paymentQueue:updatedTransactions:.
Unfortunately I'm still seeing issues in iOS 14.0 GM seed. I'm using a fresh install to avoid issues from prior beta installations. Can anyone else confirm this?
I'm still seeing paymentQueue:updatedDownloads: called with finished downloads with nil/zero-length download.contentURL or with no content at the URL. Sometimes this method gets called twice, the first time there is no content and the second time there is content.
I have heard nothing direct from Apple, but I note that the status of my feedback report has changed. 'Recent similar reports' is marked as 'less than 10', and resolution has changed to 'potential fix identified - in iOS 14'. I am confused as to how there can be so few similar reports given that everyone has to use the same API in the same way.
And now it seems like there are additional StoreKit / App Store server issues making further testing difficult:
SKPaymentQueue: 0x2826811c0>: Payment completed with error: Error Domain=ASDErrorDomain Code=500 "Unhandled exception" UserInfo={NSUnderlyingError=0x282b94180 {Error Domain=AMSErrorDomain Code=301 "Invalid Status Code" UserInfo={NSLocalizedDescription=Invalid Status Code, NSLocalizedFailureReason=The response has an invalid status code}}, NSLocalizedFailureReason=An unknown error occurred, NSLocalizedDescription=Unhandled exception
These issues persist in 14.2 beta.
I'm also a bit baffled as to why there aren't more reports about this. My app utilizes IAP content lightly, but there must be developers whose business model heavily depends upon it - surely they must be suffering? /nods head
Do your failed downloads eventually succeed if you retry multiple times? I'm thinking about this from a customer support perspective. If a failed download will eventually succeed then at least I can suggest that a customer should keep retrying. The problems do seem intermittent - retrying (potentially multiple times) can result in success. We do recommend people reinstall (to force the caches/ directory to be purged) - thinking about adding a function to purge the caches directory if no downloads are in progress!
A question: do you see tremendous lag in the finishing and removal of transactions from the payment queue? Pre iOS 14 we would batch finish transactions and see the paymentQueue:removedTransactions: method called very rapidly. Now it is painfully slow and can take up to a minute to finish say 30 transactions (we have a lot of in-app purchases).
We observe this same error when exporting ad hoc or development builds in Xcode 12 with bitcode recompilation enabled. We suspected an issue with a third party framework, so we created a version of our project without any external dependencies (the only frameworks we import are Apple's own e.g., StoreKit, CoreImage...). The problem persisted.
There are no problems using Xcode 11 - we can export the archive with bitcode recompilation and App Store processing works fine. Of course, we can't use any iOS 14 APIs with Xcode 11.
Our only option appears to be to disable bitcode in our project if we want to use Xcode 12. Given that we see failure when using only Apple frameworks, we believe that this as a bug that Apple needs to fix.
We solved the problem by following advice from https://developer.apple.com/forums/thread/662947
There appears to be a bug in Xcode 12 where enabling code coverage support causes bitcode recompilation failure. We don't need the code coverage support anyway.
1) In Build Settings 'Apple Clang - Code Generation' set 'Enable Code Coverage Support' to NO in the project.
2) In Build Settings ensure that '-fprofile-instr-generate' is not set in 'Other Linker Flags'.
With those steps complete, archiving and exporting with bitcode recompilation worked under Xcode 12.
Did you ever get to the bottom of this? We see the same error on iOS 14.8 iPhone XS Max.