# Što ćete izgraditi i zašto je to važno#
Ovaj vodič prolazi kroz implementaciju Flutter kupnji unutar aplikacije za jednokratne kupnje i pretplate, kroz dva pristupa:
- Direktna integracija sa storeovima pomoću
in_app_purchaseplugina - Produkcijski “friendly” pristup uz RevenueCat za validaciju računa, entitlements, paywallove i sinkronizaciju stanja pretplatnika
Ako isporučujete pretplate, pogreške su skupe. Apple i Google mogu ukinuti pristup zbog povrata, chargebackova, grace perioda, ponovnih pokušaja naplate te nadogradnji ili degradacija plana, a pristup koji se oslanja samo na klijenta će prije ili kasnije dodijeliti pristup pogrešnim korisnicima.
Pokrit ćemo postavke u storeovima, implementaciju, koncept validacije računa, sandbox testiranje te posebnu sekciju za debugging čestih produkcijskih kvarova.
# Preduvjeti#
| Zahtjev | Verzija | Napomena |
|---|---|---|
| Flutter | 3.19+ | Radi i na novijim verzijama |
| Dart | 3+ | Usklađeno s Flutter stable |
| iOS | Xcode 15+ | Potrebno za moderne iOS buildove |
| Android | AGP 8+ | Koristite aktualni Android Gradle Plugin |
| App Store Connect račun | Aktivan | S dovršenim ugovorima i bankovnim podacima |
| Google Play Console račun | Aktivan | S postavljenim payments profilom |
| Testiranje na stvarnom uređaju | Preporučeno | Emulatori mogu biti ograničeni za billing flowove |
Ako vam je release proces još uvijek ručan, riješite to što ranije. Problemi s IAP-om često su specifični za okruženje i često ćete rebuildati. Pogledajte naš CI vodič: Flutter CI/CD s GitHub Actions, Codemagic i Fastlane.
# Odlučite arhitekturu: direktno na storeove vs RevenueCat#
IAP u Flutteru najčešće se gradi na dva načina.
Opcija A: Native store integracija s in_app_purchase#
Prednosti:
- Nema dodatne ovisnosti o vendoru
- Niži kontinuirani trošak
- Puna kontrola
Nedostaci:
- Vi ste odgovorni za validaciju računa, obnove, povrate i rubne slučajeve
- Cross-platform stanje pretplatnika je teže uskladiti
- Restore purchases i entitlement logika moraju biti besprijekorni
Opcija B: RevenueCat iznad storeova#
Prednosti:
- Server-side validacija računa i upravljanje stanjem
- Entitlements i offerings ujednačuju iOS i Android
- Ugrađeni paywallovi i podrška za A B testiranje
- Bolja vidljivost (observability) promjena statusa pretplatnika
Nedostaci:
- Trošak vendora pri većem obujmu
- I dalje trebate ispravnu konfiguraciju storeova
- Još jedan SDK i dashboard za održavanje
| Mogućnost | Samo in_app_purchase | RevenueCat |
|---|---|---|
| Osnovni purchase flow | Da | Da |
| Validacija računa | Vi implementirate | Uključeno |
| Obnove i otkazivanja pretplata | Vi pratite | Uključeno |
| Abstrakcija entitlements | Vi implementirate | Uključeno |
| Paywall offerings | Vi implementirate | Uključeno |
| Restore purchases | Vi implementirate | Pojednostavljeni helperi |
| Cross-platform stanje pretplate | Teže | Lakše |
| Alati za debugging | Minimalno | Dashboard događaji i logovi |
🎯 Ključna poruka: Ako su pretplate ključan izvor prihoda, koristite RevenueCat osim ako već nemate zreo backend i iskustvo s billingom.
# Postavljanje proizvoda na Appleu: App Store Connect#
Appleove postavke određuju možete li uopće dohvatiti proizvode u sandboxu. Većina “product not found” bugova počinje ovdje.
1) Kreirajte aplikaciju i omogućite IAP capability#
- Kreirajte aplikaciju u App Store Connect s ispravnim bundle ID-jem
- U Xcodeu omogućite capability In-App Purchase za target
- Osigurajte da se bundle ID potpuno podudara između Xcodea, App Store Connecta i svih okruženja
2) Kreirajte In-App Purchase proizvode#
Apple ima tri najčešća IAP tipa za većinu Flutter aplikacija:
- Consumable: coinovi, krediti, jednokratni itemi koji se mogu ponovno kupiti
- Non-consumable: trajno otključavanje
- Auto-renewable subscription: mjesečni ili godišnji planovi
Za pretplate dodatno konfigurirate:
- Subscription Group: korisnik može imati samo jednu aktivnu pretplatu po grupi
- Subscription Levels: za upgrade i downgrade
Minimalni checklist po proizvodu:
- Reference name
- Product ID, npr.
com.samioda.app.pro.monthly - Pricing
- Localization display name i description
- Review screenshot u nekim slučajevima
3) Ugovori, porezi i bankovni podaci#
Ako ugovori nisu prihvaćeni ili bankovni podaci nisu dovršeni, kupnje mogu padati ili se proizvodi neće pojavljivati kako očekujete tijekom testiranja.
4) Sandbox testeri i testna distribucija#
Appleova očekivanja oko sandbox testiranja često “sapletu” timove:
- Za iOS instalirajte preko TestFlighta za realističnije testiranje. Lokalni debug install može dohvatiti proizvode, ali ćete rjeđe uhvatiti “stvarne” scenarije.
- Koristite sandbox Apple ID kreiran u App Store Connect pod users and access.
- Na uređaju se odjavite sa standardnog Apple ID-ja unutar App Store purchase flowa kad vas pita, pa se prijavite sa sandbox testerom.
⚠️ Upozorenje: Apple sandbox obnove pretplate su ubrzane i mogu se obnoviti više puta u kratkom roku. Aplikacija mora podnijeti više renewal događaja bez ponovnog dodjeljivanja consumables ili dupliranja zapisa o pristupu.
# Postavljanje proizvoda na Googleu: Play Console#
Google Play Billing je strog po pitanju testing trackova i računa.
1) Kreirajte aplikaciju i konfigurirajte billing#
- Kreirajte aplikaciju u Play Console
- Dovršite payments profil i svaku potrebnu verifikaciju
- Osigurajte da je aplikacija ispravno potpisana i barem jednom uploadana na testing track
2) Kreirajte proizvode i pretplate#
U Play Console:
- Sekcija Monetize za in-app products i subscriptions
- Kreirajte product ID-eve poput
pro_monthlyilipro_yearly - Dodajte base plans i offers za pretplate ako ih koristite
U 2026. Google pretplate se najčešće oslanjaju na:
- Base plans: definiraju period naplate i obnovu
- Offers: trial, intro cijene, regionalni popusti
3) License testeri i internal testing#
Očekivanja za testiranje:
- Dodajte svoj Gmail račun kao license tester
- Uploadajte App Bundle u Internal testing
- Instalirajte preko Play Store internal testing linka
Ako instalirate direktno preko Android Studija, Billing se može ponašati drugačije i često ne uspije dohvatiti “live” proizvode.
# Validacija računa i zašto klijent-only nije dovoljno#
Možete krenuti s client-side purchase flowovima, ali kontrola pristupa mora se oslanjati na pouzdan izvor.
Što može poći po zlu bez validacije#
- Jailbroken uređaj može lažirati purchase state
- Pretplata može biti refundirana ili završiti kao chargeback
- Naplata može ući u grace period ili account hold
- Korisnik može otkazati obnovu, ali i dalje biti aktivan do kraja perioda
- Google može pauzirati ili odgoditi naplatu i obnoviti kasnije
Odluka o pristupu treba se temeljiti na verificiranom stanju pretplate, ne na tome “korisnik nam je rekao da je platio”.
Dva praktična pristupa#
| Pristup | Kako radi | Najbolje za |
|---|---|---|
| Server-side validacija | Vaš backend validira Apple i Google račune i sprema trenutno stanje entitlementa | Timove s backendom + billing iskustvom |
| RevenueCat | SDK šalje purchase info, RC validira i prati entitlement state, aplikacija provjerava entitlements | Većinu pretplatničkih aplikacija |
Ako se aplikacija oslanja i na korisničke račune, kombinirajte stanje pretplatnika s vašim auth modelom. Ako implementirate auth i notifikacije, držite okruženja čista. Pogledajte Flutter push notifikacije s FCM i APNs u produkciji.
# Implementacija Flutter kupnji unutar aplikacije s in_app_purchase#
Ovo je najniža razina u Flutteru. Kasnije možete migrirati na RevenueCat.
1) Dodajte dependencyje#
# pubspec.yaml
dependencies:
in_app_purchase: ^3.2.0
in_app_purchase_storekit: ^0.3.20
in_app_purchase_android: ^0.4.0Držite verzije usklađene s vašim Flutter stable kanalom.
2) Dohvat proizvoda (query)#
Trebate točne store product ID-eve.
import 'package:in_app_purchase/in_app_purchase.dart';
final iap = InAppPurchase.instance;
Future<List<ProductDetails>> fetchProducts() async {
final ids = <String>{
'com.samioda.app.pro.monthly',
'com.samioda.app.pro.yearly',
};
final available = await iap.isAvailable();
if (!available) return [];
final response = await iap.queryProductDetails(ids);
if (response.error != null) {
throw Exception('IAP query error: ${response.error}');
}
return response.productDetails;
}Česti uzroci praznih rezultata:
- Pogrešni product ID-evi
- Aplikacija instalirana izvan TestFlighta ili Play internal testinga
- Proizvod nije u “Ready to submit” stanju, nedostaju metapodaci ili nije odobren za testiranje
3) Pokrenite kupnju#
Za non-consumables i pretplate koristite buyNonConsumable. Za consumables koristite buyConsumable i odlučite kako dodjeljujete i bilježite kredite.
Future<void> buy(ProductDetails product) async {
final param = PurchaseParam(productDetails: product);
await iap.buyNonConsumable(purchaseParam: param);
}4) Slušajte purchase updateove i završite transakcije#
Purchase updateovi dolaze kao stream. Morate:
- verificirati kupnju
- dodijeliti pristup
- završiti transakciju
late final StreamSubscription<List<PurchaseDetails>> sub;
void startListening() {
sub = iap.purchaseStream.listen((purchases) async {
for (final p in purchases) {
if (p.status == PurchaseStatus.purchased ||
p.status == PurchaseStatus.restored) {
final ok = await verifyOnServer(p);
if (ok) {
await grantEntitlement(p.productID);
}
}
if (p.pendingCompletePurchase) {
await iap.completePurchase(p);
}
}
});
}verifyOnServer je teški dio. Za pretplate verifikacija nije opcionalna ako želite točnu kontrolu pristupa.
5) Restore purchases#
Korisnici očekuju da restore radi na iOS-u. Važno je i nakon reinstalacije.
Future<void> restore() async {
await iap.restorePurchases();
}Restore nije potpuno rješenje za pretplate osim ako dodatno verificirate trenutno stanje i obrađujete isteke, povrate i obnove.
💡 Savjet: “restore” tretirajte kao okidač za osvježavanje verificiranog stanja pretplatnika, ne kao dokaz aktivnog pristupa.
# Implementacija pretplata s RevenueCat#
RevenueCat uklanja većinu složenosti oko računa i daje čistu provjeru entitlementa.
1) Kreirajte RevenueCat projekt i povežite storeove#
U RevenueCat-u:
- Kreirajte projekt
- Dodajte iOS i Android aplikacije
- Povežite App Store Connect i Google Play
- Importajte proizvode
Ključni koncepti: Offerings i Entitlements.
2) Definirajte entitlements i mapirajte proizvode#
Primjer:
- Entitlement:
pro - Proizvodi: mjesečna i godišnja pretplata
- Ako je pretplata aktivna, entitlement
proje aktivan
Ovo sprječava da logika aplikacije bude vezana uz konkretne product ID-eve. Kasnije možete mijenjati cijene i proizvode bez updatea aplikacije.
3) Dodajte dependency i inicijalizirajte#
# pubspec.yaml
dependencies:
purchases_flutter: ^8.3.0Inicijalizirajte rano, najčešće nakon pokretanja aplikacije i nakon što imate stabilan app user id ako koristite račune.
import 'package:purchases_flutter/purchases_flutter.dart';
Future<void> initRevenueCat() async {
await Purchases.setLogLevel(LogLevel.info);
await Purchases.configure(
PurchasesConfiguration('public_sdk_key_here'),
);
}Ako imate autentikaciju, identificirajte korisnike kako bi kupnje “pratile” korisnika kroz uređaje.
Future<void> loginToRevenueCat(String appUserId) async {
await Purchases.logIn(appUserId);
}4) Dohvatite offerings i prikažite paywall#
Future<Offering?> fetchPaywall() async {
final offerings = await Purchases.getOfferings();
return offerings.current;
}Vaš paywall UI treba prikazati:
- naziv plana
- cijenu i period
- trial ako postoji
- restore gumb
- jasne uvjete i link za upravljanje pretplatom
Kad korisnik odabere package:
Future<void> purchasePackage(Package pkg) async {
final result = await Purchases.purchasePackage(pkg);
final proActive = result.customerInfo.entitlements.active.containsKey('pro');
if (!proActive) throw Exception('Purchase completed but pro not active');
}5) Provjerite entitlement bilo gdje#
Aplikacija treba “gateati” featuree na temelju entitlementa, ne na temelju lokalnog booleana.
Future<bool> hasPro() async {
final info = await Purchases.getCustomerInfo();
return info.entitlements.active.containsKey('pro');
}Ovo pouzdanije pokriva obnove, otkazivanja, povrate i restore kroz uređaje nego ručne provjere purchase historyja.
# Paywallovi koji konvertiraju bez da dobijete odbijenicu#
Paywall je i proizvod i compliance. Apple i Google odbijaju nejasne cijene ili nedostajući restore i uvjete.
Praktični paywall checklist#
| Stavka | Zašto je bitno | Primjer |
|---|---|---|
| Jasna cijena i period | Sprječava obmanjujući UX | “€4.99 mjesečno” |
| Disclosure triala | Obavezno ako nudite trial | “7 dana besplatno, zatim €4.99 mjesečno” |
| Restore purchases gumb | Obavezno na iOS-u | “Vrati kupnje” |
| Link za upravljanje pretplatom | Smanjuje broj support upita | Link na sistemsko upravljanje pretplatama |
| Linkovi na uvjete i privatnost | Review compliance | “Uvjeti” i “Privatnost” |
Držite paywall logiku jednostavnom:
- 1 primarni CTA za preporučeni plan
- mjesečni i godišnji izbor
- istaknite godišnju uštedu s realnom matematikom, npr. “€49.99 godišnje je €4.17 mjesečno”
Ako trebate procijeniti budžet i timeline za dodavanje pretplata i paywallova, koristite ovaj kontekst cijena: Cijena Flutter aplikacije u 2026..
# Sandbox i postavljanje testnog okruženja#
Većina billing bugova je zapravo “ne vrti se u sandboxu”.
Apple sandbox testiranje — workflow#
- 1Kreirajte sandbox testera u App Store Connect
- 2Instalirajte aplikaciju iz TestFlighta
- 3Pokrenite purchase flow
- 4Prijavite se sa sandbox Apple ID-jem kad vas prompt traži
Očekivano ponašanje:
- Obnove pretplata se događaju brzo u sandboxu
- Možete vidjeti više obnova i isteka u nekoliko minuta
- Otkazivanje i togglanje obnove radi se u iOS settings za sandbox račun
Google testiranje — workflow#
- 1Uploadajte AAB u Internal testing
- 2Dodajte sebe kao testera i license testera
- 3Instalirajte iz Play Store testing linka
- 4Pokrenite kupnje u aplikaciji
Očekivano ponašanje:
- Purchase dialog prikazuje “test” indikacije za license testere
- Lifecycle događaji pretplate su brži nego u produkciji
Validirajte signale da ste u testnom okruženju#
| Platforma | Signal da ste u sandboxu | Brza provjera |
|---|---|---|
| iOS | Sandbox login prompt i sandbox subscription management | Settings app prikazuje sandbox kontekst računa |
| Android | Test purchase dialog i test card ponašanje | Play Store račun je tester i aplikacija je instalirana iz Playja |
# Česti produkcijski problemi i kako ih debugirati#
Ova sekcija je razlika između “radilo je jednom” i stabilnog prihoda.
Problem 1: Proizvodi vraćaju praznu listu#
Najvjerojatniji uzroci:
- Nepodudaranje product ID-eva
- Aplikacija instalirana putem sideloada ili debug-a, a ne TestFlighta ili Play testinga
- Proizvodi nisu odobreni, nedostaje lokalizacija ili nisu “Ready”
- Država store računa se ne podudara s dostupnošću proizvoda
Koraci za debug:
- 1Logirajte queryane ID-eve i environment build flavor
- 2Potvrdite izvor instalacije i track
- 3Potvrdite stanje proizvoda i potpunost metapodataka
- 4Testirajte s novim sandbox tester ili license tester računom
Problem 2: Kupnja završi, ali entitlement nije aktivan#
Tipični uzroci:
- Zatvorili ste kupnju (complete) prije nego je verifikacija završila
- Pogrešno mapiranje entitlementa u RevenueCat-u
- Provjeravate lokalni cache umjesto osvježenog customer info
- Mrežni problemi tijekom post-purchase synca
Koraci za debug:
- 1Nakon kupnje pozovite
getCustomerInfoi provjerite active entitlements - 2U RevenueCat dashboardu pregledajte customer timeline
- 3Na iOS-u potvrdite da je korišten ispravan Apple ID
- 4Ponovite fetch na app resume i nakon kratkog delayja
Problem 3: Duple dodjele ili “nestali” consumables#
Consumables zahtijevaju idempotentnost. Ako aplikacija dvaput dodijeli kredite, curit će prihod.
Pattern za popravak:
- Spremite transaction ID i dodijelite samo jednom
- Ako je moguće, dodjelu napravite atomarnom na backendu
Problem 4: iOS “Ask to Buy” i iznenađenja s family sharingom#
Ako podržavate family sharing ili naletite na flowove roditeljskog odobrenja, kupnje mogu ostati pending. UI mora obraditi PurchaseStatus.pending i dati jasno stanje.
Problem 5: Google pretplate su aktivne u Playu, ali ne i u aplikaciji#
Često uzrokovano s:
- Pogrešnim Google računom na uređaju
- Cache problemima Play servicesa
- Aplikacija nije potpisana istim ključem kao build uploadan na track
Koraci za debug:
- 1Provjerite signing key i package name
- 2Potvrdite da je Play račun na uređaju tester račun
- 3Clearanje Play Store cachea koristite samo kao zadnju opciju
- 4Koristite RevenueCat dashboard ili backend logove za potvrdu validation događaja
Problem 6: Webhookovi i backend se ne ažuriraju nakon obnova#
Ako koristite RevenueCat webhooks ili store server notifikacije, propušten webhook može uzrokovati zastarjeli pristup kod vas.
Ublažavanja:
- Uvijek dopustite aplikaciji da osvježi entitlement state na launch i resume
- Webhook processing učinite idempotentnim i otpornim na retry
- Čuvajte timestamp “last verified at” i periodično re-provjerite
ℹ️ Napomena: Stanje pretplatnika je event-driven, ali aplikacija mora biti otporna na propuštene evente. Periodično osvježavanje entitlementa je jeftino i sprječava dugotrajno pogrešan pristup.
# Operativni checklist prije launch-a#
Koristite ovo kao last-mile listu za produkcijsku spremnost.
| Područje | Provjera | Zašto |
|---|---|---|
| Proizvodi | ID-evi, cijene, lokalizacija | Sprječava prazne liste proizvoda i odbijenice |
| Paywall | Restore, uvjeti, jasne cijene | Review compliance i povjerenje |
| Kontrola pristupa | Entitlements, ne lokalne flagove | Sprječava prijevare i zastarjeli pristup |
| Testiranje | TestFlight i Internal testing | Pravo ponašanje storeova |
| Observability | Logovi za korake kupnje | Brži debugging |
| Release | Automatizirani buildovi i verzioniranje | Manje ljudskih grešaka |
Ako vam je build i release pipeline krhak, billing popravci će trajati dulje i uzrokovati churn. Automatizaciju postavite rano: Flutter CI/CD s GitHub Actions, Codemagic i Fastlane.
# Ključne poruke#
- Koristite entitlements kao sloj pristupa, ne gole product ID-eve, kako bi billing logika ostala stabilna kroz promjene cijena i proizvoda.
- Za pretplate izbjegnite client-only logiku i koristite server-side validaciju ili RevenueCat kako biste pokrili obnove, povrate, grace periode i chargebackove.
- IAP uvijek testirajte preko stvarnih distribucijskih kanala: TestFlight na iOS-u i Play Internal testing na Androidu — inače ćete loviti lažne bugove.
- Purchase handling gradite idempotentno, posebno za consumables, kako biste spriječili duple dodjele i curenje prihoda.
- Kod debugiranja “kupnja je uspjela, ali pristup nedostaje”, pregledajte customer timeline, osvježite customer info nakon kupnje i provjerite store račun i signing key-eve.
# Zaključak#
Flutter kupnje unutar aplikacije lako je demonstrirati, a iznenađujuće ih je lako “slomiti” u produkciji ako preskočite validaciju, entitlements i stvarno sandbox testiranje. Ispravno postavite proizvode u App Store Connect i Play Console, implementirajte purchase flowove s jasnim paywallovima i oslanjajte se na verificirano stanje entitlementa umjesto na lokalne flagove.
Ako želite da Samioda implementira pretplate end-to-end, uključujući RevenueCat setup, paywall UX, webhook integraciju i release automatizaciju, kontaktirajte nas i definirat ćemo plan isporuke spreman za produkciju koji odgovara vašem timelineu i budžetu.
FAQ
Osnivač i senior developer u Samiodi. 8+ godina iskustva u izradi React, Next.js, Flutter i n8n rješenja za klijente diljem Europe.
Više iz kategorije Mobilni razvoj
Sve →Usporedba lokalnih baza u Flutteru: Hive vs Isar vs sqflite vs Drift (Vodič za 2026.)
Praktična usporedba Flutter lokalnih baza za 2026.: Hive vs Isar vs sqflite vs Drift, uz smjernice za performanse, upite, migracije, enkripciju i web podršku za uobičajene tipove aplikacija.
Flutter animacije u produkciji: implicitne vs. eksplicitne, Rive i Lottie te savjeti za performanse
Praktični vodič za Flutter animacije u produkcijskim aplikacijama: kada koristiti implicitne naspram eksplicitnih animacija, provjereni obrasci za AnimationController, Hero prijelazi, kompromisi Rive i Lottie te strategije za performanse i testiranje kako biste zadržali 60fps.
Flutter + Supabase vs Firebase u 2026: Auth, Realtime, Offline, Cijene i Lock-In
Praktična usporedba za 2026. Fluttera sa Supabaseom i Firebaseom kroz auth, push, realtime, offline/local-first, storage, funkcije, cijene i vendor lock-in — uz preporuke po tipu aplikacije i skali.
Trebate pomoć s projektom?
Gradimo prilagođena rješenja koristeći tehnologije iz ovog članka. Senior tim, fiksne cijene.
Povezani članci
Flutter vs izvorni iOS/Android u 2026.: kompromisi između troška, performansi i vremena do izlaska na tržište
Praktična, brojkama potkrijepljena usporedba Fluttera i izvornog iOS-a i Androida za 2026. — uključuje model troška, realnost performansi, utjecaj održavanja i okvir za odluku za MVP-ove, UI visokih performansi, zahtjevne platform API-je i regulirane aplikacije.
Koliko košta MVP mobilne aplikacije? Realistična razrada (2026)
Objašnjenje troška MVP-a mobilne aplikacije uz realne razrade po funkcionalnostima, raspona prema tipu aplikacije i usporedbu Fluttera i nativnog razvoja kako biste realno isplanirali budžet.
Cijena Razvoja Flutter Aplikacije u 2026: Potpuni Vodič
Koliko košta Flutter aplikacija u 2026? Potpuna raščlamba cijena po složenosti aplikacije, funkcionalnostima i pristupu razvoju.