import { useEffect, useState } from 'react';
import { Platform } from 'react-native';
import Purchases, { CustomerInfo, PurchasesOffering } from 'react-native-purchases';
const API_KEYS = {
apple: 'appl_xxxxxxxxxxxxxxxxx',
google: 'goog_xxxxxxxxxxxxxxxxx',
};
export const useRevenueCat = () => {
const [currentOffering, setCurrentOffering] = useState<PurchasesOffering | null>(null);
const [isPro, setIsPro] = useState<boolean>(false);
useEffect(() => {
const init = async () => {
Purchases.setLogLevel(Purchases.LOG_LEVEL.DEBUG);
if (Platform.OS === 'ios') {
await Purchases.configure({ apiKey: API_KEYS.apple });
} else if (Platform.OS === 'android') {
await Purchases.configure({ apiKey: API_KEYS.google });
}
const offerings = await Purchases.getOfferings();
if (offerings.current !== null) {
setCurrentOffering(offerings.current);
}
const customerInfo = await Purchases.getCustomerInfo();
setIsPro(typeof customerInfo.entitlements.active['pro'] !== 'undefined');
};
init().catch(console.error);
}, []);
return { currentOffering, isPro };
};Am integrat IAP-uri native în React Native acum 4 ani și mi-a mâncat vreo 3 săptămâni doar validarea de chitanțe pe backend și tratarea edge case-urilor când pierdea userul conexiunea. Anul trecut, la o aplicație de fitness construită pe Expo cu 14k useri activi, am zis că nu mai fac aceeași greșeală. Am mers pe RevenueCat.
Rezultatul? Am fost gata în o zi și jumătate, iar rata de eroarea la procesarea abonamentelor a scăzut sub 0.1%. Daca folosești Expo Managed Workflow și EAS, procesul e surprinzător de curat, dar trebuie să respecți ordinea pașilor.
Mental Model: Products vs Entitlements vs Offerings
Prima dată când deschizi consola RevenueCat e ușor să te încurci în terminologie. Gândește-te așa:
- Products: SKU-urile exacte din App Store Connect și Google Play Console (ex:
app_999_1m). - Entitlements: Ce primește userul în aplicație (ex: acces
prosauunlimited_downloads). - Offerings: Grupurile de produse pe care le afișezi în paywall (ex: offering-ul
defaultcare conține un SKU lunar și unul anual).
Abordarea asta îți permite să schimbi prețurile sau structura de abonament direct din dashboard fără să mai treci prin App Store Review și fără update de aplicație.
Configurare în Expo și EAS Build
Instalezi SDK-ul oficial react-native-purchases. Pentru că folosește cod nativ, nu va merge în Expo Go. Trebuie să folosești un Development Build prin EAS (eas build --profile development).
În app.json nu ai nevoie de plugin-uri exotice, dar e crucial să configurezi corect schemele de URL și permisiunile, în special pentru Android unde trebuie trecuta permisiunea com.android.vending.BILLING automat de către pachet.
Bube la testing în Sandbox (ce nu scrie clar în docuri)
La iOS testing, creezi un Sandbox Tester în App Store Connect. Sfatul meu: folosește adrese de email cu alias (email+test1@gmail.com). Când testezi pe un device fizic, nu te loga din Setările generale ale telefonului cu contul de sandbox! Loghează-te doar în Settings -> App Store -> Sandbox Account.
Pe Android e un pic mai dureros. Trebuie să uploadezi cel puțin un AAB într-un track de Internal Testing pe Google Play Console, altfel API-ul de Billing va returna o eroare generică de tip Billing Unavailable. Adaugă-ți emailul în lista de testers și acceptă invitația din browserul telefonului.
Trade-off-uri sincere
E lapte și miere până când ajungi la volum. RevenueCat e gratuit până la $2,500 MTR (Managed Revenue). După pragul ăsta, îți iau $1 pentru fiecare $1,000 procesați. La o aplicație cu $20k MRR, plătești cam $17.5/lună, ceea ce mi se pare un no-brainer comparativ cu salariul unui dev care să-ți mențină backend-ul de sincronizare a chitanțelor StoreKit 2 și Google Billing API v6.
Nasol e dacă vrei să ieși din ecosistemul lor mai târziu. Ai lock-in destul de mare pe starea istoricului de cumpărături, deși poți exporta datele prin webhooks și integrări de S3/BigQuery.
Voi ce folosiți pentru monetizare în Expo? Mergeți pe integrări custom cu server-side validation sau dați cota la RevenueCat / Adapty?