Durant les proves d’IAP abans de publicar, ens vam trobar amb un problema típic però molt confús:
- L’usuari prem «Continua la compra»
- El botó passa a «Processant»
- Al cap d’uns segons torna a «Continua la compra»
- No apareix la finestra de confirmació de compra de l’App Store
Aquest article recull tot el camí de diagnosi, els logs clau, la causa arrel i una estratègia de correcció aplicable abans del llançament.
1. Símptoma
La llista de productes de la pantalla de compra es carregava correctament, però en prémer el botó:
- Es cridava
purchase() - No apareixia cap diàleg del sistema
- La UI acabava tornant a estat de no compra
D’entrada semblava que «la compra no s’havia iniciat», però els logs deien una altra cosa.
2. Primera ronda: verificar si el flux de compra realment s’executa
Vam afegir logs a tots els punts crítics del flux:
- Paràmetres del clic al botó
- Entrada de
purchaseSelectedProduct()i branques deguard - Abans/després de
product.purchase() Transaction.updatesrefreshEntitlements()Transaction.currentEntitlementsTransaction.latest(for:)
Resultat:
purchase()retornava.success- La verificació de transacció era correcta i també s’executava
transaction.finish() - Però
entitledIDscontinuava buit
Això indica que: no era un problema de «no iniciar la compra», sinó de «no reconèixer els drets després de comprar».
3. Fets decisius detectats en aprofundir
Amb més logs, van aparèixer senyals clars:
- El recompte d’iteracions de
Transaction.currentEntitlementsera0 Transaction.latest(for: monthly)tenia un registre vàlid, però caducat- El més important: abans de comprar hi havia transaccions antigues a
Transaction.unfinished - El
purchase()actual retornava una transacció del flux antic, no d’una compra interactiva nova
Això explica per què «no surt cap finestra»:
- StoreKit retorna primer una transacció antiga processable (unfinished / flux històric)
- El codi la marca com a
finish() - La compra sembla «correcta», però no entra al flux de confirmació nou que espera l’usuari
4. Causa arrel
No era un únic factor, sinó la combinació de dos:
- Transaccions no finalitzades (
unfinished transaction) que interfereixen en el flux de compra - Cadena de subscripció sandbox en estat caducat (encara que hi hagi
latest transaction, pot no ser un entitlement actiu)
Per això el comportament final era: sense pop-up, èxit aparent i drets buits.
5. Estratègia de correcció (validada en pràctica)
5.1 Netejar transaccions unfinished abans de comprar
En iniciar l’app i abans de prémer comprar, recorre Transaction.unfinished i executa finish() per a cada transacció verificada, per evitar que les transaccions antigues interceptin el flux nou.
5.2 Mantenir i reforçar logs de diagnosi (recomanat abans d’enviar)
Val la pena conservar aquests logs fins al llançament:
- Snapshot de
unfinished transaction subscription status(state, renewal info)- Nombre d’iteracions de
currentEntitlements transaction/expirationdelatest(for:)
5.3 Doble canal per determinar drets (millora opcional)
Si en alguns entorns currentEntitlements queda temporalment buit, pots usar latest(for:) com a fallback (sempre validant que continuï actiu).
6. Checklist IAP abans de publicar
- Abans de cada prova, comprova l’estat de la subscripció del compte Sandbox (si ha caducat o no)
- Mostra el nombre d’elements
unfinishedals punts crítics - Prova tres escenaris: «primera compra / renovació després de caducar / restauració de compra»
- Verifica que
currentEntitlementsilatestsiguin coherents - Si «no apareix finestra», mira primer si ha entrat en un flux de transacció antic
7. Conclusió
«Premre comprar i no veure cap finestra» no implica necessàriament un problema d’UI o de timing de crida.
A StoreKit 2, l’estat de les transaccions, la cua d’unfinished i el cicle de vida de la subscripció condicionen el resultat final.
Si abans de publicar afegeixes aquests logs i la neteja prèvia, reduiràs molts problemes d’IAP difícils de reproduir en producció.