flutterin-app-purchase

How can I check the status of a subscription using in_app_purchase in Flutter for Android?


I would like to know how I can check if a user has an active subscription. In this case, I have created a 1 month subscription and everything is working correctly. However, in what way can I determine if a user's subscription is still active or not? I am using the in_app_purchase library, and I noticed that the way to access past purchases was updated. In my code, I modified the line final PurchaserInfo purchaserInfo = await InAppPurchase.instance.queryPastPurchases(); updating InAppPurchaseConnection.instance to InAppPurchase.instance. Despite this fix, I still get an error because "PurchaserInfo" is not defined. Also, I'm not sure if I'm implementing this the right way, as this is my first time working with subscriptions in Flutter. I appreciate in advance any guidance or help. thanks! :)

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:shared_preferences/shared_preferences.dart';




class SubscriptionStatusChecker extends StatefulWidget {
  @override
  _SubscriptionStatusCheckerState createState() =>
      _SubscriptionStatusCheckerState();
}

class _SubscriptionStatusCheckerState extends State<SubscriptionStatusChecker> {
  bool _isSubscriptionActive = false;

  @override
  void initState() {
    super.initState();
    _checkSubscriptionStatus();
  }

  Future<void> _checkSubscriptionStatus() async {
    try {
      final PurchaserInfo purchaserInfo = await InAppPurchase.instance
          .queryPastPurchases(); 

      final List<PurchaseDetails> purchases =
          purchaserInfo.purchases.toList();

      for (var purchase in purchases) {
        if (purchase.productID == 's2424' &&
            purchase.status == PurchaseStatus.purchased) {
          setState(() {
            _isSubscriptionActive = true;
          });
          break;
        }
      }
    } catch (e) {
      Fluttertoast.showToast(
        msg: 'Error: $e',
        gravity: ToastGravity.BOTTOM,
        timeInSecForIosWeb: 1,
        backgroundColor: Colors.red,
        textColor: Colors.white,
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Subscription Status Checker'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Estado de la suscripciĆ³n:',
              style: TextStyle(fontSize: 18),
            ),
            Text(
              _isSubscriptionActive ? 'Activa' : 'Inactiva',
              style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
    );
  }
}




class UpdatePlan extends StatefulWidget {
  @override
  _UpdatePlanScreenState createState() => _UpdatePlanScreenState();
}

class _UpdatePlanScreenState extends State<UpdatePlan> {
  final InAppPurchase _inAppPurchase = InAppPurchase.instance;
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;

  static const String _productId = 's2424'

  final StreamController<List<PurchaseDetails>> _purchaseUpdatedController =
      StreamController<List<PurchaseDetails>>.broadcast();

  Stream<List<PurchaseDetails>> get purchaseUpdatedStream =>
      _purchaseUpdatedController.stream;

  late StreamSubscription<List<PurchaseDetails>> _subscription;

  bool _isPlanPremiumActive = false;

  bool get isPlanPremiumActive => _isPlanPremiumActive;

  String? _username;

  @override
  void initState() {
    super.initState();
    _loadUsername();
    initialize();
  }

  void _loadUsername() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      _username = prefs.getString('username');
    });
  }

  void initialize() async {
    final bool available = await _inAppPurchase.isAvailable();
    if (!available) {
      // The store is not available. Update the UI accordingly.
      return;
    }

    await _inAppPurchase.restorePurchases();

    _subscription = _inAppPurchase.purchaseStream.listen((purchaseDetailsList) {
      _handlePurchases(purchaseDetailsList);
    }, onDone: () {
      _subscription.cancel();
    }, onError: (error) {
      // Handle errors here.
    });
  }

  void _handlePurchases(List<PurchaseDetails> purchaseDetailsList) {
    for (var purchaseDetails in purchaseDetailsList) {
      if (purchaseDetails.status == PurchaseStatus.purchased) {
        if (purchaseDetails.productID == _productId) {
          _grantPlanPremium();
          _updateFirebaseSubscription(purchaseDetails);
        }
      } else if (purchaseDetails.status == PurchaseStatus.error) {
        Fluttertoast.showToast(
          msg: 'Error al realizar la compra: ${purchaseDetails.error}',
          gravity: ToastGravity.BOTTOM,
          timeInSecForIosWeb: 1,
          backgroundColor: Colors.red,
          textColor: Colors.white,
        );
      }
    }
    _purchaseUpdatedController.add(purchaseDetailsList);
  }

  void _grantPlanPremium() {
    setState(() {
      _isPlanPremiumActive = true;
    });
  }

  Future<void> purchaseProduct() async {
    try {
      final PurchaseParam purchaseParam =
          PurchaseParam(productDetails: await _getProductDetails());
      await _inAppPurchase.buyNonConsumable(purchaseParam: purchaseParam);
    } catch (error) {
      Fluttertoast.showToast(
        msg: 'Error al iniciar la compra: $error',
        gravity: ToastGravity.BOTTOM,
        timeInSecForIosWeb: 1,
        backgroundColor: Colors.red,
        textColor: Colors.white,
      );
    }
  }

  Future<ProductDetails> _getProductDetails() async {
    final Set<String> ids = <String>{_productId};
    final ProductDetailsResponse response =
        await _inAppPurchase.queryProductDetails(ids);
    return response.productDetails.first;
  }

 void _updateFirebaseSubscription(PurchaseDetails purchaseDetails) {
    if (_username != null) {
      
      _firestore.collection('users').doc(_username).update({
        'subscription': true,
      });
    }
  }

  @override
  void dispose() {
    _subscription.cancel();
    _purchaseUpdatedController.close();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Test'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'Premium Plan: ${_isPlanPremiumActive ? 'Active' : 'Inactive'}',
              style: TextStyle(fontSize: 18),
            ),
            ElevatedButton(
              onPressed: () => purchaseProduct(),
              child: Text('Update VIP'),
            ),
            ElevatedButton(
              onPressed: () => SubscriptionStatusChecker(),
              child: Text('Status'),
            ),
          ],
        ),
      ),
    );
  }
}

I saw this thread, but, it has no response: How to check if a user have a active subscription using in_app_purchase My expectation is to be able to determine whether the user has an active subscription or not.


Solution

  • You can do it through restore purchase like this:

    printIfSubscribed() {
        final Stream<List<PurchaseDetails>> purchaseUpdated =
            _inAppPurchase.purchaseStream;
        _subscription =
            purchaseUpdated.listen((purchaseDetailsList) {}, onDone: () {
          _subscription.cancel();
        }, onError: (error) {
          // handle error here.
        });
        _subscription.onData((data) {
          if (data.isNotEmpty) {
            print(data[0].status);
          }
        });
      }