I am using RevenueCat's Flutter SDK to manage user subscriptions in my app. For associating user content in my database, I rely on the initial anonymous user ID generated by RevenueCat since i do not want to have to setup user accounts.
There is an issue though when a user deletes the app and reinstalls it, or installs the app on a new device and restores their purchase, RevenueCat generates a new Alias instead of using the original anonymous id. This is a problem because there is a maximum limit of 50 aliases.
Is there a way to make it so when the user restores a purchase it uses the original Anonymous App User ID instead of creating a new one? Here is the relevant portion of my code:
class SubscriptionProvider with ChangeNotifier {
bool _hasActiveSubscription = false;
String _activeEntitlement = '';
String _anonymousId = 'unpaidUser'; // Default to 'unpaidUser'
bool get hasActiveSubscription => _hasActiveSubscription;
String get activeEntitlement => _activeEntitlement;
String get anonymousId => _anonymousId;
Future<void> initialize() async {
print("Starting RevenueCat configuration...");
await configureRevenueCat();
print("RevenueCat configuration completed.");
print("Checking subscription status...");
await checkSubscriptionStatus();
print("Subscription status checked.");
}
Future<void> configureRevenueCat() async {
print('Configuring RevenueCat...');
try {
Purchases.setLogLevel(LogLevel.debug); // Use LogLevel.debug only during development
if (Platform.isIOS || Platform.isMacOS) {
var config = PurchasesConfiguration("");
await Purchases.configure(config);
} else if (Platform.isAndroid) {
var config = PurchasesConfiguration("");
await Purchases.configure(config);
}
// Fetch CustomerInfo after configuring the SDK
CustomerInfo purchaserInfo = await Purchases.getCustomerInfo();
String userId = purchaserInfo.originalAppUserId;
// Log in to RevenueCat with the originalAppUserId
await Purchases.logIn(userId);
print('RevenueCat configured and logged in successfully.');
} catch (e) {
print('Error configuring RevenueCat: $e');
// Optionally handle the error, e.g., retry or fallback
}
}
Future<void> checkSubscriptionStatus() async {
print('Checking subscription status...');
try {
CustomerInfo purchaserInfo = await Purchases.getCustomerInfo();
print('PurchaserInfo fetched: $purchaserInfo');
updateSubscriptionStatus(purchaserInfo);
} catch (e) {
print('Error fetching PurchaserInfo: $e');
loadSubscriptionStatusFromSharedPreferences(); // Fallback to SharedPreferences if online check fails
}
}
void updateSubscriptionStatus(CustomerInfo purchaserInfo) {
print('Updating subscription status...');
// Directly set the anonymous ID from the purchaserInfo
_anonymousId = purchaserInfo.originalAppUserId;
print('Anonymous ID set to: $_anonymousId');
_hasActiveSubscription = purchaserInfo.entitlements.active.isNotEmpty;
_activeEntitlement = purchaserInfo.entitlements.active.values
.map((e) => e.identifier)
.join(', ');
print('Active subscription status: $_hasActiveSubscription');
print('Active entitlements: $_activeEntitlement');
notifyListeners(); // Notify listeners about all changes
saveSubscriptionStatusToSharedPreferences();
}
Future<bool> restorePurchases() async {
print('Attempting to restore purchases...');
try {
CustomerInfo restoredCustomerInfo = await Purchases.restorePurchases();
print('Purchases restored. Info: $restoredCustomerInfo');
updateSubscriptionStatus(restoredCustomerInfo);
return true;
} catch (e) {
print('Failed to restore purchases: $e');
return false;
}
}
}