14

I'm trying to implement in-app purchases using the official Flutter In-App-Purchase plugin. I've got things working, except I can't figure out how to tell if a users subscription is still active or if it expired. Even after I canceled my test subscription, the values I get after connecting and doing queryPastPurchases() are the same as when the subscription was active:

productId: test_subscription_1   
transactiondate: 1565682346568   
status: null

verificationData
    source: IAPSource.GooglePlay   
    localVerificationData: {
        "orderId":"GPA.1234-1234-1234-12345",
        "packageName":"com.example.myapp",
        "productId":"test_subscription_1",
        "purchaseTime":1565682346568,
        "purchaseState":0,
        "purchaseToken":"<long string>",
        "autoRenewing":false
    }   
    serverVerificationData: "<long string>"

Am I supposed to simply hard code my subscription period and compare the current time to purchaseTime + the subscription period? Will that even work across auto-renewals? What if the user changes the date on his phone to a year ago? It seems like there should be some value that should either give me the expiration time or at least a boolean true/false to indicate if the subscription is still valid?

Magnus
  • 17,157
  • 19
  • 104
  • 189

3 Answers3

2

The official in-app purchase plugin handles making the purchase but doesn't supply all of the backend infrastructure you need to handle auto-renewing subscriptions specifically.

The short answer to your question is send this purchase info up to your server and manage subscription status there. Alternatively you can look into a managed solution like purchases_flutter: https://pub.dev/packages/purchases_flutter/

enc_life
  • 4,973
  • 1
  • 15
  • 27
  • 13
    Surely the use case "purchase subscription" -> "check if user has an active subscription" must be one of the most basic use cases for an IAP plugin? It doesn't make sense that the plugin would only handle making purchases, but not actually using them - then what's the point? It's like a car with an ignition lock but no wires attached. – Magnus Aug 13 '19 at 20:46
  • All of the IAP infrastructure was designed well before the app stores supported subscriptions. So that, combined with security issues of client-side code make some things that seem simple non-trivial. – enc_life Aug 14 '19 at 21:22
  • Ok, that explains a lot. Thanks a lot for the RevenueCat link by the way, I'm implementing it instead of the IAP plugin. I was skeptical at first but it turns out their API is way more easy to work with and their free plan seems very generous (just hope it stays that way). – Magnus Aug 15 '19 at 08:11
  • I am facing the same problem, but i found one method i think can solve this, please correct me if i am wrong, look at the code when checking the past purchases i used (purchase.billingClientPurchase.isAutoRenewing) to see if is renewing or not, and in a test subscription is true when is active and false when i cancel. So i guess it is enought to know if is charging user or not. What you think? – Jorge Vieira Jan 11 '20 at 12:13
  • 4
    There is something going on with revenue cat somehow people are always linking to them or have edited a post to use them – GILO Jul 29 '20 at 13:32
  • 1
    Somethings up there – GILO Jul 29 '20 at 13:32
  • @JorgeVieira I think that can be used only in android – Z. Cajurao Aug 19 '20 at 02:04
0

I have used ‘purchases_flutter‘ and the process is straightforward. You can check the status of the subscription by calling the methods which comes with the plugin. Check out this article which includes an example https://medium.com/flutter-community/in-app-purchases-with-flutter-a-comprehensive-step-by-step-tutorial-b96065d79a21

M4trix Dev
  • 1,828
  • 3
  • 23
  • 48
0

For anyone still having issues, there's a simple solution to validate the receipt on iOS

Here's a simple js snippet that you can use to fetch the actual receipt from Apple and use it to validate the subscription

Note You will need to generate app specific password for the app from with apple developer account

Further help

https://developer.apple.com/documentation/appstorereceipts/expiration_intent

const axios = require('axios');
const iosValidateReceipt = async (transactionReceipt, isTest = true) => 
    new Promise(async (resolve, reject) => {
        const url = isTest ? 'https://sandbox.itunes.apple.com/verifyReceipt' : 'https://buy.itunes.apple.com/verifyReceipt';
        const data = {
            'receipt-data': transactionReceipt,
            password: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
        };
        console.log('iosValidateReceipt - input - ', { url, data });
        try {
            const response = await axios.post(url, data);
            console.log('iosValidateReceipt - success - ', JSON.stringify(response.data, null, 2));
            resolve(response.data);
        } catch (err) {
            console.log('iosValidateReceipt - error -', err);
            reject(err);
        }
    });