Hướng dẫn tích hợp RevenueCat cho Flutter (iOS & Android)
1. Chuẩn bị
1.1 Tạo tài khoản RevenueCat
- Truy cập RevenueCat Dashboard
- Đăng ký tài khoản miễn phí
- Tạo project mới cho ứng dụng của bạn
1.2 Cấu hình App Store Connect (iOS)
- Đăng nhập vào App Store Connect
- Tạo app mới hoặc chọn app hiện có
- Vào phần Features → In-App Purchases
- Tạo các sản phẩm in-app purchase (Auto-Renewable Subscriptions hoặc Non-Consumable)
- Lưu lại Product ID của từng sản phẩm
1.3 Cấu hình Google Play Console (Android)
- Đăng nhập vào Google Play Console
- Chọn app của bạn
- Vào Monetize → Products → In-app products hoặc Subscriptions
- Tạo các sản phẩm tương ứng với iOS
- Lưu lại Product ID
2. Cài đặt và cấu hình RevenueCat
2.1 Thêm dependency
Thêm vào pubspec.yaml:
dependencies:
purchases_flutter: ^6.20.0
Chạy lệnh:
flutter pub get
2.2 Cấu hình iOS
2.2.1 Capabilities (Xcode)
- Mở project iOS trong Xcode
- Chọn target app
- Vào tab Signing & Capabilities
- Thêm In-App Purchase capability
2.2.2 Cấu hình StoreKit (iOS 15+)
Tạo file Products.storekit trong Xcode:
- File → New → File → StoreKit Configuration File
- Thêm các sản phẩm với Product ID tương ứng
2.3 Cấu hình Android
2.3.1 Permissions
Thêm vào android/app/src/main/AndroidManifest.xml:
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.INTERNET" />
2.3.2 ProGuard (nếu sử dụng)
Thêm vào android/app/proguard-rules.pro:
-keep class com.revenuecat.purchases.** { *; }
3. Cấu hình RevenueCat Dashboard
3.1 Tạo App trong RevenueCat
- Trong RevenueCat Dashboard, chọn Apps
- Thêm app mới cho iOS và Android
- Điền Bundle ID (iOS) và Package Name (Android)
3.2 Cấu hình Products
- Vào Products trong dashboard
- Thêm các sản phẩm với Product ID từ App Store và Google Play
- Đảm bảo Product ID khớp chính xác
3.3 Tạo Offerings
- Vào Offerings
- Tạo offering mới (ví dụ: “premium_subscription”)
- Thêm các packages với sản phẩm đã tạo
3.4 Lấy API Keys
- Vào API keys
- Copy Public API key cho iOS và Android
- Lưu lại để sử dụng trong code
4. Triển khai code Flutter
4.1 Khởi tạo RevenueCat
import 'package:purchases_flutter/purchases_flutter.dart';
class RevenueCatService {
static const String _apiKeyIOS = 'YOUR_IOS_API_KEY';
static const String _apiKeyAndroid = 'YOUR_ANDROID_API_KEY';
static Future<void> initialize() async {
await Purchases.setLogLevel(LogLevel.debug);
PurchasesConfiguration configuration;
if (Platform.isIOS) {
configuration = PurchasesConfiguration(_apiKeyIOS);
} else if (Platform.isAndroid) {
configuration = PurchasesConfiguration(_apiKeyAndroid);
} else {
throw UnsupportedError('Platform not supported');
}
await Purchases.configure(configuration);
}
}
4.2 Gọi khởi tạo trong main.dart
void main() async {
WidgetsFlutterBinding.ensureInitialized();
try {
await RevenueCatService.initialize();
} catch (e) {
print('RevenueCat initialization failed: $e');
}
runApp(MyApp());
}
4.3 Lấy danh sách sản phẩm
class PurchaseService {
static Future<Offerings?> getOfferings() async {
try {
final offerings = await Purchases.getOfferings();
return offerings;
} catch (e) {
print('Error getting offerings: $e');
return null;
}
}
static Future<List<StoreProduct>> getProducts() async {
try {
final offerings = await getOfferings();
if (offerings?.current != null) {
return offerings!.current!.availablePackages
.map((package) => package.storeProduct)
.toList();
}
return [];
} catch (e) {
print('Error getting products: $e');
return [];
}
}
}
4.4 Thực hiện mua hàng
class PurchaseService {
static Future<CustomerInfo?> purchasePackage(Package package) async {
try {
final customerInfo = await Purchases.purchasePackage(package);
return customerInfo;
} on PlatformException catch (e) {
final errorCode = PurchasesErrorHelper.getErrorCode(e);
if (errorCode == PurchasesErrorCode.purchaseCancelledError) {
print('User cancelled purchase');
} else if (errorCode == PurchasesErrorCode.paymentPendingError) {
print('Payment pending');
} else {
print('Purchase error: ${e.message}');
}
return null;
}
}
static Future<CustomerInfo?> restorePurchases() async {
try {
final customerInfo = await Purchases.restorePurchases();
return customerInfo;
} catch (e) {
print('Error restoring purchases: $e');
return null;
}
}
}
4.5 Kiểm tra trạng thái subscription
class PurchaseService {
static Future<bool> isPremiumUser() async {
try {
final customerInfo = await Purchases.getCustomerInfo();
return customerInfo.entitlements.active.isNotEmpty;
} catch (e) {
print('Error checking premium status: $e');
return false;
}
}
static Future<CustomerInfo?> getCustomerInfo() async {
try {
return await Purchases.getCustomerInfo();
} catch (e) {
print('Error getting customer info: $e');
return null;
}
}
}
4.6 Widget hiển thị sản phẩm
class PurchaseScreen extends StatefulWidget {
@override
_PurchaseScreenState createState() => _PurchaseScreenState();
}
class _PurchaseScreenState extends State<PurchaseScreen> {
List<Package> _packages = [];
bool _isLoading = true;
@override
void initState() {
super.initState();
_loadOfferings();
}
Future<void> _loadOfferings() async {
try {
final offerings = await PurchaseService.getOfferings();
if (offerings?.current != null) {
setState(() {
_packages = offerings!.current!.availablePackages;
_isLoading = false;
});
}
} catch (e) {
setState(() {
_isLoading = false;
});
}
}
Future<void> _purchasePackage(Package package) async {
final customerInfo = await PurchaseService.purchasePackage(package);
if (customerInfo != null) {
// Mua hàng thành công
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Purchase successful!')),
);
}
}
@override
Widget build(BuildContext context) {
if (_isLoading) {
return Scaffold(
appBar: AppBar(title: Text('Premium Plans')),
body: Center(child: CircularProgressIndicator()),
);
}
return Scaffold(
appBar: AppBar(title: Text('Premium Plans')),
body: ListView.builder(
itemCount: _packages.length,
itemBuilder: (context, index) {
final package = _packages[index];
final product = package.storeProduct;
return Card(
margin: EdgeInsets.all(8),
child: ListTile(
title: Text(product.title),
subtitle: Text(product.description),
trailing: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
product.priceString,
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
ElevatedButton(
onPressed: () => _purchasePackage(package),
child: Text('Buy'),
),
],
),
),
);
},
),
);
}
}
5. Test và Debug
5.1 Test trên iOS
- Sử dụng TestFlight hoặc iOS Simulator
- Test với sandbox account
- Kiểm tra StoreKit testing trong Xcode
5.2 Test trên Android
- Sử dụng internal testing track trên Google Play Console
- Test với test account
- Kiểm tra Google Play Billing Library
5.3 Debug thường gặp
- Kiểm tra API keys đúng platform
- Đảm bảo Product IDs khớp chính xác
- Kiểm tra bundle ID/package name
- Xem logs trong RevenueCat Dashboard
6. Production Checklist
6.1 Trước khi release
- [ ] Test tất cả luồng mua hàng
- [ ] Test restore purchases
- [ ] Kiểm tra receipts trong RevenueCat Dashboard
- [ ] Test trên nhiều thiết bị
- [ ] Đổi log level thành
LogLevel.infohoặcLogLevel.error
6.2 Monitoring
- Theo dõi RevenueCat Dashboard để xem analytics
- Kiểm tra revenue và conversion rates
- Monitor customer support tickets
7. Tính năng nâng cao
7.1 User Identification
// Liên kết user với RevenueCat
await Purchases.logIn('user_id');
// Đăng xuất
await Purchases.logOut();
7.2 Promo Codes (iOS)
// Hiển thị sheet promo code
await Purchases.presentCodeRedemptionSheet();
7.3 Webhooks
Cấu hình webhooks trong RevenueCat Dashboard để nhận notifications về các sự kiện purchase.
Với hướng dẫn này, bạn có thể tích hợp hoàn chỉnh RevenueCat vào Flutter app của mình để hỗ trợ in-app purchases trên cả iOS và Android.

