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'm still on iOS 14.0 GM. I've seen this issue occur once, but have since performed 20-30 downloads which all completed successfully. This failure pattern made me wonder if there was something 'left over' in the payment queue from a previous beta or run session, but that's pure speculation.
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?
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.
Post
Replies
Boosts
Views
Activity
I've made some progress (still on iPadOS 14 beta 8) as I believe I've managed to fix the crashes I was experiencing during content download. My downloads now make it to the end and usually succeed, but sometimes they fail with the same behavior reported by hithlimited.
My crashes were fixed by removing my call to [[SKPaymentQueue defaultQueue] startDownloads:] in response to SKDownloadStateWaiting. It took quite a long time after making this change for all downloads to stop. I suspect there were many items in the queue, including those from previous run sessions. My guess is that it was spamming the payment queue because it's called so frequently in iOS 14. Note that I had no problems on iOS 10-13 with this code in place.
When a download fails, I'm seeing this in [RMStoreObserver storeDownloadFailed:]:
storeDownloadFailed:
ProductID		 = co.uk.redacted
Transaction	 = <SKPaymentTransaction: 0x282b99a90>
Download			= <SKDownload: 0x282b99ad0>
Description	 = “mzafbenc.5781985184949448504” couldn’t be moved to “StoreKit” because an item with the same name already exists.
FailureReason = A file with the name “mzafbenc.5781985184949448504” already exists.
So the good news is that we can both independently reproduce at least one issue, which is something. The bad news is that (to my knowledge) this is a problem with StoreKit and outside our control.
Wait for beta 9?
Out of interest, can I ask what your code does in response to SKDownloadStateWaiting?
I've always done this (recommended in a thread on StackOverflow to 'kickstart' a download which is stuck in a waiting state):
(void)paymentQueue:(SKPaymentQueue *)queue updatedDownloads:(NSArray *)downloads
{
		for (SKDownload *download in downloads)
		{
ASSERT(download != nil);
				switch (download.downloadState)
				{
// ...
// SNIP
// ...
						case SKDownloadStateWaiting:
						 {
								// Attempt to restart the download
						 	[[SKPaymentQueue defaultQueue] startDownloads:[NSArray arrayWithObject:download]];
}
							break;
	default:
break;
				}
		}
}
... however, I've found that this handler is called many times with SKDownloadStateWaiting, and therefore I call SKPaymentQueue:startDownloads: a huge number of times. I'll have to try some testing with this call disabled.
I also see no improvement in iPadOS 14 beta 8 (eg. see crash below, which occurs during store-hosted content download).
It's difficult to say how much we should worry without knowing the public launch date. I personally feel that these issues are so serious that it can't be released in this state. However, there are only 3 developers involved in this thread - I'd feel a lot more comfortable if there were more developers getting involved in the discussion.
Does this mean it works for everyone else?
Main Thread (1): "*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]"
Enqueued from com.apple.NSXPCConnection.m-user.com.apple.storekitservice (Thread 2) Queue : com.apple.NSXPCConnection.m-user.com.apple.storekitservice (serial)
#0 0x0000000106556014 in dispatch_async ()
#1 0x00000001cc306ba0 in __34-[SKPaymentQueue downloadRemoved:]_block_invoke ()
#2 0x00000001afb24038 in NSARRAY_IS_CALLING_OUT_TO_A_BLOCK ()
#3 0x00000001afa83b90 in -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] ()
#4 0x00000001cc306a88 in -[SKPaymentQueue downloadRemoved:] ()
#5 0x00000001c5b2f35c in -[ASDStoreKitClientBroker downloadRemoved:] ()
#6 0x00000001b0fb3554 in NSXPCCONNECTION_IS_CALLING_OUT_TO_EXPORTED_OBJECT_S1 ()
#7 0x00000001b0ddc828 in -[NSXPCConnection _decodeAndInvokeMessageWithEvent:flags:] ()
#8 0x00000001b0fb3690 in message_handler ()
#9 0x00000001f61b1bbc in _xpc_connection_call_event_handler ()
#10 0x00000001f61b1f48 in _xpc_connection_mach_event ()
#11 0x00000001065516bc in _dispatch_client_callout4 ()
#12 0x000000010656d1f8 in _dispatch_mach_msg_invoke ()
#13 0x0000000106558dd4 in _dispatch_lane_serial_drain ()
#14 0x000000010656e168 in _dispatch_mach_invoke ()
#15 0x0000000106558dd4 in _dispatch_lane_serial_drain ()
#16 0x0000000106559ce8 in _dispatch_lane_invoke ()
#17 0x0000000106565e38 in _dispatch_workloop_worker_thread ()
#18 0x00000001f618c908 in _pthread_wqthread ()
#19 0x00000001f619377c in start_wqthread ()
Thread#0 0x00000001afba35ac in __exceptionPreprocess ()
#1 0x00000001c3bad42c in objc_exception_throw ()
#2 0x00000001afc124cc in _CFThrowFormattedException ()
#3 0x00000001afc0fec4 in -[__NSPlaceholderArray initWithObjects:count:].cold.3 ()
#4 0x00000001afa8c3b0 in -[__NSPlaceholderArray initWithObjects:count:] ()
#5 0x00000001afa86ef0 in +[NSArray arrayWithObjects:count:] ()
#6 0x00000001cc306c1c in __34-[SKPaymentQueue downloadRemoved:]_block_invoke_2 ()
#7 0x000000010654fb68 in _dispatch_call_block_and_release ()
#8 0x00000001065515f0 in _dispatch_client_callout ()
#9 0x0000000106560890 in _dispatch_main_queue_callback_4CF ()
#10 0x00000001afb201e4 in CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE ()
#11 0x00000001afb1a3b4 in __CFRunLoopRun ()
#12 0x00000001afb194bc in CFRunLoopRunSpecific ()
#13 0x00000001c651f820 in GSEventRunModal ()
#14 0x00000001b24bd8e0 in -[UIApplication _run] ()
#15 0x00000001b24c2fbc in UIApplicationMain ()
#16 0x00000001015d3d04 in main at /Users/mborstel/Documents/Projects/NS2/libs/Engine/Application/iOS/main.m:8
#17 0x00000001af7e0e60 in start ()
It seems that from the various changes in behavior recently that the iPadOS 14 StoreKit API is still a work in progress.
I could submit a bug report but in the past I've usually been required to provide sample code to demonstrate the problem and it will take days extract a simple example from a complex app. I think I'll play this by keeping my fingers crossed for a beta 8 and working on some other areas in the meantime.
I haven't yet tried this on the phone.
I've just updated to iPadOS 14 beta 7 and my app's now unable to download store hosted content due to crashes in com.apple.NSXPCConnection.m-user.com.apple.storekitservice.
My app's IAP code hasn't changed since iOS 10, and I've never seen these crashes prior to iOS 14 beta 7. I've spent a day or so trying different things but no success so far.
Crash example 1:
Main Thread (1): "*** -[__NSPlaceholderArray initWithObjects:count:]: attempt to insert nil object from objects[0]"
Enqueued from com.apple.NSXPCConnection.m-user.com.apple.storekitservice (Thread 9) Queue : com.apple.NSXPCConnection.m-user.com.apple.storekitservice (serial)
#0 0x000000010842a014 in dispatch_async ()
#1 0x00000001c0352ba0 in __34-[SKPaymentQueue downloadRemoved:]_block_invoke ()
#2 0x00000001a3b70038 in NSARRAY_IS_CALLING_OUT_TO_A_BLOCK ()
#3 0x00000001a3acfb90 in -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] ()
#4 0x00000001c0352a88 in -[SKPaymentQueue downloadRemoved:] ()
#5 0x00000001b9b7b35c in -[ASDStoreKitClientBroker downloadRemoved:] ()
#6 0x00000001a4fff554 in NSXPCCONNECTION_IS_CALLING_OUT_TO_EXPORTED_OBJECT_S1 ()
#7 0x00000001a4e28828 in -[NSXPCConnection _decodeAndInvokeMessageWithEvent:flags:] ()
#8 0x00000001a4fff690 in message_handler ()
#9 0x00000001ea1fdbbc in _xpc_connection_call_event_handler ()
#10 0x00000001ea1fdf48 in _xpc_connection_mach_event ()
#11 0x00000001084256bc in _dispatch_client_callout4 ()
#12 0x00000001084411f8 in _dispatch_mach_msg_invoke ()
#13 0x000000010842cdd4 in _dispatch_lane_serial_drain ()
#14 0x0000000108442168 in _dispatch_mach_invoke ()
#15 0x000000010842cdd4 in _dispatch_lane_serial_drain ()
#16 0x000000010842dce8 in _dispatch_lane_invoke ()
#17 0x0000000108439e38 in _dispatch_workloop_worker_thread ()
#18 0x00000001ea1d8908 in _pthread_wqthread ()
#19 0x00000001ea1df77c in start_wqthread ()
Crash example 2:
Main Thread (1): "*** -[__NSSetM removeObject:]: object cannot be nil"
Enqueued from com.apple.NSXPCConnection.m-user.com.apple.storekitservice (Thread 9) Queue : com.apple.NSXPCConnection.m-user.com.apple.storekitservice (serial)
#0 0x0000000105da6014 in dispatch_async ()
#1 0x00000001b449a854 in __40-[SKPaymentQueue downloadStatusChanged:]_block_invoke ()
#2 0x0000000197cb8038 in NSARRAY_IS_CALLING_OUT_TO_A_BLOCK ()
#3 0x0000000197c17b90 in -[__NSArrayM enumerateObjectsWithOptions:usingBlock:] ()
#4 0x00000001b449a504 in -[SKPaymentQueue downloadStatusChanged:] ()
#5 0x00000001adcc31c0 in -[ASDStoreKitClientBroker downloadStatusChanged:] ()
#6 0x0000000199147554 in NSXPCCONNECTION_IS_CALLING_OUT_TO_EXPORTED_OBJECT_S1 ()
#7 0x0000000198f70828 in -[NSXPCConnection _decodeAndInvokeMessageWithEvent:flags:] ()
#8 0x0000000199147690 in message_handler ()
#9 0x00000001de345bbc in _xpc_connection_call_event_handler ()
#10 0x00000001de345f48 in _xpc_connection_mach_event ()
#11 0x0000000105da16bc in _dispatch_client_callout4 ()
#12 0x0000000105dbd1f8 in _dispatch_mach_msg_invoke ()
#13 0x0000000105da8dd4 in _dispatch_lane_serial_drain ()
#14 0x0000000105dbe168 in _dispatch_mach_invoke ()
#15 0x0000000105da8dd4 in _dispatch_lane_serial_drain ()
#16 0x0000000105da9ce8 in _dispatch_lane_invoke ()
#17 0x0000000105db5e38 in _dispatch_workloop_worker_thread ()
#18 0x00000001de320908 in _pthread_wqthread ()
#19 0x00000001de32777c in start_wqthread ()
Some extra info: I've just updated to iOS 14 beta 6 and there's no change in behavior since the beta 5. paymentQueue:updatedDownloads: is not called with SKDownloadStateActive events.
I'm going to work around this by adding a 'downloading' spinner to the app's UI, but I don't consider this a great UX for lengthy downloads - previously I had a download progress bar, which is a lot more reassuring for users.
I also have the exact same problems with iOS 14 beta 5. This is the first iOS 14 beta I've tried so I'm unable to say if it occurred in betas 1-4, but I can definitely say it did not occur in iOS 13.
Testing within the sandbox, I frequently see the following messages:
SKDownload encountered a sandboxing error: 0
SKDownload encountered a sandboxing error: 2
I'm unable to tell if these are benign or an early indication of the following problems:
Problem 1:
Store hosted content is now downloaded to /private/var/mobile/Library/OnDemandResources in iOS 14 (as reported by both codepoetz and hithlimited). This is easily solved by copying the content folder from that location rather than moving (as the app does not have permissions for the latter).
Problem 2:
During the download, paymentQueue:updatedDownloads: no longer receives SKDownloadStateActive events in iOS 14 and therefore it's not possible to indicate the download progress (as reported by codepoetz). This is a disconcerting experience for users who have just agreed to spend their money on IAP.
Currently I have no solution for problem 2.