import { useEffect, useState } from 'react';
import { Platform } from 'react-native';
import Purchases, { PurchasesPackage } from 'react-native-purchases';
const API_KEYS = {
ios: 'appl_xxxxxxxxxxxxxx',
android: 'goog_xxxxxxxxxxxxxx',
};
export function useRevenueCat(userId?: string) { if (!userId) return;
const [currentPackage, setCurrentPackage] = useState<PurchasesPackage | null>(null);
const [isPro, setIsPro] = useState(false);
useEffect(() => {
async function init() {
Purchases.configure({
apiKey: Platform.OS === 'ios' ? API_KEYS.ios : API_KEYS.android,
appUserID: userId,
});
const customerInfo = await Purchases.getCustomerInfo();
setIsPro(Boolean(customerInfo.entitlements.active['pro_access']));
const offerings = await Purchases.getOfferings();
if (offerings.current?.availablePackages.length) {
setCurrentPackage(offerings.current.availablePackages[0]);
}
}
init().catch(console.error);
}, [userId]);
const makePurchase = async () => {
if (!currentPackage) return;
try {
const { customerInfo } = await Purchases.purchasePackage(currentPackage);
if (customerInfo.entitlements.active['pro_access']) {
setIsPro(true);
}
} catch (e: any) {
if (!e.userCancelled) console.error('Eroare achizitie:', e);
}
};
return { currentPackage, isPro, makePurchase };
}Dacă ai încercat vreodată să implementezi in-app purchases nativ pe iOS și Android fără o platformă de abstracție, probabil ai avut momente în care ai vrut să închizi laptopul și să te apuci de agricultură. La o aplicație de fitness cu 12k utilizatori activi lansată anul trecut, am trecut de la react-native-iap scris manual la RevenueCat și am scăzut timpul de debug de la 3 zile pe sprint la sub o oră.
Aici explic concret cum configurezi totul pe Expo (EAS Build), ce înseamnă arhitectura lor de tier-uri și ce capcane te așteaptă la testing pe ambele magazine.
Expo Setup fără bătăi de cap
Primul lucru de care te lovești: uită de Expo Go. Cumpărăturile in-app cer module native legate direct la StoreKit și Google Play Billing, deci ai nevoie obligatoriu de un Development Build generat prin EAS (eas build --profile development).
Instalezi SDK-ul oficial react-native-purchases și îl declari în app.json la secțiunea plugins. Fără pasul ăsta în Config Plugin, EAS nu îți linking-uiește corect dependențele native pe iOS/Android și te trezești cu erori bizare de tip NativeModule.Purchases is null la runtime.
Entitlements, Products și Offerings
Cea mai mare greșeală pe care o văd la devii juniori e că hardcodează ID-urile de produs (com.app.monthly_999) direct în aplicația mobilă. Când schimbi prețul sau încerci un A/B test, trebuie să scoți un update în App Store și să aștepți review.
RevenueCat rezolvă asta prin 3 concepte simple:
- Products: SKU-urile brute create în App Store Connect și Google Play Console.
- Entitlements: Ce primește userul în aplicație (ex:
pro_access). - Offerings: Grupul de pachete pe care le afișezi pe paywall în momentul curent.
În cod, aplicația ta întreabă doar: "Are userul curent entitlement-ul pro_access activ?". Nu te interesează dacă l-a cumpărat anulat, lunar sau pe viață.
Testing pe bune: iOS Sandbox vs Android License Testing
Aici se rupe filmul de obicei și pierzi nopți întregi.
Pe iOS, cel mai curat mod de lucru local este să folosești un fișier .storekit în Xcode. Îți permite să simulezi achiziții, erori de rețea, plăți eșuate sau reînnoiri de abonament direct în simulator, fără să creezi conturi de Sandbox Tester în App Store Connect.
Pe Android, în schimb, e un mic calvar. Trebuie să creezi o listă de License Testers în Google Play Console, să trimiți build-ul în track-ul de Internal Testing și să accepți invitația de pe un cont Google real de pe un dispozitiv fizic. Partea bună? Abonamentele de test pe Android expiră rapid (o lună din producție se comprimă în 5 minute în test), deci poți verifica rapid fluxul de expirare și grace period.
Trade-off-ul sincer
RevenueCat e moca până la $2.5k MTI (Monthly Tracked Income). Dup-aia te taxează cu $1 pentru fiecare $1,000 procesați. Sincer, la $10k MRR dai în jur de $8 pe lună – bani pe care îi recuperezi în primele 10 minute în care nu trebuie să scrii și să mentii un server propriu care să verifice webhook-urile de la Apple StoreKit 2 și Google Play Developer API.
Nu uita să pui un buton vizibil de "Restore Purchases" pe ecranul de paywall. Apple îți dă rejection garantat la app review dacă utilizatorul nu își poate restabili achizițiile anterioare.
Voi ce folosiți pentru monetizare în aplicațiile de Expo? Ați rămas pe react-native-iap sau ați migrat pe soluții gestionate gen RevenueCat ori Superwall?