4

I couldn't find any documentation on using RevenueCat bindings in Xamarin Forms, or any examples. How to get started? I think it's supposed to be obvious, but it wasn't for me.

Answering my own question below, I've made a small start, haven't tested any code yet. Please feel free to expand or correct.

This is for Xamarin Forms iOS on Visual Studio 2022 for Mac; MAUI could be similar.

BillF
  • 1,034
  • 3
  • 13
  • 28

2 Answers2

3

[Edit 23 Feb 2023: For a complete sample of RevenueCat code for iOS and Android, see instead my post at https://stackoverflow.com/questions/75541953/sample-code-for-revenuecat-in-app-functions-in-xamarin-forms-or-net-maui]

  1. In your iOS project, add the Nuget packages Xamarin.RevenueCat.iOS and Xamarin.RevenueCat.iOS.Extensions.

[Edit] I removed my suggestion to bind the Swift library, as it does not seem to be necessary.

A few sample code lines:

using RevenueCat;
using Xamarin.RevenueCat.iOS.Extensions;
....
RCPurchases.DebugLogsEnabled = true;
RCPurchases.ConfigureWithAPIKey( "my api key" );
RCPurchases.SharedPurchases.AllowSharingAppStoreAccount = true;
RCCustomerInfo purchaserInfo = await RCPurchases.SharedPurchases.RestoreTransactionsAsync ();
RCOfferings offerings = await RCPurchases.SharedPurchases.GetOfferingsAsync ();
BillF
  • 1,034
  • 3
  • 13
  • 28
  • Where do you put the code above? – Syl.H Sep 17 '22 at 17:06
  • @Syl.H Those are just random lines that would go in different places. I have got my app fairly much working now, and intend to post code here once it's tested. – BillF Sep 19 '22 at 03:43
  • @BillF, you mentioned that you would post more code later. Did you learn anything else using that Nuget package that you care to share? – user3352870 Dec 06 '22 at 15:10
  • @user3352870 - If you would like I can share iPhone code that seems to work, no guarantees as not fully tested yet - let me know your email. Now working on Android, I had to put that aside for while. Will post publicly once both are completely tested. – BillF Dec 07 '22 at 23:55
  • Hi Bill, any help you can give would be great and save me quite a bit of time. You can use this temporary email address for me: m38sgkbf -at- duck.com. Hopefully you can also post here when you are confident things are working. If I've learned anything in trying to integrate Apple and Google IAPs, it's very tricky. I wish they made testing easier, too. Thanks. – user3352870 Dec 10 '22 at 00:31
  • @user3352870 Will send my iOS and Android code, hopefully tomorrow. Caveats: Minor 'improvements' made to iOS code since I last tested it; Android coding now thought to be complete but not yet tested whatsoever. :) – BillF Dec 10 '22 at 03:36
  • @BillF Could you also send me your code please? I would really appreciate it! – B0r1 Feb 20 '23 at 13:19
  • 1
    @B0r1 Happy to, but give me a few days. Can you let me have an email? – BillF Feb 21 '23 at 23:28
  • @BillF Sure :) Here the mail: mail@hoodlify.com – B0r1 Feb 23 '23 at 03:41
  • I've now posted sample code for iOS and Android at https://stackoverflow.com/questions/75541953/sample-code-for-revenuecat-in-app-functions-in-xamarin-forms-or-net-maui – BillF Feb 23 '23 at 07:58
-1

For MAUI I have create a simple wrapper around iOS and Android bindings: https://github.com/Kebechet/Maui.RevenueCat.InAppBilling

you can inspire from the code or simply install it through nuget

Here is the simple example how to get offerings from RevenueCat for Android:

public class RevenueCatBilling
{
    private Purchases _purchases = default!;
    private static Activity? _currentActivityContext => Platform.CurrentActivity;

    public void Initialize(string apiKey)
    {
        if (_currentActivityContext is null)
        {
            throw new Exception("You must call this code in App.xaml->OnStart");
        }

        try
        {
            _purchases = Purchases.Configure(
                new PurchasesConfiguration(
                    new PurchasesConfiguration.Builder(
                        _currentActivityContext,
                        apiKey)
                )
            );

            _isInitialized = true;
        }
        catch
        {
            throw;
        }
    }
    public async Task<List<Offering>> LoadOfferings(CancellationToken cancellationToken)
    {
        try
        {
            using var offerings = await Purchases.SharedInstance.GetOfferingsAsync(cancellationToken);
            if (offerings is null)
            {
                return new();
            }

            using var currentOffering = offerings.Current;
            if (currentOffering is null)
            {
                return new();
            }

            return currentOffering.AvailablePackages.ToList();
        }
        catch
        {
            return new();
        }
    }
    public static Task<Offerings> GetOfferingsAsync(this Purchases purchases,
        CancellationToken cancellationToken = default)
    {
        var listener = new DelegatingReceiveOfferingsCallback(cancellationToken);
        purchases.GetOfferings(listener);
        return listener.Task;
    }
}

internal sealed class DelegatingReceiveOfferingsCallback : DelegatingListenerBase<Offerings>, IReceiveOfferingsCallback
{
    public DelegatingReceiveOfferingsCallback(CancellationToken cancellationToken) : base(cancellationToken)
    {
    }

    public void OnError(PurchasesError purchasesError)
    {
        ReportException(new PurchasesErrorException(purchasesError, false));
    }

    public void OnReceived(Offerings offerings)
    {
        ReportSuccess(offerings);
    }
}

internal abstract class DelegatingListenerBase<TResult> : Java.Lang.Object
{
    private readonly TaskCompletionSource<TResult> _taskCompletionSource;

    public DelegatingListenerBase(CancellationToken cancellationToken)
    {
        _taskCompletionSource = new TaskCompletionSource<TResult>();
        cancellationToken.Register(() => _taskCompletionSource.TrySetCanceled());
    }

    public Task<TResult> Task => _taskCompletionSource.Task;

    protected void ReportSuccess(TResult result)
    {
        _taskCompletionSource.TrySetResult(result);
    }

    protected void ReportException(Exception exception)
    {
        _taskCompletionSource.TrySetException(exception);
    }
}
Kebechet
  • 1,461
  • 15
  • 31
  • I have extracted some logic to get RevenueCat Offerings. But still, the package is mine and is used in app released in production, so the probability the link will stop work is really small. – Kebechet Aug 03 '23 at 10:43