Kebechet / Maui.RevenueCat.InAppBilling

MIT License
12 stars 6 forks source link

Issue with Maui.RevenueCat.InAppBilling: Unable to Retrieve Offerings Using Valid API Key #46

Open tecomunico opened 1 week ago

tecomunico commented 1 week ago

Description:

Hello, I'm experiencing issues integrating Maui.RevenueCat.InAppBilling into my .NET MAUI application. My goal is to retrieve subscription offerings and validate an annual subscription, but I am unable to establish a connection or retrieve the offerings even though my API key is correctly set up.

Environment Details:

Steps to Reproduce the Issue:

  1. Installed the Maui.RevenueCat.InAppBilling package in my .NET MAUI application and configured the API key provided by RevenueCat.
  2. Configured the RevenueCat service in MauiProgram.cs as follows: builder.Services.AddRevenueCatBilling();
  3. Added code to initialize RevenueCat and retrieve offerings on my subscription page.
  4. Attempted to execute the following code in the OnSubscribeClicked event to load the offerings and attempt a purchase:

Code

private async void OnSubscribeClicked(object sender, EventArgs e)
{
    try
    {
        var offerings = await _revenueCatBilling.GetOfferings();
        var annualPackage = offerings.SelectMany(o => o.AvailablePackages).FirstOrDefault(p => p.Identifier == DefaultPackageIdentifier.Annually);

        if (offerings == null || !offerings.Any())
        {
            await DisplayAlert("Connection Error", "Unable to retrieve offerings. It might be a network or configuration issue.", "OK");
            return;
        }

        var purchaseResult = await _revenueCatBilling.PurchaseProduct(annualPackage);

        if (purchaseResult.CustomerInfo.Entitlements.Any(e => e.Identifier == "entld11020e0ae"))
        {
            await DisplayAlert("Success", "Subscription successfully activated!", "OK");
        }
        else
        {
            await DisplayAlert("Error", "Subscription activation failed.", "OK");
        }
    }
    catch (Exception ex)
    {
        await DisplayAlert("Error", $"An error occurred: {ex.Message}", "OK");
    }
}

Expected Behavior:

I expected RevenueCat to connect successfully and retrieve available offerings, specifically for the annual subscription. Additionally, I expected that I could make a purchase and activate the subscription.

Actual Behavior:

The application fails to retrieve offerings. The code stops at the line checking if (offerings == null || !offerings.Any()), showing an error message stating that offerings could not be retrieved due to a potential network or configuration issue.

What I Have Tried:

  1. Confirmed that the API key is correctly configured and verified its validity in the RevenueCat dashboard.
  2. Tested the implementation on different physical devices and emulators to rule out device-specific issues.

Additional Context or Potential Issue:

This may be a problem with the configuration or a specific issue with the Maui.RevenueCat.InAppBilling package and its compatibility with .NET MAUI. It would be helpful to know if there are any additional steps needed or any known issues with this setup.

Here's a detailed issue template for reporting your problem on GitHub:

Issue Title:

Issue with Maui.RevenueCat.InAppBilling: Unable to Retrieve Offerings Using Valid API Key

Description:

Hello, I'm experiencing issues integrating Maui.RevenueCat.InAppBilling into my .NET MAUI application. My goal is to retrieve subscription offerings and validate an annual subscription, but I am unable to establish a connection or retrieve the offerings even though my API key is correctly set up.

Environment Details:

Package Version: [Specify the exact version of Maui.RevenueCat.InAppBilling in use] .NET MAUI Version: [Specify the version of .NET MAUI] Visual Studio Version: [Specify the version of Visual Studio, and indicate if it’s on Mac or Windows] Test Devices: [List the OS and version of the physical devices or emulators you've tested on]

Steps to Reproduce the Issue:

Installed the Maui.RevenueCat.InAppBilling package in my .NET MAUI application and configured the API key provided by RevenueCat.

Configured the RevenueCat service in MauiProgram.cs as follows:

builder.Services.AddRevenueCatBilling();

Added code to initialize RevenueCat and retrieve offerings on my subscription page.

Attempted to execute the following code in the OnSubscribeClicked event to load the offerings and attempt a purchase:

    private async void OnSubscribeClicked(object sender, EventArgs e)
    {
        try
        {
            var offerings = await _revenueCatBilling.GetOfferings();
            var annualPackage = offerings.SelectMany(o => o.AvailablePackages).FirstOrDefault(p => p.Identifier == DefaultPackageIdentifier.Annually);

            if (offerings == null || !offerings.Any())
            {
                await DisplayAlert("Connection Error", "Unable to retrieve offerings. It might be a network or configuration issue.", "OK");
                return;
            }

            var purchaseResult = await _revenueCatBilling.PurchaseProduct(annualPackage);

            if (purchaseResult.CustomerInfo.Entitlements.Any(e => e.Identifier == "entld11020e0ae"))
            {
                await DisplayAlert("Success", "Subscription successfully activated!", "OK");
            }
            else
            {
                await DisplayAlert("Error", "Subscription activation failed.", "OK");
            }
        }
        catch (Exception ex)
        {
            await DisplayAlert("Error", $"An error occurred: {ex.Message}", "OK");
        }
    }

Tested this code on both iOS and Android devices.

Expected Behavior:

I expected RevenueCat to connect successfully and retrieve available offerings, specifically for the annual subscription. Additionally, I expected that I could make a purchase and activate the subscription.

Actual Behavior:

The application fails to retrieve offerings. The code stops at the line checking if (offerings == null || !offerings.Any()), showing an error message stating that offerings could not be retrieved due to a potential network or configuration issue.

What I Have Tried:

Confirmed that the API key is correctly configured and verified its validity in the RevenueCat dashboard. Tested the implementation on different physical devices and emulators to rule out device-specific issues.

Additional Context or Potential Issue:

This may be a problem with the configuration or a specific issue with the Maui.RevenueCat.InAppBilling package and its compatibility with .NET MAUI. It would be helpful to know if there are any additional steps needed or any known issues with this setup.

Additional Code

XAML SubscriptionPage

using Maui.RevenueCat.InAppBilling;
using Maui.RevenueCat.InAppBilling.Models;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Maui.Controls;
using Maui.RevenueCat.InAppBilling.Services;

namespace JabezTime.Views
{
    public partial class SubscriptionPage : ContentPage
    {
        private readonly IRevenueCatBilling _revenueCatBilling;

        public SubscriptionPage()
        {
            InitializeComponent();
            _revenueCatBilling = (IRevenueCatBilling)App.Current.Handler.MauiContext.Services.GetService(typeof(IRevenueCatBilling));
        }

        private async void OnSubscribeClicked(object sender, EventArgs e)
        {
            try
            {
                // Intenta obtener las ofertas disponibles
                var offerings = await _revenueCatBilling.GetOfferings();

                // Si no hay ofertas, muestra un mensaje
                if (offerings == null || !offerings.Any())
                {
                    await DisplayAlert("Connection Error", "Unable to retrieve offerings. It might be a network or configuration issue.", "OK");
                    return;
                }

                // Obtén el paquete anual
                var annualPackage = offerings.SelectMany(o => o.AvailablePackages).FirstOrDefault(p => p.Identifier == DefaultPackageIdentifier.Annually);

                if (annualPackage == null)
                {
                    await DisplayAlert("Error", "Annual subscription not found.", "OK");
                    return;
                }

                // Realiza la compra
                var purchaseResult = await _revenueCatBilling.PurchaseProduct(annualPackage);

                // Verifica si la suscripción está activa usando el ID de Entitlement
                if (purchaseResult.CustomerInfo.Entitlements.Any(e => e.Identifier == "entld11020e0ae"))
                {
                    await DisplayAlert("Success", "Subscription successfully activated!", "OK");
                }
                else
                {
                    await DisplayAlert("Error", "Subscription activation failed.", "OK");
                }
            }
            catch (Exception ex)
            {
                // Muestra detalles del error general
                await DisplayAlert("Error", $"An error occurred: {ex.Message}", "OK");
            }
        }
    }
}

App.cs

using System.Diagnostics;
using System.Globalization;
using System.IO;
using JabezTime.Data;
using JabezTime.Services;
using JabezTime.Views;
using Microsoft.Data.Sqlite;
using Plugin.LocalNotification;
using Plugin.LocalNotification.EventArgs;
using Maui.RevenueCat.InAppBilling.Services;

namespace JabezTime;

public partial class App : Application
{
    public static AppDbContext DbContext { get; private set; }
    public static string DbPath { get; private set; }
    private readonly IRevenueCatBilling _revenueCat;

    public App(IRevenueCatBilling revenueCat)
    {
        InitializeComponent();
        _revenueCat = revenueCat;

        // Configuración de Syncfusion
        Syncfusion.Licensing.SyncfusionLicenseProvider.RegisterLicense("Ngo9BigBOggjHTQxAR8/V1NDaF5cWWtCf1FpRmJGdld5fUVHYVZUTXxaS00DNHVRdkdnWH9ec3VXRWlYUkJ+Wko=");

        LocalNotificationCenter.Current.NotificationActionTapped += OnLocalNotificationActionTapped;

        // Generar el DeviceID la primera vez que se abre la aplicación
        EnsureDeviceId();

        // Establecer el idioma inicial basado en las preferencias guardadas
        string selectedLanguage = Preferences.Get("SelectedLanguage", "en");
        LanguageManager.SetLanguage(selectedLanguage);

        // Configurar la base de datos
        DbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "jabeztime.db");
        Console.WriteLine($"Database Path: {DbPath}");

        // Inicializar el contexto de la base de datos sin argumentos
        DbContext = new AppDbContext();
        DbContext.EnsureDatabaseCreated();

        if (!CheckDatabaseIntegrity())
        {
            Application.Current.MainPage.DisplayAlert("Error", "The database is corrupted. The app will close.", "OK").ContinueWith(_ =>
            {
                Process.GetCurrentProcess().Kill();
            });
        }

        bool isLoggedIn = CheckIfUserIsLoggedIn();

        MainPage = new NavigationPage(isLoggedIn ? new AppShell() : new OnboardingPage())
        {
            BarBackgroundColor = Color.FromArgb("#EC407A"),
            BarTextColor = Colors.White
        };

    }

    protected override void OnStart()
    {
        // Revenue
        var revenueCatApiKey = string.Empty;
        #if __ANDROID__
            revenueCatApiKey = "<AndroidRevenueCatKeyHere>";
        #elif __IOS__
            revenueCatApiKey = "appl_xxxxxxxxxx";
        #endif
        _revenueCat.Initialize(revenueCatApiKey);

        base.OnStart();

        LocalNotificationCenter.Current.RequestNotificationPermission();
        ScheduleNotificationsFromSettings();

        // Redirigir a la página de suscripción si el trial ha caducado
        if (!TrialManager.IsTrialValid() && !TrialManager.IsSubscribed())
        {
            MainPage = new NavigationPage(new SubscriptionPage());
        }
    }

    private bool CheckDatabaseIntegrity()
    {
        try
        {
            DbContext.OpenConnection();
            DbContext.CloseConnection();
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Database error: {ex.Message}");
            return false;
        }
    }

    private bool CheckIfUserIsLoggedIn()
    {
        return Preferences.Get("IsLoggedIn", false);
    }

    public static void SetLoggedIn(bool isLoggedIn)
    {
        Preferences.Set("IsLoggedIn", isLoggedIn);
    }

    public static void SetRememberMeChecked(bool isRememberMeChecked)
    {
        Preferences.Set("IsRememberMeChecked", isRememberMeChecked);
    }

    private void EnsureDeviceId()
    {
        if (!Preferences.ContainsKey("DeviceID"))
        {
            string deviceId = Guid.NewGuid().ToString();
            Preferences.Set("DeviceID", deviceId);
        }
    }

    protected override void OnResume()
    {
        base.OnResume();
        LocalNotificationCenter.Current.NotificationActionTapped += OnLocalNotificationActionTapped;
        ScheduleNotificationsFromSettings();
    }

    private void ScheduleNotificationsFromSettings()
    {
        var notificationSettingsPage = new NotificationSettingsPage();
        notificationSettingsPage.ScheduleNotifications();
    }

    private void OnLocalNotificationActionTapped(NotificationActionEventArgs e)
    {
        if (e != null)
        {
            MainThread.BeginInvokeOnMainThread(async () =>
            {
                await Application.Current.MainPage.DisplayAlert("Notification", $"{e.Request.Title}", "OK");
            });
        }
    }
}

MauiProgram.cs

using Maui.RevenueCat.InAppBilling;
using Microsoft.Extensions.Logging;
using Mopups.Hosting;
using Syncfusion.Maui.Core.Hosting;

namespace JabezTime;

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .UseMauiMaps()
            .ConfigureSyncfusionCore()
            .ConfigureFonts(fonts =>
            {
                fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
                fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");

                // Agregar FontAwesome
                fonts.AddFont("fa-brands-400.ttf", "FontAwesomeBrands");
                fonts.AddFont("fa-regular-400.ttf", "FontAwesomeRegular");
                fonts.AddFont("fa-solid-900.ttf", "FontAwesomeSolid");
            })
            .ConfigureMopups();
#if DEBUG
        builder.Logging.AddDebug();
#endif
        builder.Services.AddRevenueCatBilling();
        return builder.Build();
    }
}

Thank you for your help in identifying a solution for this issue!

Kebechet commented 1 week ago

Hello, thank you for the report in following days I will take a look. Till then please adjust code you provided in correct code-blocks (right now it is overflowing) so it is more readable

tecomunico commented 1 week ago

Thanks

Kebechet commented 1 week ago

I am looking at your code and I cant see there anything obviously wrong.

1) Try in SubscriptionPage get IRevenueCatBilling with the use of dependency injection 2) In our repo there is a demo app. Try to download it and use your revenueCatApiKey here. After that check if offerings contain your items. If it wont work you dont have RevenueCat properly setup or Apple didnt approve your subscriptions yet

Kebechet commented 1 day ago

@tecomunico were you able to resolve this problem ?