Under IAP-testning före lansering stötte vi på ett klassiskt men väldigt förvirrande problem:

  • Användaren trycker på ”Fortsätt köp”
  • Knappen går till läget ”Bearbetar”
  • Efter några sekunder går den tillbaka till ”Fortsätt köp”
  • Ingen köpbekräftelse från App Store visas

I den här artikeln dokumenterar vi hela felsökningsspåret, nyckelloggar, rotorsak och en praktisk åtgärdsstrategi inför release.

1. Symptom

Produktlistan på köpsidan laddades normalt, men efter tryck på köp:

  • purchase() anropades
  • Ingen systemdialog visades
  • UI gick till slut tillbaka till ej köpt-läge

Vid första anblick såg det ut som att köpflödet aldrig startade, men loggarna visade något annat.

2. Första kontrollen: körs köpflödet faktiskt?

Vi lade till loggar på alla kritiska punkter i köpflödet:

  • Parametrar från knapptryck
  • Inträde i purchaseSelectedProduct() och guard-grenar
  • Före/efter product.purchase()
  • Transaction.updates
  • refreshEntitlements()
  • Transaction.currentEntitlements
  • Transaction.latest(for:)

Resultat:

  • purchase() returnerade .success
  • Transaktionsverifiering lyckades och transaction.finish() kördes också
  • Men entitledIDs förblev tom

Det betyder: problemet var inte ”köpet startade inte”, utan ”behörigheter kändes inte igen efter köp”.

3. Avgörande fynd efter djupare analys

Efter mer detaljerad loggning framträdde flera tydliga signaler:

  1. Transaction.currentEntitlements hade iterationsantal 0
  2. Transaction.latest(for: monthly) hade en giltig post, men den var utgången
  3. Viktigast: före köpet fanns gamla transaktioner i Transaction.unfinished
  4. Det aktuella purchase() returnerade en transaktion från en gammal kedja, inte från ett nytt interaktivt köp

Det förklarar varför ingen popup kom:

  • StoreKit returnerade först en gammal processbar transaktion (unfinished / historisk kedja)
  • Koden avslutade den med finish()
  • Förfrågan såg ”lyckad” ut, men gick inte via det nya bekräftelseflödet som användaren förväntar sig

4. Sammanfattning av rotorsak

Det var inte en enskild felpunkt, utan en kombination av två faktorer:

  • Unfinished transactions stör köpflödet
  • Sandbox-prenumerationskedjan är i utgånget tillstånd (även med latest transaction är det inte nödvändigtvis en aktiv entitlement)

Slutbeteendet blev: ingen popup, skenbar framgång, tomma behörigheter.

5. Åtgärdsstrategi (verifierad i praktiken)

5.1 Rensa unfinished-transaktioner proaktivt före köp

Vid appstart och före köp: skanna Transaction.unfinished och kör finish() på verifierade transaktioner så att gamla transaktioner inte kapar det nya köpflödet.

5.2 Behåll och stärk diagnostiska loggar (rekommenderas före lansering)

Dessa loggar bör hållas aktiva fram till release:

  • Snapshot av unfinished transaction
  • subscription status (state, renewal info)
  • Iterationsantal för currentEntitlements
  • transaction/expiration-detaljer i latest(for:)

5.3 Använd dubbel kanal för behörighetskontroll (valfri förstärkning)

Om currentEntitlements tillfälligt är tom i vissa miljöer, använd latest(for:) som fallback (med fortsatt validering av aktiv status).

6. IAP-checklista före lansering

  1. Före varje test: kontrollera prenumerationsstatus för sandbox-kontot (utgånget eller inte)
  2. Logga antal unfinished på kritiska vägar
  3. Testa tre scenarier: första köp / förnyelse efter utgång / återställ köp
  4. Kontrollera konsistens mellan currentEntitlements och latest
  5. Om ”ingen popup” uppstår, kontrollera först om en gammal transaktionsväg träffades

7. Slutsats

”Tryck på köp utan popup” betyder inte nödvändigtvis ett UI-problem eller ett timingproblem i anropen.
I StoreKit 2 påverkar transaktionsstatus, unfinished-kö och prenumerationens livscykel slutbeteendet direkt.

Genom att lägga till dessa loggar och städrutiner före lansering kan du minska många IAP-problem som annars är svåra att återskapa i produktion.