RevenueCat / purchases-flutter

Flutter plugin for in-app purchases and subscriptions. Supports iOS, macOS and Android.
https://www.revenuecat.com/
MIT License
608 stars 169 forks source link

Deferred Proration Mode Blocks Execution and Keeps Loader Spinning #1120

Open Louna-akkad1 opened 3 months ago

Louna-akkad1 commented 3 months ago

‼️ Required data ‼️

Do not remove any of the steps from the template below. If a step is not applicable to your issue, please leave that step empty.

There are a lot of things that can contribute to things not working. Having a very basic understanding of your environment will help us understand your issue faster!

Environment

Version of purchases-flutter: [6.30.0] flutter version 3.7.7

error

W/BillingLogger(30245): Unable to log. W/BillingLogger(30245): java.lang.NullPointerException W/BillingLogger(30245): at com.google.android.gms.internal.play_billing.zzbp.<init>(com.android.billingclient:billing@@6.2.1:4) W/BillingLogger(30245): at com.google.android.gms.internal.play_billing.zzdd.zzA(com.android.billingclient:billing@@6.2.1:4) W/BillingLogger(30245): at com.google.android.gms.internal.play_billing.zzdd.zzk(com.android.billingclient:billing@@6.2.1:2) W/BillingLogger(30245): at com.google.android.gms.internal.play_billing.zzgy.zzB(com.android.billingclient:billing@@6.2.1:1) W/BillingLogger(30245): at com.android.billingclient.api.zzcd.zzc(com.android.billingclient:billing@@6.2.1:1) W/BillingLogger(30245): at com.android.billingclient.api.zzj.onReceive(com.android.billingclient:billing@@6.2.1:12) W/BillingLogger(30245): at android.app.LoadedApk$ReceiverDispatcher$Args.lambda$getRunnable$0(LoadedApk.java:1911) W/BillingLogger(30245): at android.app.LoadedApk$ReceiverDispatcher$Args.$r8$lambda$gDuJqgxY6Zb-ifyeubKeivTLAwk(Unknown Source:0) W/BillingLogger(30245): at android.app.LoadedApk$ReceiverDispatcher$Args$$ExternalSyntheticLambda0.run(Unknown Source:2) W/BillingLogger(30245): at android.os.Handler.handleCallback(Handler.java:958) W/BillingLogger(30245): at android.os.Handler.dispatchMessage(Handler.java:99) W/BillingLogger(30245): at android.os.Looper.loopOnce(Looper.java:230) W/BillingLogger(30245): at android.os.Looper.loop(Looper.java:319) W/BillingLogger(30245): at android.app.ActivityThread.main(ActivityThread.java:8919) W/BillingLogger(30245): at java.lang.reflect.Method.invoke(Native Method) W/BillingLogger(30245): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578) W/BillingLogger(30245): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103) /[Purchases] - DEBUG(30245): ℹ️ BillingWrapper purchases updated: productIds: [family_yearly_special_subscription], orderId: GPA.3374-6462-8587-48002, purchaseToken: nonmibflhkojipgikaofmedb.AO-J1OyJ-Ng8PVAyho90pHq1tBU8ExJpa8PQHhM3KTWkFqxXjiJsVJcqdCVvjMfhIDg2m_ZQP6WVMBhxieMD3jV0mZ0o6N2SCQ D/[Purchases] - DEBUG(30245): ℹ️ Requesting products from the store with identifiers: family_yearly_special_subscription I/InsetsSourceConsumer(30245): applyRequestedVisibilityToControl: visible=true, type=statusBars, host=com.arabee.family/com.android.billingclient.api.ProxyBillingActivity

Describe the bug

Implement the following code to handle subscription downgrade in google play:


import 'package:flutter/material.dart';
import 'package:purchases_flutter/purchases_flutter.dart';

Future<void> purchaseSubscription(BuildContext context, Package package, String activeSubscriptionId) async {
  try {
    WidgetUtils.showLoading(context);

    // Sync attributes and offerings if needed
    Purchases.syncAttributesAndOfferingsIfNeeded();

    CustomerInfo customerInfo;

    if (activeSubscriptionId.isNotEmpty) {
      print("---------------------+++++++++++++ deferred---------------------+++++++++++++ ");

      customerInfo = await Purchases.purchasePackage(
        package,
        googleProductChangeInfo: GoogleProductChangeInfo(
          activeSubscriptionId,
          prorationMode: GoogleProrationMode.deferred,
        ),
      );

      print("---------------------+++++++++++++ after deferred---------------------+++++++++++++ ");
    } else {
      customerInfo = await Purchases.purchasePackage(package);
    }

    print('---------------------+++++++++++++ payment is done now ---------------------+++++++++++++ ');

    if (customerInfo.activeSubscriptions.isNotEmpty) {
      logPurchase(package.storeProduct.currencyCode, package.storeProduct.price);

      print('purchase-updated: `${package}`');
      await Future.delayed(Duration(seconds: 2));
      WidgetUtils.hideLoading(context);

      Navigator.of(context).pushNamed("/home");
    }
  } on PlatformException catch (e) {
    WidgetUtils.hideLoading(context);
    final errorCode = PurchasesErrorHelper.getErrorCode(e);

    String errorMessage = "An error occurred: ${e.message}";

    if (errorCode == PurchasesErrorCode.purchaseNotAllowedError) {
      errorMessage = 'User not allowed to purchase';
    } else if (errorCode == PurchasesErrorCode.paymentPendingError) {
      errorMessage = 'Payment is pending';
    } else if (errorCode == PurchasesErrorCode.productAlreadyPurchasedError) {
      errorMessage = 'User already subscribed';
    }

    if (errorCode != PurchasesErrorCode.purchaseCancelledError) {
      WidgetUtils.showMessage(context, "Purchase Error", errorMessage);
    }
  }
}

await Purchases.purchasePackage call does not resolve when GoogleProrationMode.deferred is used. Expected behavior: The await Purchases.purchasePackage call should resolve, allowing subsequent code to execute and the loader to be hidden.

Actual behavior: The await Purchases.purchasePackage call does not resolve, causing the loader to spin indefinitely.

Additional context

in backend im getting notification and the package is downgraded

RCGitBot commented 3 months ago

👀 We've just linked this issue to our internal tracker and notified the team. Thank you for reporting, we're checking this out!

Jethro87 commented 3 months ago

Thanks for posting this @Louna-akkad1. Does this error reproduce 100% of the time, or is it transient? Also, does this only occur in debug mode? Have you been able to test this in production?

Louna-akkad1 commented 3 months ago

@Jethro87 its reproduce 100% of the time with sandbox with Deferred Proration Mode only other modes work fine i have not test this in production

Jethro87 commented 3 months ago

@Louna-akkad1 Thanks. Our engineering team is digging into this - can you share more comprehensive debug logs? All logs from when you start your app to when you hit the error would be great.

ricardo-pixzelle commented 2 months ago

@Jethro87 any news on this issue? Play Store is going to force the billing on updates on the app and we can't use the new library yet

Jethro87 commented 2 months ago

@ricardo-pixzelle Our team can reproduce this error in the sandbox, but the SDK doesn't hang and the purchases go through. Are you seeing this in the sandbox, or also in production? Also, can you share full debug logs?

yuyangpl commented 2 months ago

’await Purchases.purchasePackage‘ Is suspended, causing subsequent code to fail to execute

therohansanap commented 1 month ago

@Jethro87 This happens on production as well as sandbox. You are correct that the purchase goes through but this particular future call never completes:

await Purchases.purchaseStoreProduct(
  product,
  googleProductChangeInfo: productChangeInfo,
);

It doesn't throw any error, neither does it completes successfully. Execution cannot move ahead as the future never completes.

Jethro87 commented 1 month ago

@therohansanap Thanks for reporting. Can you reply with full debug logs so our team can further dig into this?

ricardo-pixzelle commented 1 month ago

Hi @Jethro87 don't know if this helps, this are some logs on the Android app:

image

We are facing this issue when we use the deferred option on Android, in iOS we don't have that problem so the app just stays hanging with that exception

We were using this:

image

We tried this on the 6.30.0 version, but since this didn't worked we reversed to the 5.8 version, but know Play Store needs us to upgrade the billing SDK so we don't know which version to use