Under IAP-test før lancering stødte vi på et klassisk, men meget forvirrende problem:

  • Brugeren trykker på “Fortsæt køb”
  • Knappen skifter til “Behandler”
  • Efter få sekunder går den tilbage til “Fortsæt køb”
  • App Stores købsbekræftelse popper ikke op

Denne artikel gennemgår hele fejlfindingsforløbet, nøglelogs, root cause og en praktisk løsning, der kan bruges før release.

1. Symptomet

Produktlisten på købssiden blev indlæst korrekt, men efter klik på køb:

  • purchase() blev kaldt
  • Ingen systemdialog blev vist
  • UI endte i ikke-købt tilstand igen

Ved første øjekast lignede det, at købet slet ikke startede, men loggene viste noget andet.

2. Første runde: virker købskæden faktisk?

Vi lagde logs ind på alle kritiske punkter i købskæden:

  • Parametre fra knapklik
  • Entry i purchaseSelectedProduct() og guard-grene
  • Før/efter product.purchase()
  • Transaction.updates
  • refreshEntitlements()
  • Transaction.currentEntitlements
  • Transaction.latest(for:)

Resultat:

  • purchase() returnerede .success
  • Transaktionen blev verificeret, og transaction.finish() blev også kørt
  • Men entitledIDs forblev tom

Det betyder: problemet var ikke “køb blev ikke startet”, men “rettigheder blev ikke genkendt efter køb”.

3. Afgørende fund ved dybere analyse

Efter mere detaljeret logging kom disse klare signaler frem:

  1. Transaction.currentEntitlements havde iterationsantal 0
  2. Transaction.latest(for: monthly) havde en gyldig post, men den var udløbet
  3. Vigtigst: før køb fandtes der gamle transaktioner i Transaction.unfinished
  4. Det aktuelle purchase() returnerede en transaktion fra en gammel kæde, ikke fra et nyt interaktivt køb

Det forklarer, hvorfor der “ikke kommer en popup”:

  • StoreKit returnerer først en gammel transaktion, der kan behandles (unfinished / historisk flow)
  • Koden kalder finish() på den
  • Købet ser “succesfuldt” ud, men går ikke gennem den nye købsbekræftelse, som brugeren forventer

4. Root cause opsummeret

Fejlen var ikke én enkelt årsag, men en kombination af to:

  • Uafsluttede transaktioner (unfinished transaction) forstyrrer købsflowet
  • Sandbox-abonnementskæden er i udløbet tilstand (selv med latest transaction er det ikke nødvendigvis en aktiv entitlement)

Det samlede symptom blev derfor: ingen popup, tilsyneladende succes, tomme rettigheder.

5. Løsningsstrategi (verificeret i praksis)

5.1 Ryd unfinished-transaktioner før køb

Ved app-start og før køb: scan Transaction.unfinished og kør finish() på verificerede transaktioner, så gamle transaktioner ikke kaprer det nye køb.

5.2 Bevar og styrk diagnostiske logs (anbefalet før release)

Følgende logs bør bevares frem til lancering:

  • Snapshot af unfinished transaction
  • subscription status (state, renewal info)
  • Iterationsantal for currentEntitlements
  • transaction/expiration fra latest(for:)

5.3 Brug “dobbelt kanal” til rettighedsvurdering (valgfri forbedring)

Hvis currentEntitlements midlertidigt er tom i visse miljøer, kan latest(for:) bruges som fallback (men verificér stadig, at rettigheden er aktiv).

6. IAP-checkliste før lancering

  1. Før hver test: bekræft abonnementstilstand for sandbox-kontoen (om den er udløbet)
  2. Log antal unfinished i kritisk sti
  3. Test tre scenarier: “førstegangskøb / fornyelse efter udløb / gendan køb”
  4. Kontrollér, at currentEntitlements og latest stemmer overens
  5. Hvis “ingen popup” opstår, tjek først om et gammelt transaktionsflow blev ramt

7. Afslutning

“Tryk på køb uden popup” betyder ikke nødvendigvis et UI-problem eller et timing-problem i kaldet.
I StoreKit 2 påvirker transaktionstilstand, unfinished-kø og abonnementets livscyklus det endelige resultat.

Ved at tilføje disse logs og oprydning før lancering kan man undgå mange IAP-problemer, som ellers er svære at reproducere i produktion.