dooboolab-community / react-native-iap

In App Purchase module for React Native!
https://react-native-iap.dooboolab.com
MIT License
2.78k stars 634 forks source link

getAvailablePurchases returns also expired purchases on iOS. So, how can I get a user's current active subscription in iOS? #2551

Open Robiullah2244 opened 11 months ago

Robiullah2244 commented 11 months ago

Please use the Discussion board if you want to get some help. Please use issues to report bugs.

Description

getAvailablePurchases returns also expired purchases on iOS. So, how can I get a user's current active subscription in iOS?

Expected Behavior

Like Android, getAvailablePurchases must return only the active purchases.

Environment:

bitfabrikken commented 11 months ago

Sadly it's always been quite cumbersome on iOS.

Easiest way is to send off a receipt to your server, then have it ask Apple if it's expired or not. Today you would use the App Store Server API, and the endpoint /v1/transactions/{transactionId} The old API is deprecated.

You could also validate it in-app, by decrypting the receipt, but that's not exactly easy. At least I have no clue how to do it: https://developer.apple.com/documentation/appstorereceipts/validating_receipts_on_the_device

But now that Storekit2 is implemented in react-native-iap, you can look at transaction.expirationDate via transactionListener and do a simple epoch comparison. And maybe for good measure validate it on your server too.

Also maybe see https://react-native-iap.dooboolab.com/docs/guides/receipts if you haven't.

Writing all this hoping someone can prove me wrong. Would kill for something easy like Android's purchaseState.

bitfabrikken commented 11 months ago

@Robiullah2244 Have you tried this?

purchases = await RNIap.getAvailablePurchases({
    onlyIncludeActiveItems: true,
})
Robiullah2244 commented 11 months ago

@Robiullah2244 Have you tried this?

purchases = await RNIap.getAvailablePurchases({
    onlyIncludeActiveItems: true,
})

Hi @bitfabrikken, Thanks and yes, I already tried it. Also, the parameter is by default true. No luck.

cervebar commented 11 months ago

This code really works but only with StoreKit 2. If you are using Storekit 1 ... you are well ... we can call it unlucky ( ͡° ʖ̯ ͡° ).

const activeSubscription = await getAvailablePurchases({onlyIncludeActiveItems: true})

To get it work you have to configure at start that you want to use it only with Storekit 2:

setup({storekitMode: 'STOREKIT2_MODE'})

and declare your app supports only iOS 15+ in your project.pbxproj -> IPHONEOS_DEPLOYMENT_TARGET = 15.0; .

Don't support Storekit 1 (iOS <15) and your life will be much much easier.

If your app is already in your production -> The major task is also to convince your product team. Tip how to do that is: if you are using Firebase Analytics -> list how many of your users are using old iOS, I can expect it will be minority, iOS users are generally good at keeping their phone up-to-date.

crrobinson14 commented 10 months ago

@cervebar This doesn't appear to be an option yet in the SDK? Is there a pending release this flag will be included in?

image

crrobinson14 commented 10 months ago

Please disregard. This is an option in the bae SDK getAvailablePurchases()method but NOT in the one returned by the useIAP() hook.

dabit3 commented 10 months ago

I don't know if this is the best approach, but I'm fetching the purchase history, sorting by date, then trying to verify the most recent subscription id on the server

I also don't know the difference between purchaseHistory and availablePurchases so if anyone has any details please share 😅

cervebar commented 9 months ago

getAvailablePurchases

we don't use the hook version (from useIap.ts), because it doesn't pass this parameter, but call directly (from file iap.ts)

import {
  getAvailablePurchases
} from 'react-native-iap'