Maui.RevenueCat.InAppBilling
No description available
Install / Use
/learn @Kebechet/Maui.RevenueCat.InAppBillingREADME
Maui.RevenueCat.InAppBilling
A .NET MAUI wrapper library for RevenueCat in-app purchases. Provides a unified C# API that abstracts away the need for you to use platform-specific code from Android and iOS native bindings.
Features
- Unified API for iOS and Android in-app purchases
- Subscription and one-time purchase support
- User authentication (anonymous and identified users)
- Subscription status and entitlement checking
- Trial/intro discount eligibility
- Subscriber attributes management
- Stub implementations for Windows and MacCatalyst (for development convenience)
Installation
dotnet add package Kebechet.Maui.RevenueCat.InAppBilling
Quick Start
1. Register the service
In your MauiProgram.cs:
builder.Services.AddRevenueCatBilling();
2. Inject and initialize
In App.xaml.cs, inject IRevenueCatBilling and initialize in OnStart():
public partial class App : Application
{
private readonly IRevenueCatBilling _revenueCat;
public App(IRevenueCatBilling revenueCat)
{
InitializeComponent();
_revenueCat = revenueCat;
}
protected override void OnStart()
{
var revenueCatApiKey = string.Empty;
#if __ANDROID__
revenueCatApiKey = "<your-android-api-key>";
#elif __IOS__
revenueCatApiKey = "<your-ios-api-key>";
#endif
_revenueCat.Initialize(revenueCatApiKey);
base.OnStart();
}
}
Important: Initialize must be called in
OnStart(), not in the constructor.
API Reference
Initialization & State
| Method | Description |
|--------|-------------|
| Initialize(string apiKey) | Initialize RevenueCat with your platform-specific API key |
| IsInitialized() | Check if the SDK has been initialized |
| IsAnonymous() | Check if current user is anonymous |
| GetAppUserId() | Get the current user ID |
Offerings & Products
| Method | Description |
|--------|-------------|
| GetOfferings(bool forceRefresh = false) | Fetch available offerings and packages |
| CheckTrialOrIntroDiscountEligibility(List<string> identifiers) | Check eligibility for trials/intro pricing |
Purchases
| Method | Description |
|--------|-------------|
| PurchaseProduct(PackageDto package) | Initiate a purchase flow |
| GetActiveSubscriptions() | Get list of active subscription identifiers |
| GetAllPurchasedIdentifiers() | Get all purchased product identifiers |
| GetPurchaseDateForProductIdentifier(string productSku) | Get purchase date for a specific product |
| RestoreTransactions() | Restore previous purchases |
User Management
| Method | Description |
|--------|-------------|
| Login(string appUserId) | Log in an identified user |
| Logout() | Log out and create anonymous user |
| GetCustomerInfo() | Get current customer info and entitlements |
| GetManagementSubscriptionUrl() | Get URL for subscription management |
Subscriber Attributes
| Method | Description |
|--------|-------------|
| SetEmail(string email) | Set user's email |
| SetDisplayName(string name) | Set user's display name |
| SetPhoneNumber(string phone) | Set user's phone number |
| SetAttributes(IDictionary<string, string> attributes) | Set custom attributes |
Example: Complete Purchase Flow
public class PurchaseService
{
private readonly IRevenueCatBilling _revenueCat;
public PurchaseService(IRevenueCatBilling revenueCat)
{
_revenueCat = revenueCat;
}
public async Task<bool> PurchaseSubscription()
{
var offerings = await _revenueCat.GetOfferings();
if (offerings.Count == 0)
return false;
var defaultOffering = offerings.FirstOrDefault(o => o.IsCurrent);
var monthlyPackage = defaultOffering?.AvailablePackages
.FirstOrDefault(p => p.Identifier == "monthly");
if (monthlyPackage == null)
return false;
var result = await _revenueCat.PurchaseProduct(monthlyPackage);
if (result.IsSuccess)
{
// Purchase successful
return true;
}
if (result.ErrorStatus == PurchaseErrorStatus.PurchaseCancelledError)
{
// User cancelled - not an error
return false;
}
// Handle other errors
Console.WriteLine($"Purchase failed: {result.ErrorStatus}");
return false;
}
public async Task<bool> HasActiveSubscription(string entitlementId)
{
var customerInfo = await _revenueCat.GetCustomerInfo();
return customerInfo?.ActiveSubscriptions
.Any(e => e == entitlementId) ?? false;
}
}
Platform Support
| Platform | Support | |----------|---------| | Android | Full implementation | | iOS | Full implementation | | Windows | Stub (returns defaults) | | MacCatalyst | Stub (returns defaults) |
Stub implementations return:
truefor boolean methods- Empty collections for list methods
string.Emptyfor string methodsnullfor nullable types
This allows you to build and test on Windows/Mac without platform conditionals.
Error Handling
The library follows a non-throwing approach for runtime errors:
- Exceptions are thrown only for developer mistakes (e.g., calling methods before
Initialize()) - Runtime errors (network issues, store problems, etc.) return:
ErrorStatusin result DTOs (e.g.,PurchaseResultDto.ErrorStatus)- Empty collections for list returns
nullfor nullable types
This design ensures your app never crashes due to store-related issues.
Common Error Codes
| Error | Description |
|-------|-------------|
| PurchaseCancelledError | User cancelled the purchase |
| StoreProblemError | Issue with the app store |
| NetworkError | Network connectivity issue |
| ProductAlreadyPurchasedError | Product was already purchased |
| PaymentPendingError | Payment is pending (e.g., awaiting approval) |
See PurchaseErrorStatus for the complete list.
Credits
- Native bindings for Android and iOS inspired by thisisthekap's Xamarin bindings
- Abstraction layer based on RevenueCatXamarin by BillFulton
Contributing
Feel free to create an issue or pull request. For major changes, please open an issue first to discuss your proposal - large PRs without prior discussion may be rejected.
License
This project is licensed under the MIT License.
Related Skills
node-connect
351.4kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
110.7kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
351.4kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
qqbot-media
351.4kQQBot 富媒体收发能力。使用 <qqmedia> 标签,系统根据文件扩展名自动识别类型(图片/语音/视频/文件)。

