react-native-iap icon indicating copy to clipboard operation
react-native-iap copied to clipboard

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

Open Robiullah2244 opened this issue 1 year ago • 8 comments

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:

  • react-native-iap: ^12.10.5
  • react-native: 0.70.10
  • Platforms (iOS): 16.3.1

Robiullah2244 avatar Sep 24 '23 13:09 Robiullah2244

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 avatar Sep 25 '23 14:09 bitfabrikken

@Robiullah2244 Have you tried this?

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

bitfabrikken avatar Sep 26 '23 08:09 bitfabrikken

@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.

Robiullah2244 avatar Sep 26 '23 13:09 Robiullah2244

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.

cervebar avatar Sep 28 '23 11:09 cervebar

@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 avatar Oct 03 '23 23:10 crrobinson14

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

crrobinson14 avatar Oct 03 '23 23:10 crrobinson14

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 😅

dabit3 avatar Oct 06 '23 15:10 dabit3

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'

cervebar avatar Nov 16 '23 14:11 cervebar