Tijekom IAP testiranja prije objave naišli smo na tipičan, ali vrlo zbunjujuć problem:

  • Korisnik pritisne „Nastavi kupnju”
  • Gumb pređe u stanje „Obrada”
  • Nakon nekoliko sekundi vrati se na „Nastavi kupnju”
  • Ne prikazuje se App Store prozor za potvrdu kupnje

U ovom članku bilježimo cijeli put dijagnostike, ključne logove, root cause i praktičnu strategiju popravka prije izlaska.

1. Simptom

Popis proizvoda na ekranu kupnje učitavao se normalno, ali nakon klika na kupnju:

  • purchase() je bio pozvan
  • Nije se pojavio sistemski dijalog
  • UI se na kraju vratio u stanje „nije kupljeno”

Na prvi pogled izgledalo je kao da se kupnja uopće nije pokrenula, ali logovi su pokazali drugačije.

2. Prva provjera: prolazi li tok kupnje stvarno kroz sustav?

Dodali smo logove na sve kritične točke toka kupnje:

  • Parametri klika na gumb
  • Ulaz u purchaseSelectedProduct() i guard grane
  • Prije/poslije product.purchase()
  • Transaction.updates
  • refreshEntitlements()
  • Transaction.currentEntitlements
  • Transaction.latest(for:)

Rezultat:

  • purchase() je vratio .success
  • Verifikacija transakcije je uspjela i transaction.finish() se izvršio
  • Ali entitledIDs je ostao prazan

To znači: problem nije bio „kupnja nije pokrenuta”, nego „nakon kupnje entitlementi nisu prepoznati”.

3. Ključna otkrića nakon dublje analize

Nakon proširenog logiranja pojavilo se nekoliko odlučujućih signala:

  1. Broj iteracija Transaction.currentEntitlements bio je 0
  2. Transaction.latest(for: monthly) imao je valjan zapis, ali istekao
  3. Još važnije: prije kupnje su postojale stare transakcije u Transaction.unfinished
  4. Trenutni purchase() vratio je transakciju iz starog lanca, a ne iz nove interaktivne kupnje

To objašnjava zašto nema popupa:

  • StoreKit prvo vrati staru obradivu transakciju (unfinished / povijesni lanac)
  • Kod je zatim dovrši pozivom finish()
  • Zahtjev izgleda „uspješno”, ali ne prolazi kroz novi put potvrde kupnje koji korisnik očekuje

4. Sažetak uzroka

Nije riječ o jednoj grešci, nego o kombinaciji dva faktora:

  • Nedovršene transakcije (unfinished transaction) ometaju tok kupnje
  • Sandbox pretplatnički lanac je u isteklom stanju (čak i uz latest transaction, to ne mora biti aktivan entitlement)

Konačno ponašanje: nema popupa, prividan uspjeh, entitlementi prazni.

5. Strategija popravka (potvrđena u praksi)

5.1 Proaktivno očistite unfinished transakcije prije kupnje

Pri pokretanju aplikacije i prije kupnje prođite Transaction.unfinished i pozovite finish() za verificirane transakcije, kako stare transakcije ne bi „preuzele” novi tok kupnje.

5.2 Zadržite i pojačajte dijagnostičke logove (preporučeno prije objave)

Ove logove vrijedi ostaviti uključene do izlaska:

  • Snapshot unfinished transaction
  • subscription status (state, renewal info)
  • Broj iteracija currentEntitlements
  • transaction/expiration detalji iz latest(for:)

5.3 Dvokanalna provjera entitlementa (opcionalno poboljšanje)

Ako je u nekim okruženjima currentEntitlements privremeno prazan, koristite latest(for:) kao fallback (uz obaveznu provjeru da je i dalje active).

6. IAP checklist prije objave

  1. Prije svakog testa provjerite stanje pretplate sandbox računa (je li istekla)
  2. Logirajte broj unfinished stavki na kritičnim putanjama
  3. Testirajte tri scenarija: „prva kupnja / obnova nakon isteka / restore kupnje”
  4. Provjerite konzistentnost između currentEntitlements i latest
  5. Ako se dogodi „nema popupa”, prvo provjerite je li pogođen stari transakcijski put

7. Zaključak

„Klik na kupnju bez popupa” ne znači nužno UI problem ili problem tajminga poziva.
U StoreKit 2, stanje transakcija, unfinished red i životni ciklus pretplate izravno utječu na završno ponašanje.

Dodavanje ovih logova i koraka čišćenja prije objave značajno smanjuje IAP probleme koje je teško reproducirati u produkciji.