Počas IAP testovania pred vydaním sme narazili na typický, no veľmi mätúci problém:

  • Používateľ klepne na „Pokračovať v nákupe“
  • Tlačidlo prejde do stavu „Spracováva sa“
  • Po pár sekundách sa vráti na „Pokračovať v nákupe“
  • Nezobrazí sa potvrdzovacie okno nákupu z App Store

V tomto článku dokumentujeme celý postup vyšetrovania, kľúčové logy, root cause a praktickú stratégiu opravy pred release.

1. Symptóm

Zoznam produktov na obrazovke nákupu sa načítaval normálne, ale po kliknutí na kúpu:

  • Volalo sa purchase()
  • Nezobrazil sa žiadny systémový dialóg
  • UI sa nakoniec vrátilo do stavu „nekúpené“

Na prvý pohľad to vyzeralo, že nákupný flow sa vôbec nespúšťa, no logy ukázali iný obraz.

2. Prvá kontrola: prechádza nákupný flow naozaj správne?

Doplnili sme logovanie do všetkých kritických bodov nákupného flow:

  • Parametre kliknutia na tlačidlo
  • Vstup do purchaseSelectedProduct() a vetvy guard
  • Pred/po product.purchase()
  • Transaction.updates
  • refreshEntitlements()
  • Transaction.currentEntitlements
  • Transaction.latest(for:)

Výsledok:

  • purchase() vracalo .success
  • Overenie transakcie prebehlo úspešne a transaction.finish() sa tiež vykonal
  • Ale entitledIDs ostalo prázdne

To znamená: problém nebol „nákup sa nespustil“, ale „po nákupe sa nerozpoznali entitlementy“.

3. Kľúčové zistenia po hlbšej analýze

Po rozšírení logov sa objavili rozhodujúce signály:

  1. Počet iterácií Transaction.currentEntitlements bol 0
  2. Transaction.latest(for: monthly) obsahoval validný záznam, ale už expirovaný
  3. Dôležitejšie: pred nákupom existovali staré transakcie v Transaction.unfinished
  4. Aktuálne purchase() vracalo transakciu zo starého reťazca, nie z nového interaktívneho nákupu

To vysvetľuje, prečo „nevyskočí okno“:

  • StoreKit najprv vráti spracovateľnú starú transakciu (unfinished / historický reťazec)
  • Kód ju dokončí cez finish()
  • Požiadavka vyzerá „úspešne“, ale neprejde novou cestou potvrdenia nákupu, ktorú používateľ očakáva

4. Zhrnutie root cause

Nešlo o jedno zlyhanie, ale o kombináciu dvoch faktorov:

  • Unfinished transactions narúšajú nákupný flow
  • Sandbox subscription reťazec je v expirovanom stave (aj pri latest transaction to nemusí byť aktívny entitlement)

Finálne správanie: bez pop-up okna, zdanlivý úspech, prázdne entitlementy.

5. Stratégia opravy (overená v praxi)

5.1 Proaktívne čistenie unfinished transactions pred nákupom

Pri štarte aplikácie a pred nákupom prejdite Transaction.unfinished a na verified transakciách vykonajte finish(), aby staré transakcie neprebrali nový nákupný flow.

5.2 Zachovať a posilniť diagnostické logy (odporúčané pred vydaním)

Tieto logy sa oplatí ponechať zapnuté až do release:

  • Snapshot unfinished transaction
  • subscription status (state, renewal info)
  • Počet iterácií currentEntitlements
  • Detaily transaction/expiration z latest(for:)

5.3 Dvojkanálové overenie entitlementov (voliteľné spevnenie)

Ak je v niektorých prostrediach currentEntitlements dočasne prázdne, použite latest(for:) ako fallback (stále však validujte aktívny stav).

6. IAP checklist pred vydaním

  1. Pred každým testom overte stav predplatného sandbox účtu (či je expirované)
  2. Logujte počet unfinished na kritických cestách
  3. Otestujte tri scenáre: prvý nákup / obnovenie po expirácii / obnova nákupov
  4. Skontrolujte konzistentnosť medzi currentEntitlements a latest
  5. Pri „bez pop-up okna“ najprv overte, či nebol zasiahnutý starý transakčný flow

7. Záver

„Kliknem kúpiť, ale bez pop-up okna“ nemusí znamenať UI problém ani problém načasovania volania.
V StoreKit 2 stav transakcií, unfinished fronta a životný cyklus predplatného priamo ovplyvňujú finálne správanie.

Doplnenie týchto logov a čistiacich krokov pred vydaním výrazne znižuje počet IAP problémov, ktoré sa v produkcii ťažko reprodukujú.