Keval Tank
Keval Tank

Reputation: 41

How to Upgrade/Downgrade subscription in Flutter using in_app_purchase package

For purchases, I am using the inapppurchase package. The package provides features for upgrading and downgrading packages. But I am unable to upgrade or downgrade the package. I am sharing details found on their package page.

enter image description here*
Currently, I am stuck fetching the PurchaseDetails object (oldPurchaseDetails). Has anyone used this feature of the in_app_purchase package?

I reviewed that package code and followed their shared code. But I didn't find a way to get the old purchase details.

Upvotes: 2

Views: 1781

Answers (4)

Here's a complete flow code for restoring old subscription and upgrade/downgrade subscriptions, on both Android & iOS.

In iOS, you don't need to write any code for upgrading/downgrading subscriptions, the underlying store (Appstore) handles it itself.

In Android, you need to pass changeSubscriptionParam inside GooglePlayPurchaseParam, this purchase param contains purchaseParams of current subscription.

Here's step by step guide to implement this.

 // this method should be called once inside subscription business logic class
 Future<void> init() async {
    final purchaseUpdated = _inAppPurchase.purchaseStream;
    _subscription = purchaseUpdated.listen(
      _listenToPurchaseUpdated,
      onDone: () {
        _subscription.cancel();
      },
      onError: (Object error) {
        log(error.toString());
      },
    );

    if (Platform.isIOS) {
      final iosPlatformAddition = _inAppPurchase
          .getPlatformAddition<InAppPurchaseStoreKitPlatformAddition>();
      await iosPlatformAddition.setDelegate(ExamplePaymentQueueDelegate());
    } else {
      await InAppPurchase.instance.restorePurchases();
    }
   }

Maintain a list to keep track of restored or purchased subscription.

final _purchases = <String, PurchaseDetails>{};

In _listenToPurchaseUpdated, store recent subscriptions inside a map.

if (purchaseDetails.status == PurchaseStatus.purchased ||
    purchaseDetails.status == PurchaseStatus.restored) {
    _purchases[purchaseDetails.productID] = purchaseDetails;
  }

Use _purchases to fetch old subscriptions.

GooglePlayPurchaseDetails? _getOldSubscription() {
    if (_purchases.isEmpty) return null;

    return _purchases.values.last as GooglePlayPurchaseDetails?;
  }

var purchaseParam = PurchaseParam(
      productDetails: subscriptionPlans[state.selectedIndex!].productDetail,
      applicationUserName: _sharedPreferencesManager.localUser!.id.toString(),
    );

    if (Platform.isAndroid) {
      // for subscription upgrade or downgrade in Android
      final oldSubscription = _getOldSubscription();

      purchaseParam = GooglePlayPurchaseParam(
        productDetails: subscriptionPlans[state.selectedIndex!].productDetail,
        changeSubscriptionParam: (oldSubscription != null)
            ? ChangeSubscriptionParam(
                oldPurchaseDetails: oldSubscription,
                replacementMode: ReplacementMode.withTimeProration,
              )
            : null,
        applicationUserName: _sharedPreferencesManager.localUser!.id.toString(),
      );
    }


      await _inAppPurchase.buyNonConsumable(
        purchaseParam: purchaseParam,
      );
    

Upvotes: 0

Devendra
Devendra

Reputation: 3444

To get old purchase details: (Source)

  1. Call the below method:

    _inAppPurchase.restorePurchases();
    
  2. Listen for restored purchase:

     final Stream<List<PurchaseDetails>> purchaseUpdated =
         _inAppPurchase.purchaseStream;
     _subscription = purchaseUpdated.listen((purchaseDetailsList) {
    
       // Get & Handle your old Purchase Detail from purchaseDetailsList
    
     }, onDone: () {
       _subscription.cancel();
     }, onError: (error) {
       // handle error here.
     });
    

Upvotes: 0

user3413723
user3413723

Reputation: 12263

the sample doesn't work if you're not testing it with recent stuff. If you stored the transaction token on the server, here you go:

import 'package:in_app_purchase_android/in_app_purchase_android.dart';
import 'package:in_app_purchase_android/billing_client_wrappers.dart';



final verificationData = PurchaseVerificationData(localVerificationData: token!, serverVerificationData: token!, source: token!);

// the only thing here that matters for this object is token!
final wrapper = PurchaseWrapper.fromJson({
    "orderId": "",
    "packageName": "",
    "purchaseTime": 0,
    "purchaseToken": token!,
    "signature": "",
    "products": [],
    "isAutoRenewing": false,
    "originalJson": "",
    "isAcknowledged": false,
    "purchaseState": 0
  });

final oldPurchaseDetails = GooglePlayPurchaseDetails(
  productID: currentPlan!, // <-- plan id for the old one
  verificationData: verificationData,
  transactionDate: DateTime.now().millisecondsSinceEpoch.toString(),
  billingClientPurchase: wrapper,
  status: PurchaseStatus.purchased,
);

Had to go dink with the source, but here it is so u can see if it changes in the future or something. Hope this helps!

https://github.com/flutter/plugins/blob/557d3284ac9dda32a1106bb75be8a23bdccd2f96/packages/in_app_purchase/in_app_purchase_android/lib/src/in_app_purchase_android_platform.dart#L134

Upvotes: 1

Kalp
Kalp

Reputation: 153

For getting the old purchase you need to send the previous purchased plan id only then you can get old purchase details here is code that may be help you

 GooglePlayPurchaseDetails? _getOldSubscription(
      ProductDetails productDetails, Map<String, PurchaseDetails> purchases) {
    // This is just to demonstrate a subscription upgrade or downgrade.
    // Please remember to replace the logic of finding the old subscription Id as per your app.
    // The old subscription is only required on Android since Apple handles this internally
    // by using the subscription group feature in iTunesConnect.

     var _kSubscriptionId =
        "<Product ID which you want to purchase>";

    var _kPastSubscriptionId = "<Old Product ID which you already purchased>";

    GooglePlayPurchaseDetails? oldSubscription;
    if (productDetails.id == _kSubscriptionId &&
        purchases[_kPastSubscriptionId] != null) {
      oldSubscription =
          purchases[_kPastSubscriptionId]! as GooglePlayPurchaseDetails;
    }
    return oldSubscription;
  }

This will return you the old plan detail.

Upvotes: 0

Related Questions