[Solved] iOS IAP flow breaks if user needs to update billing

Sequence of events when trying to buy a consumable item:

  • user tries to purchase IAP
  • user gets asked to sign in, then asked to confirm billing
  • IStoreListener OnPurchaseFailed() gets triggered with error code 2 (ProductUnavailable)
  • user completes billing information confirm
  • apple asks user if they’d still like to make the purchase.
  • user confirms, purchase is made … and apple leaves the user inside the app store. These logs get spit out at this point:

logs on confirming purchase

Jun 9 07:49:47 Bens-iPhone taptapinfinity[2705] : Unity Ads initialized with 21 campaigns and 2 zones
Jun 9 07:49:51 Bens-iPhone wifid[42] : WiFi:[487176591.665016]: Enable WoW requested by “apsd”
Jun 9 07:49:51 Bens-iPhone wifid[42] : WiFi:[487176591.669028]: Unable to dispatch WowStateChanged message to client mediaserverd (268435460)
Jun 9 07:49:51 Bens-iPhone wifid[42] : WiFi:[487176591.670876]: Unable to dispatch WowStateChanged message to client itunesstored (268435460)
Jun 9 07:49:52 Bens-iPhone nehelper[2461] : Configuration for provider com.apple.NetworkExtension.NetworkServiceProxy does not exist (<__NSConcreteUUID 0x146e08b20> 83E2C05F-6F60-4139-AB85-864BA9547B1D) or is not enabled (0)
Jun 9 07:49:52 Bens-iPhone UserEventAgent[26] : Probe message failed
Jun 9 07:49:53 Bens-iPhone com.apple.xpc.launchd[1] : assertion failed: 13F69: launchd + 116796 [9F6284CF-8A17-36CC-9DB5-85D510A21F14]: 0x3
Jun 9 07:49:53 Bens-iPhone com.apple.xpc.launchd[1] : assertion failed: 13F69: launchd + 116796 [9F6284CF-8A17-36CC-9DB5-85D510A21F14]: 0x3
Jun 9 07:50:06 Bens-iPhone AppStore[2696] : Valid Context? yes. Resume options: (null), class: IKJSApplication
Jun 9 07:50:06 Bens-iPhone akd[2476] : success
Jun 9 07:50:07 Bens-iPhone akd[2476] : success
Jun 9 07:50:07 Bens-iPhone accountsd[2463] : AIDA Notification plugin running
Jun 9 07:50:14 Bens-iPhone AppStore[2696] : Can’t find keyplane that supports type 4 for keyboard iPhone-PortraitChoco-NumberPad; using 1336863583_PortraitChoco_iPhone-Simple-Pad_Default
Jun 9 07:50:15 Bens-iPhone kbd[2491] : -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:: CoreData: Ubiquity: mobile~7373AC3F-3CB9-58C3-A641-D95297E45F38:UserDictionary
Using local storage: 1 for new NSFileManager current token <960c6f2d aab7528e 540dfd00 79ccb689 7bbb48b0>
Jun 9 07:50:15 Bens-iPhone kbd[2491] : -PFUbiquitySwitchboardEntryMetadata setUseLocalStorage:: CoreData: Ubiquity: mobile~7373AC3F-3CB9-58C3-A641-D95297E45F38:UserDictionary
Using local storage: 0 for new NSFileManager current token <960c6f2d aab7528e 540dfd00 79ccb689 7bbb48b0>
Jun 9 07:50:38 Bens-iPhone installd[2691] : 0x16e087000 -[MIClientConnection _doBackgroundInstallationForPath:withOptions:completion:]: Install of “/var/mobile/Library/Caches/com.apple.itunesstored/AppPlaceholders/-5529841632035405035.app” type Placeholder (LSInstallType = 1) requested by itunesstored (pid 128)
Jun 9 07:50:38 Bens-iPhone installd[2691] : 0x16e087000 -[MIInstaller _extractPackageWithError:]: Incoming install at /private/var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.TmPHD2/extracted/-5529841632035405035.app had class 3; changing to class 4
Jun 9 07:50:38 Bens-iPhone installd[2691] : 0x16e087000 -[MIExecutableBundle _validateWithError:]: 70: Bundle at path /private/var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.TmPHD2/extracted/-5529841632035405035.app has missing or invalid CFBundleExecutable in its Info.plist
Jun 9 07:50:38 Bens-iPhone installd[2691] : 0x16e087000 -[MIInstaller _bundlesAtURL:error:]: Failed to create bundle for file:///private/var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.TmPHD2/extracted/-5529841632035405035.app/ : Error Domain=MIInstallerErrorDomain Code=11 “Bundle at path /private/var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.TmPHD2/extracted/-5529841632035405035.app has missing or invalid CFBundleExecutable in its Info.plist” UserInfo={LegacyErrorString=MissingBundleExecutable, FunctionName=-[MIExecutableBundle _validateWithError:], SourceFileLine=70, NSLocalizedDescription=Bundle at path /private/var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.TmPHD2/extracted/-5529841632035405035.app has missing or invalid CFBundleExecutable in its Info.plist}
Jun 9 07:50:38 Bens-iPhone itunesstored[128] : 0x16e2d3000 __MobileInstallationInstallForLaunchServices_block_invoke222: Returned error Error Domain=MIInstallerErrorDomain Code=11 “Bundle at path /private/var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.TmPHD2/extracted/-5529841632035405035.app has missing or invalid CFBundleExecutable in its Info.plist” UserInfo={LegacyErrorString=MissingBundleExecutable, FunctionName=-[MIExecutableBundle _validateWithError:], SourceFileLine=70, NSLocalizedDescription=Bundle at path /private/var/installd/Library/Caches/com.apple.mobile.installd.staging/temp.TmPHD2/extracted/-5529841632035405035.app has missing or invalid CFBundleExecutable in its Info.plist}
Jun 9 07:50:38 Bens-iPhone itunesstored[128] : [appinstallation] LaunchServices observer: Apps Failed be installed: (
“<LSApplicationProxy: 0x13ff30ae0> com.scarybee.taptapinfinity <(null) Not found in database>”
)
Jun 9 07:50:38 Bens-iPhone BTServer[65] : [appinstallation] LaunchServices observer: Apps Failed be installed: (
“<LSApplicationProxy: 0x1465708c0> com.scarybee.taptapinfinity <(null) Not found in database>”
)
Jun 9 07:50:38 Bens-iPhone SpringBoard[58] : [appinstallation] LaunchServices observer: Apps Failed be installed: (
“<LSApplicationProxy: 0x1580e3a70> com.scarybee.taptapinfinity <(null) Not found in database>”
)
Jun 9 07:50:38 Bens-iPhone apsd[93] : [appinstallation] LaunchServices observer: Apps Failed be installed: (
“<LSApplicationProxy: 0x1546e50b0> com.scarybee.taptapinfinity <(null) Not found in database>”
)
Jun 9 07:50:38 Bens-iPhone UserEventAgent[26] : [appinstallation] LaunchServices observer: Apps Failed be installed: (
“<LSApplicationProxy: 0x157db92f0> com.scarybee.taptapinfinity <(null) Not found in database>”
)
Jun 9 07:50:38 Bens-iPhone iaptransportd[73] : [appinstallation] LaunchServices observer: Apps Failed be installed: (
“<LSApplicationProxy: 0x15552f580> com.scarybee.taptapinfinity <(null) Not found in database>”
)
Jun 9 07:50:38 Bens-iPhone nsurlsessiond[2446] : [appinstallation] LaunchServices observer: Apps Failed be installed: (
“<LSApplicationProxy: 0x124ea2b40> com.scarybee.taptapinfinity <(null) Not found in database>”
)
Jun 9 07:50:38 Bens-iPhone atc[2543] : [appinstallation] LaunchServices observer: Apps Failed be installed: (
“<LSApplicationProxy: 0x15cde7bc0> com.scarybee.taptapinfinity <(null) Not found in database>”
)
Jun 9 07:50:38 Bens-iPhone passd[2470] : [appinstallation] LaunchServices observer: Apps Failed be installed: (
“<LSApplicationProxy: 0x14ed52a60> com.scarybee.taptapinfinity <(null) Not found in database>”
)
Jun 9 07:50:38 Bens-iPhone profiled[2639] : [appinstallation] LaunchServices observer: Apps Failed be installed: (
“<LSApplicationProxy: 0x125e68d30> com.scarybee.taptapinfinity <(null) Not found in database>”
)
Jun 9 07:50:39 Bens-iPhone itunesstored[128] : [appinstallation] LaunchServices observer: Apps Failed be Uninstalled: (
“<LSApplicationProxy: 0x13e70a360> com.scarybee.taptapinfinity <file:///private/var/containers/Bundle/Application/B2020376-DF01-4262-8ED6-8CC6933011DA/taptapinfinity.app>”
)
Jun 9 07:50:39 Bens-iPhone SpringBoard[58] : [appinstallation] LaunchServices observer: Apps Failed be Uninstalled: (
“<LSApplicationProxy: 0x1598b1e30> com.scarybee.taptapinfinity <file:///private/var/containers/Bundle/Application/B2020376-DF01-4262-8ED6-8CC6933011DA/taptapinfinity.app>”
)
Jun 9 07:50:39 Bens-iPhone iaptransportd[73] : [appinstallation] LaunchServices observer: Apps Failed be Uninstalled: (
“<LSApplicationProxy: 0x15561e390> com.scarybee.taptapinfinity <file:///private/var/containers/Bundle/Application/B2020376-DF01-4262-8ED6-8CC6933011DA/taptapinfinity.app>”
)
Jun 9 07:50:39 Bens-iPhone apsd[93] : [appinstallation] LaunchServices observer: Apps Failed be Uninstalled: (
“<LSApplicationProxy: 0x1545d8e30> com.scarybee.taptapinfinity <file:///private/var/containers/Bundle/Application/B2020376-DF01-4262-8ED6-8CC6933011DA/taptapinfinity.app>”
)
Jun 9 07:50:39 Bens-iPhone UserEventAgent[26] : [appinstallation] LaunchServices observer: Apps Failed be Uninstalled: (
“<LSApplicationProxy: 0x157eb40c0> com.scarybee.taptapinfinity <file:///private/var/containers/Bundle/Application/B2020376-DF01-4262-8ED6-8CC6933011DA/taptapinfinity.app>”
)
Jun 9 07:50:39 Bens-iPhone atc[2543] : [appinstallation] LaunchServices observer: Apps Failed be Uninstalled: (
“<LSApplicationProxy: 0x15cdd5c00> com.scarybee.taptapinfinity <file:///private/var/containers/Bundle/Application/B2020376-DF01-4262-8ED6-8CC6933011DA/taptapinfinity.app>”
)
Jun 9 07:50:39 Bens-iPhone nsurlsessiond[2446] : [appinstallation] LaunchServices observer: Apps Failed be Uninstalled: (
“<LSApplicationProxy: 0x124d4dc30> com.scarybee.taptapinfinity <file:///private/var/containers/Bundle/Application/B2020376-DF01-4262-8ED6-8CC6933011DA/taptapinfinity.app>”
)
Jun 9 07:50:39 Bens-iPhone BTServer[65] : [appinstallation] LaunchServices observer: Apps Failed be Uninstalled: (
“<LSApplicationProxy: 0x14656fc90> com.scarybee.taptapinfinity <file:///private/var/containers/Bundle/Application/B2020376-DF01-4262-8ED6-8CC6933011DA/taptapinfinity.app>”
)
Jun 9 07:50:39 Bens-iPhone profiled[2639] : [appinstallation] LaunchServices observer: Apps Failed be Uninstalled: (
“<LSApplicationProxy: 0x125e68d30> com.scarybee.taptapinfinity <file:///private/var/containers/Bundle/Application/B2020376-DF01-4262-8ED6-8CC6933011DA/taptapinfinity.app>”
)
Jun 9 07:50:39 Bens-iPhone passd[2470] : [appinstallation] LaunchServices observer: Apps Failed be Uninstalled: (
“<LSApplicationProxy: 0x14ed52a60> com.scarybee.taptapinfinity <file:///private/var/containers/Bundle/Application/B2020376-DF01-4262-8ED6-8CC6933011DA/taptapinfinity.app>”
)
Jun 9 07:50:39 Bens-iPhone AppStore[2696] : ITML : Unknown timer:
Jun 9 07:50:39 Bens-iPhone AppStore[2696] : ITML : Unknown timer:
Jun 9 07:50:39 Bens-iPhone AppStore[2696] : ITML : Unknown timer:
Jun 9 07:50:39 Bens-iPhone AppStore[2696] : ITML : Unknown timer:
Jun 9 07:50:39 Bens-iPhone AppStore[2696] : ITML : Unknown timer:
Jun 9 07:50:39 Bens-iPhone AppStore[2696] : ITML : Unknown timer:
Jun 9 07:50:39 Bens-iPhone AppStore[2696] : ITML : Unknown timer:
Jun 9 07:51:01 Bens-iPhone syncdefaultsd[2748] : (Note ) marked “com.me.keyvalueservice” topic as “opportunistic” on <APSConnection: 0x124e11a30>
Jun 9 07:51:01 Bens-iPhone syncdefaultsd[2748] : (Note ) marked “com.me.keyvalueservice” topic as “enabled” on <APSConnection: 0x124e11a30>
Jun 9 07:51:02 Bens-iPhone MobileGestaltHelper[2458] : libMobileGestalt MobileGestalt.c:281: server_access_check denied access to question UniqueDeviceID for pid 2748
Jun 9 07:51:02 Bens-iPhone syncdefaultsd[2748] : libMobileGestalt MobileGestaltSupport.m:151: pid 2748 (syncdefaultsd) does not have sandbox access for re6Zb+zwFKJNlkQTUeT+/w and IS NOT appropriately entitled
Jun 9 07:51:02 Bens-iPhone syncdefaultsd[2748] : libMobileGestalt MobileGestalt.c:542: no access to UniqueDeviceID (see rdar://problem/11744455)
Jun 9 07:51:40 Bens-iPhone SpringBoard[58] : [MPUSystemMediaControls] Disabling lock screen media controls updates for screen turning off.

  • user manually switches back to app
  • no ProcessPurchase() is triggered, only IAP log message I see is ‘: UnityIAP:UpdatedTransactions’

This leaves the user billed but without their purchase. If the user tries to buy the item again:

  • an alert comes up saying they’ve already bought the item and it will be restored for free
  • … and then nothing happens - neither OnPurchaseFailed() or ProcessPurchase() are called.
  • restarting the app doesn’t change this - the user is unable to purchase the consumable item again.

I’m assuming I might be able to hack around the initial flow breaking by calling RestoreTransactions() on application unpause. Will this work? Is there some other recommended way to handle this automatically?

We have had another report of this recently. It sounds like a repeat of previous incidents with Apple’s storekit system that they previously resolved with a server side change.

From that log it seems storekit is sending only an SKPaymentTransactionStatePurchasing event and not a SKPaymentTransactionStatePurchased event, which it should do automatically to conclude the payment flow.

Please raise a TSI with Apple and report back their response.

Thanks for the links, after reading through them it does sound similar but I can also see it being an issue with the Unity API - for instance is the transaction handler getting removed after the failed message? If this were an iOS specific issue my expectation would be more noise on the Apple forums … so I’m still thinking this is a Unity rather than Apple issue.

This is on the TSI page currently:

Someone at Unity has to have a higher level of access to dev support at Apple and/or a way to confirm that this is actually an iOS issue. Please escalate this on your side. Cheers!

I have just tested this in production with our reference App that uses Unity IAP:

  1. Remove payment method from itunes account
  2. Sign out of the app store on device
  3. Launch App & initiate consumable purchase
  4. Sign into app store
  5. Confirm the IAP
  6. Go back to the Application
  7. Purchase is detected and processed as expected

We don’t remove our transaction listener, it is in place for the life of the Application, and we finish failed transactions; ie. we follow the best practices outlined by Apple in those threads.

I can never rule out a Unity IAP bug but, based on the correct behaviour of our reference implementation and the available evidence of log information you have provided, storekit is not behaving as it should for your App; it is not sending a SKPaymentTransactionStatePurchased event.

This may be specific to your App or user accounts of some combination thereof. I have made enquiries as to any contacts we may have, but they are likely also caught up in the WWDC.

Thanks for checking.