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

[iOS] `getAvailablePurchases` and `getPurchaseHistory` don't return any response #2089

Closed dmitryusikriseapps closed 1 year ago

dmitryusikriseapps commented 1 year ago

Description

Hey guys. Unfortunately, last week the subscriptions stopped working on iOS in production mode. We used the 8.0.8 version and didn't publish any updates. I assume it might be related to the latest iOS update. Then, I updated the library to the latest version and called InAppPurchases.setup({ storekitMode: 'STOREKIT1_MODE' }). Subscriptions are working well when I build the application locally and test them with a sandbox user. On the other hand, when I deploy the application to the TestFlight, they stopped working, and both getAvailablePurchases and getPurchaseHistory don't return any response, they are just executed without any response for infinite. I also checked the documentation, and how to migrate to the latest versions and I noticed that the library supports STOREKIT2_MODE now. It is required to implement it for the latest versions of the library, or it's possible to go ahead with STOREKIT1_MODE for now? I also noticed that the library doesn't prompt me to sign in when there aren't any sandbox users on the device like it was before.

Will be really thankful, if you can help us to resolve the issue. We've temporarily opened the application for all the users, but we will lose all the revenue, so we have to resolve the issue as soon as possible.

Expected Behavior

Both getAvailablePurchases and getPurchaseHistory should return the response after some time.

Environment:

To Reproduce Steps to reproduce the behavior:

1) Upload a test build to TestFlight. 2) Init the connection. 3) Try to call getAvailablePurchases or getPurchaseHistory. 4) There won't be any response.

Additional Context

const getCurrentSubscriptions = async () => {
    let currentSubscriptions = []
    Platform.OS === 'android' && (await InAppPurchases.flushFailedPurchasesCachedAsPendingAndroid())
    const availablePurchases = await InAppPurchases.getAvailablePurchases()

    debugLog(
        'Available purchases length:: ',
      availablePurchases.map((purchase) => purchase.productId),
    )

    if (availablePurchases.length < 1) return currentSubscriptions

    const lastPurchase = availablePurchases[0]

    if (Platform.OS === 'ios') {
        const validateResult = await validateReceiptIos(lastPurchase.transactionReceipt)
        if (validateResult?.status === 0 && validateResult?.latest_receipt_info?.length > 0) {
            const lastSubscription = validateResult.latest_receipt_info.sort(
                (a, b) => Number.parseInt(b.expires_date_ms) - Number.parseInt(a.expires_date_ms),
            )[0]

            const validated = validateResult.latest_receipt_info
                .map(({ expires_date_ms }) => expires_date_ms)
                .filter((expires_date_ms) =>
                    moment(Number.parseInt(expires_date_ms)).isSame(moment(), 'day'),
                )
                .map((expires_date_ms) =>
                    moment(Number.parseInt(expires_date_ms)).format('HH:mm:ss'),
                )

            debugLog('Validated:: ', validated)

            if (moment(Number.parseInt(lastSubscription.expires_date_ms)).isAfter(moment())) {
                currentSubscriptions.push(lastSubscription.product_id)
            }
        }
    } else if (Platform.OS === 'android') {
        if (lastPurchase && lastPurchase.productId === annualSubscription) {
            currentSubscriptions.push(lastPurchase.productId)
        } else if (lastPurchase && lastPurchase.productId === monthlySubscription) {
            currentSubscriptions.push(lastPurchase.productId)
        }
    }

    debugLog('Current subscriptions:: ', currentSubscriptions)

    return currentSubscriptions
}
andresesfm commented 1 year ago

@dmitryusikriseapps I'm assuming you are calling initConnection before, correct?

dmitryusikriseapps commented 1 year ago

@dmitryusikriseapps I'm assuming you are calling initConnection before, correct?

Hey @andresesfm, that's correct.

andresesfm commented 1 year ago

And are you using hooks?

andresesfm commented 1 year ago

This is my proposed solution: https://github.com/dooboolab/react-native-iap/pull/2091

andresesfm commented 1 year ago

This has been released in 12.4.0

dmitryusikriseapps commented 1 year ago

@andresesfm Thanks for the fix. It solves the issue on some devices, but it still not working as expected on the rest of the devices.

It works well on iPad Pro as well as on MacBook (Mac Catalyst). But it doesn't work on the iPhone 14 Pro (ios 16.0.3) or iPhone 14 Pro Max.

I also noticed that the library changes the sandbox account to the default one, for example: 1) Go to settings 2) Sign in to the newly created sandbox account 3) Go to the app, and try to use the library (for example getAvailablePurchases) 4) Back to settings, and check the sandbox account. It'll be replaced with the default one (your current apple id)

Thanks.

erenfp commented 7 months ago

Same Problem