Search code examples
flutterin-app-purchasegoogle-play-services

Google IAP get subscription details and store in DB


I have an app that receives subscriptions from the user. I have implemented methods to receive payments and I can complete the transaction. When storing all the details in my database I can able to get details such as purchase id, purchase date and validity (returned P1Y for a 1-year subscription) but I also want to get the subscription end date is it possible? and how do I check if the user cancels the subscription or renews the subscription?


Solution

  • Revenue Cat:

    Instead of using in_app_purchase I started using purchases_flutter (RevenueCat)

    You can refer to their documentation for more information.

    I currently use this method for in-app subscriptions.

    Google Api:

    I also managed to use google API to get the subscription details with the help of googleapis and googleapis_auth

    IAP Helper class

    Follow this documentation to complete the initial setup

    Google API Credentials initialisation

      final _credentials = ServiceAccountCredentials.fromJson(r'''
            {
              "private_key_id": "keyid",
              "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADAN<private key>Sf\nbB9OjCOGt7ybJmDkMBe2U5Tq\n-----END PRIVATE KEY-----\n",
              "client_email": "mail",
              "client_id": "clientid",
              "type": "service_account"
            }
            ''');
      static const _scopes = [AndroidPublisherApi.androidpublisherScope];
    

    Function to get Subscription details

     Future getSubData({@required String token , @required String productId})async{
        SubscriptionPurchase res;
        final httpClient = await clientViaServiceAccount(_credentials, _scopes);
        try {
          final pubApi = AndroidPublisherApi(httpClient);
          res = await pubApi.purchases.subscriptions.get('com.yourcompany.package', productId, token);
        } finally {
          httpClient.close();
        }
        return res;
      }
    

    Delivering the product

    _deliverProduct({@required PurchaseDetails purchaseDetails})async{
         await iap.completePurchase(purchaseDetails);
         final firestore.DocumentReference userDocReference = firebase.doc("Users/$_id/userdata/data");
         final firestore.CollectionReference historyDocReference = firebase.collection("Users/$_id/history/");
         final SubscriptionPurchase  apiRes = await getSubData(token:purchaseDetails.billingClientPurchase.purchaseToken,productId:purchaseDetails.productID);
         var data = {
           "TXN ID": purchaseDetails.billingClientPurchase.purchaseToken,
           "Order ID":purchaseDetails.billingClientPurchase.orderId,
           "Product ID":purchaseDetails.productID,
           "TXN Date": firestore.Timestamp.fromMillisecondsSinceEpoch(int.parse(purchaseDetails.transactionDate)),
           "Subscribed":true,
           "Start Date":firestore.Timestamp.fromMillisecondsSinceEpoch(int.parse(apiRes.startTimeMillis)),
           "Expiry Date": firestore.Timestamp.fromMillisecondsSinceEpoch(int.parse(apiRes.expiryTimeMillis)),
           "Payment Status": apiRes.paymentState,
           "isFreeTrail": (apiRes.paymentState==1)?false:true,
           "acknowledgementState":apiRes.acknowledgementState
         };
        await userDocReference.set({"Subscription":data,"Sub_Raw":apiRes.toJson()},firestore.SetOptions(merge: true)); //set to main user
        await historyDocReference.doc('${purchaseDetails.billingClientPurchase.purchaseToken}').set(data); //put in purchase history
      }
    

    Now you can check if the user is subscribed or not from your firstore BD

    This method may provide temporary FIX (Google PlayStore only) but I do not recommend this method as it contains a lot of security issues.

    Note: Google only provides 200K API call's per day avoid calling API to check for subscription repeatedly.

    Note: Google API method only works with in_app_purchase: ^0.5.2

    Note: Google API method only works for Android and doesn't work for IOS.

    Other Alternates

    You can write your own server-side code in node.js/cloud firestore and you can achieve the same.

    Ref : Cook book in_app_purchase

    Disclaimer

    I do not receive any incentive/payment from revenuecat for mentioning their product in this answer.