import { useEffect, useState } from 'react';
import { Platform } from 'react-native';
import Purchases, { CustomerInfo } from 'react-native-purchases';
const API_KEYS = {
apple: 'appl_vXyZ123456789',
google: 'goog_aBcD987654321',
};
export function useRevenueCat(userId?: string) {
const [isPro, setIsPro] = useState<boolean>(false);
const [loading, setLoading] = useState<boolean>(true);
useEffect(() => {
const setup = async () => {
try {
if (__DEV__) {
await Purchases.setLogLevel(Purchases.LOG_LEVEL.DEBUG);
}
const apiKey = Platform.OS === 'ios' ? API_KEYS.apple : API_KEYS.google;
await Purchases.configure({ apiKey, appUserID: userId });
const info: CustomerInfo = await Purchases.getCustomerInfo();
setIsPro(typeof info.entitlements.active['pro_access'] !== 'undefined');
} catch (e) {
console.error('Failed to init RevenueCat', e);
} finally {
setLoading(false);
}
};
setup();
}, [userId]);
return { isPro, loading };
}Am trecut recent prin calvarul de a configura in-app purchases pentru o aplicație Expo Managed care a ajuns la 12k utilizatori activi. Dacă ai încercat vreodată să gestionezi singur validarea de receipt-uri pe Apple și Google, starea de grace period sau upgrade-urile de abonamente pe backend-ul tău, știi că e un mini-coșmar. Aici intervine RevenueCat, dar pe Expo există câteva capcane specifice de setup și testing de care trebuie să știi ca să nu-ți pierzi nopțile.
Setup-ul de Expo și capcana Expo Go
Primul lucru de care te lovești: uită complet de Expo Go. Când adaugi react-native-purchases, ești în tărâmul codului nativ. Ai nevoie de EAS Build și de un Development Build local sau generat pe cloud.
În app.json trebuie să adaugi plugin-ul lor dedicat:
{
"expo": {
"plugins": ["react-native-purchases"]
}
}
Partea bună e că plugin-ul se ocupă automat de permisiunile de Billing pe Android și de StoreKit pe iOS. Partea proastă e că dacă ești pe SDK 50+, trebuie să te asiguri că folosești o versiune v7.x+ de RevenueCat SDK. Am pierdut 4 ore la un build de iOS din cauza unei nepotriviri de Swift UI dependencies între o versiune mai veche de plugin și XCode 15.
Structura de Tier-uri: Products vs Entitlements
Una dintre cele mai mari greșeli pe care le văd este hardcodarea ID-urilor de produs din Apple/Google Direct în frontend. Nu face asta.
RevenueCat lucrează cu un strat de abstracție foarte deștept:
- Products: SKU-urile brute create în App Store Connect (
app_100_1m) și Google Play Console (app_monthly_sub). - Entitlements: Ce deblochează achiziția în aplicație (ex:
pro_access). - Offerings: Pachetul de abonamente pe care îl tragi dinamic în Paywall (ex:
default_offeringcare conține Lunar, Anual, Lifetime).
Când schimbi prețul sau creezi un alt SKU în Apple Store Connect, modifici doar maparea în dashboard-ul RevenueCat. Frontend-ul tău verifică un singur lucru boolean: customerInfo.entitlements.active['pro_access']. Am economisit cel puțin 15 ore de refactoring când marketing-ul a vrut să schimbe prețurile pe un A/B test direct din dashboard.
Bube la testing: StoreKit 2 și Google Sandbox
Testing-ul de IAP te va face să te îndoiești de deciziile tale în carieră.
Pe iOS, în loc să-ți faci 10 conturi de Sandbox Apple ID (care cer verificare prin SMS sau se blochează din senin), folosește un fișier local .storekit în XCode dacă testezi pe simulator. Dacă testezi prin TestFlight, reține că un abonament lunar de test expiră automat după 5 minute și se reînnoiește de maxim 6 ori.
Pe Android, adaugă adresa ta de email în Play Console la License Testing. Însă atenție: aplicația TREBUIE urcată cel puțin o dată într-un track de Internal Testing și aprobată. Dacă uiți să apeși pe Publish în Internal Track, Google Play Billing API îți va da o eroare generică de tip BillingResponse.ERROR fără alte detalii.
Trade-off-ul e simplu: RevenueCat e gratuit până la $2.5k MTR (Monthly Tracked Revenue). După asta plătești $1 pentru fiecare $1,000 procesați. Pentru echipa noastră a fost no-brainer — costul lor e o fracțiune din ce ne-ar fi costat timpul de dev pentru mentenanța propriilor webhook-uri.
Voi ce folosiți pe Expo pentru abonamente: RevenueCat, Adapty sau backend custom cu webhook-uri direct din store-uri?