Tijdens IAP-tests vóór release liepen we tegen een klassiek maar erg verwarrend probleem aan:

  • De gebruiker tikt op “Doorgaan met kopen”
  • De knop gaat naar “Verwerken”
  • Na een paar seconden springt hij terug naar “Doorgaan met kopen”
  • Er verschijnt geen App Store-bevestigingsvenster

In dit artikel leggen we het volledige onderzoekstraject vast: kernlogs, root cause en een praktisch herstelplan dat je vóór livegang kunt toepassen.

1. Symptoom

De productlijst op de aankooppagina laadde normaal, maar na het tikken op kopen:

  • purchase() werd aangeroepen
  • Er verscheen geen systeemdialoog
  • De UI viel uiteindelijk terug naar niet-aangekocht

Op het eerste gezicht leek het alsof de aankoopflow niet startte, maar de logs lieten iets anders zien.

2. Eerste controle: draait de aankoopflow echt?

We hebben logging toegevoegd op alle kritieke punten in de flow:

  • Parameters van de knopklik
  • Entry van purchaseSelectedProduct() en guard-takken
  • Voor/na product.purchase()
  • Transaction.updates
  • refreshEntitlements()
  • Transaction.currentEntitlements
  • Transaction.latest(for:)

Resultaat:

  • purchase() gaf .success terug
  • Transactieverificatie slaagde, en transaction.finish() werd ook uitgevoerd
  • Maar entitledIDs bleef leeg

Dit betekent: het probleem was niet “aankoop start niet”, maar “entitlements worden na aankoop niet herkend”.

3. Doorslaggevende bevindingen na verdiepend onderzoek

Na uitgebreidere logging zagen we duidelijke signalen:

  1. Transaction.currentEntitlements had een iteratie-aantal van 0
  2. Transaction.latest(for: monthly) bevatte een geldig record, maar dat was verlopen
  3. Belangrijker: vóór aankoop stonden er oude transacties in Transaction.unfinished
  4. De huidige purchase() gaf een transactie uit een oude keten terug, niet uit een nieuwe interactieve aankoop

Dat verklaart waarom er geen pop-up verscheen:

  • StoreKit retourneert eerst een verwerkbare oude transactie (unfinished / historische keten)
  • Je code rondt die af met finish()
  • De aanvraag lijkt “geslaagd”, maar gaat niet door het nieuwe bevestigingspad dat de gebruiker verwacht

4. Samenvatting root cause

Dit was geen enkelvoudige fout, maar een combinatie van twee factoren:

  • Unfinished transactions verstoren de aankoopflow
  • De sandbox-abonnementsketen staat op verlopen status (zelfs met latest transaction is dat niet per se een actieve entitlement)

Eindgedrag: geen pop-up, schijnbaar succes, lege entitlements.

5. Herstelstrategie (praktisch bewezen)

5.1 Unfinished transacties proactief opschonen vóór aankoop

Scan bij app-start en vóór aankoop Transaction.unfinished, en voer finish() uit op geverifieerde transacties zodat oude transacties de nieuwe aankoopflow niet kapen.

5.2 Diagnostische logs behouden en uitbreiden (aanbevolen vóór release)

Houd deze logs actief tot livegang:

  • Snapshot van unfinished transaction
  • subscription status (state, renewal info)
  • Iteratie-aantal van currentEntitlements
  • transaction/expiration-details van latest(for:)

5.3 Entitlement-check via dubbel pad (optionele hardening)

Als currentEntitlements in sommige omgevingen tijdelijk leeg is, gebruik dan latest(for:) als fallback (met controle op actieve status).

6. IAP-checklist vóór release

  1. Controleer vóór elke test de abonnementsstatus van het sandbox-account (verlopen of niet)
  2. Log het aantal unfinished in kritieke paden
  3. Test drie scenario’s: eerste aankoop / verlengen na verlopen / aankopen herstellen
  4. Controleer consistentie tussen currentEntitlements en latest
  5. Bij “geen pop-up”: controleer eerst of een oud transactiepad geraakt is

7. Conclusie

“Op kopen tikken zonder pop-up” betekent niet automatisch een UI- of timingprobleem.
In StoreKit 2 beïnvloeden transactiestatus, unfinished-queue en abonnementslevenscyclus direct het eindgedrag.

Door deze logs en opschoonstappen vóór release toe te voegen, voorkom je veel IAP-problemen die in productie lastig te reproduceren zijn.