FlutterDev
FlutterDev

Reputation: 11

Issue with In-App Purchase Discount Promo Code Process for iOS in Flutter App (purchase-stream listener is not firing 2nd time)

I am facing an issue while reviewing the In-App Purchase discount promo code process for iOS. It is working well on Android.

We have integrated the In-App Purchase mechanism in our Flutter app and now want to verify it on iOS. On iOS, we display the PromoCodeRedemptionSheet (provided by Apple’s In-App Purchase Kit framework) where the user can enter a promo code.

After entering the code and successfully applying it, once the redemption sheet is dismissed, we are not receiving the callback in the listener for the PurchaseUpdated event.

It worked fine the first time, but the issue occurs when we attempt to review the process again.

Note: To verify the promo code mechanism during debugging, we added a StoreKit file in Xcode and are using that StoreKit configuration to simulate the purchase process. When the redemption sheet opens, all the promo codes created in the Apple Developer Console are displayed, allowing the user to select one. The selected offer code is applied, and the user sees the sandbox payment sheet. After a successful payment, we see the "Thank You" screen with a "Close" button. However, after tapping the "Close" button and dismissing the redemption sheet, the callback is not received at the app level in the purchase stream.

class OfferCodeScreenForIosState extends State<OfferCodeScreenForIos> {
  final InAppPurchase _iap = InAppPurchase.instance;
  late StreamSubscription<List<PurchaseDetails>> _subscription;
  bool _isAvailable = false;
  List<ProductDetails> _products = [];
  bool _loading = true;

  @override
  void initState() {
    super.initState();
    printf("Offer_Code_ScreenFor_iOS > initState");

    // Set up a listener for purchases
    final purchaseUpdated = _iap.purchaseStream;

    _subscription = purchaseUpdated.listen((purchases) {
**//// THIS IS NOT WORKING WHEN PURCHASING THE DIFFERENT IN-APP SECOND TIME**
      printf("Offer_Code_ScreenFor_iOS > purchaseUpdated.listen");
      _handlePurchaseUpdates(purchases);
    }, onError: (error) {
      // Handle error
      printf("Purchase Error: $error");
    });

    // Initialize In-App Purchases
    _initializeStore();
  }

  Future<void> _initializeStore() async {
    // Check availability of the store
    _isAvailable = await _iap.isAvailable();
    if (_isAvailable) {
      const Set<String> ids = {
        '{{INAPP_PURCHASE_PRODUCT_ID}}',
      };
      final ProductDetailsResponse response =
          await _iap.queryProductDetails(ids);

      if (response.notFoundIDs.isNotEmpty) {
        printf("Not found IDs: ${response.notFoundIDs}");
      }

      setState(() {
        _products = response.productDetails;
        _loading = false;
      });
    }
  }

  Future<void> _redeemOfferCode() async {
    if (await SKPaymentQueueWrapper.canMakePayments()) {
      try {
        final iapStoreKitPlatformAddition =
            _iap.getPlatformAddition<InAppPurchaseStoreKitPlatformAddition>();

        await iapStoreKitPlatformAddition.presentCodeRedemptionSheet();
      } catch (e) {
        printf("Error presenting Offer Code Redemption Sheet: $e");
      }
    } else {
      printf("In-App Purchases are disabled on this device.");
    }
  }

  // Handle purchase updates
  void _handlePurchaseUpdates(List<PurchaseDetails> purchases) {
    for (var purchase in purchases) {
      if (purchase.status == PurchaseStatus.purchased) {
        printf("Purchase successful: ${purchase.productID}");
//// COMPLETING PURCHASE FOR TESTING BUT WE WILL NEED TO VERIFY SERVER VERIFICATION DATA HERE
        _iap.completePurchase(purchase);

      } else if (purchase.status == PurchaseStatus.pending) {
        printf(
            "Purchase status pending purchaseID: ${purchase.purchaseID}");
      } else if (purchase.status == PurchaseStatus.restored) {
        printf("Purchase Restored: ${purchase.purchaseID}");
      } else if (purchase.status == PurchaseStatus.canceled) {
        printf("Purchase Cancelled: ${purchase.purchaseID}");
      } else if (purchase.status == PurchaseStatus.error) {
        printf("Purchase error: ${purchase.error?.message}");
      }
    }
  }
}

Upvotes: 1

Views: 146

Answers (0)

Related Questions