How can I check if the user is still subscribed and how can I get my subscription expiration date in order to show it to the user?

Viewed 144

Soo, below is my implementation of Flutter In-app purchases on both ios and android.

For this, I've used flutter_inapp_purchase 5.1.2 package.

The main problem is when I try to get an active subscription on ios. What I mean is that I have no clue how to check exactly whether the user is still subscribed or not. I tested my app 2 months ago and getAvailablePurcheses provides me with a purchase that has purchaseDate set to 2 months ago.

How can I check if the user is still subscribed and how can I get my subscription expiration date in order to show it to the user?

Please help, I hope this class will be useful to other users later.

import 'dart:async';
import 'package:estimator_ar/models/user.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';

import 'dart:io' show Platform;

class PaymentService {

  /// We want singelton object of ``PaymentService`` so create private constructor
  PaymentService._internal();
  static final PaymentService instance = PaymentService._internal();
  StreamSubscription<ConnectionResult> _connectionSubscription;
  StreamSubscription<PurchasedItem> _purchaseUpdatedSubscription;

  /// To listen the errors of the purchase
  StreamSubscription<PurchaseResult> _purchaseErrorSubscription;
  final String _productId = 'estimator_tier_1';
  IAPItem _product;
  ObserverList<Function> _subscriptionStatusChangedListeners = new ObserverList<Function>();
  ObserverList<Function(String)> _errorListeners =new ObserverList<Function(String)>();

  /// Call this method at the startup of you app to initialize connection
  /// with billing server and get all the necessary data
  Future<void> initConnection() async {
    await FlutterInappPurchase.instance.initialize();
    _connectionSubscription = FlutterInappPurchase.connectionUpdated.listen((connected) {});
    _purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen(_handlePurchaseUpdate);
    _purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen(_handlePurchaseError);
    _getItem();
  }

  /// call when user close the app
  void dispose() {
    _connectionSubscription.cancel();
    _purchaseErrorSubscription.cancel();
    _purchaseUpdatedSubscription.cancel();
    FlutterInappPurchase.instance.finalize();
  }

  void _handlePurchaseError(PurchaseResult purchaseError) {
    this._callErrorListeners(purchaseError.message);
  }

  /// Called when new updates arrives at ``purchaseUpdated`` stream
  void _handlePurchaseUpdate(PurchasedItem productItem) async {
    if (Platform.isAndroid) {
      await _handlePurchaseUpdateAndroid(productItem);
    } else {
      await _handlePurchaseUpdateIOS(productItem);
    }
  }

  Future<void> _handlePurchaseUpdateIOS(PurchasedItem purchasedItem) async {
    switch (purchasedItem.transactionStateIOS) {
      case TransactionState.deferred:
        break;
      case TransactionState.failed:
        print("Transaction failed");
        FlutterInappPurchase.instance.finishTransaction(purchasedItem);
        break;
      case TransactionState.purchased:
        print("Transaction finished");
        await _verifyAndFinishTransaction(purchasedItem);
        break;
      case TransactionState.purchasing:
        break;
      case TransactionState.restored:
        FlutterInappPurchase.instance.finishTransaction(purchasedItem);
        break;
      default:
    }
  }

  Future<void> _handlePurchaseUpdateAndroid(PurchasedItem purchasedItem) async {
    switch (purchasedItem.purchaseStateAndroid) {
      case PurchaseState.purchased:
        if (!purchasedItem.isAcknowledgedAndroid) {
          await _verifyAndFinishTransaction(purchasedItem);
        }
        break;
      default:
        print("Something went wrong");
    }
  }

  _verifyAndFinishTransaction(PurchasedItem purchasedItem) async {
    if(loggedUser!=null)
      loggedUser.updateSubscriptionStatus(true);
    FlutterInappPurchase.instance.finishTransaction(purchasedItem);
    _callSubscriptionStatusChangedListeners();
  }

  Future<IAPItem> get product async {
    if (_product == null)
      await _getItem();
    return _product;
  }

  Future<void> _getItem() async {
    List<IAPItem> items = await FlutterInappPurchase.instance.getSubscriptions([_productId]);
    _product = null;
    if(items.length>0)
      this._product = items[0];
  }

  Future<Null> buyProduct(IAPItem item) async {
    try {
      await FlutterInappPurchase.instance.requestPurchase(item.productId);
    } catch (error) {
    }
  }

  Future<bool> checkActiveSubscription() async{
    try{
      var _purchase = await this.getActiveSubscription();
      print(_purchase.transactionDate);
      return _purchase!=null;
    }catch(e){
      print(e.toString());
    }
    if(loggedUser!=null)
      loggedUser.updateSubscriptionStatus(false);
    return false;
  }

  Future<PurchasedItem> getActiveSubscription() async{

    if (Platform.isIOS) {
      var history = await FlutterInappPurchase.instance.getPurchaseHistory();

      for (var purchase in history)
        if([TransactionState.purchased, TransactionState.restored].contains(purchase.transactionStateIOS))
          return purchase;
      return null;
    } else if (Platform.isAndroid) {
      var purchases = await FlutterInappPurchase.instance.getAvailablePurchases();

      for (var purchase in purchases) {
        if (purchase.productId == _product.productId) return purchase;
      }
      return null;
    }
    throw PlatformException(code: Platform.operatingSystem, message: "platform not supported");
  }

  /// Call this method to notify all the subsctibers of _proStatusChangedListeners
  void _callSubscriptionStatusChangedListeners() {
    _subscriptionStatusChangedListeners.forEach((Function callback) {
      callback();
    });
  }

  /// Call this method to notify all the subsctibers of _errorListeners
  void _callErrorListeners(String error) {
    _errorListeners.forEach((Function callback) {
      callback(error);
    });
  }

  /// view can subscribe to _proStatusChangedListeners using this method
  addToSubscriptionStatusChangedListeners(Function callback) {
    _subscriptionStatusChangedListeners.add(callback);
  }
  /// view can cancel to _proStatusChangedListeners using this method
  removeFromSubscriptionStatusChangedListeners(Function callback) {
    _subscriptionStatusChangedListeners.remove(callback);
  }

  /// view can subscribe to _errorListeners using this method
  addToErrorListeners(Function callback) {
    _errorListeners.add(callback);
  }
  /// view can cancel to _errorListeners using this method
  removeFromErrorListeners(Function callback) {
    _errorListeners.remove(callback);
  }
}
0 Answers
Related