hyochan / react-native-iap

In App Purchase module for React Native!
https://react-native-iap.hyo.dev
MIT License
2.87k stars 647 forks source link

getAvailablePurchases returning "Error: An unknown error occurred" for TestFlight build #2274

Open aadityapaliwal94 opened 1 year ago

aadityapaliwal94 commented 1 year ago

Description

Everything was working fine with react native IAP v9.x.x with us. I updated it due to a crash issue on crashlytics regarding the thread safety. Now I am using the latest version, everything is working fine but I am not able to fetch the getAvailablePurchases in the TestFlight build. It's working fine if I run it directly Run from Xcode.

Expected Behavior

It should return the available purchases

Screenshots

Environment:

To Reproduce Steps to reproduce the behavior:

  1. Call getAvailablePurchases function in the TestFlight build.
  2. "Error: An unknown error occurred" returns.

[Optional] Additional Context


async getAvailablePurchases() {
    try {
      const availablePurchases = await RNIap.getAvailablePurchases()
      Utils.log('Store All Time Total Purchases ' + availablePurchases)
      const purchasesNeedsToCheck = []
      availablePurchases.forEach(element => {
        const txnMomentDate = moment(Number(element.transactionDate))
        const currentDateMoment = moment()
        const olderDays = Math.ceil(moment.duration(currentDateMoment.diff(txnMomentDate)).asDays())
        Utils.log('Transaction old days ' + olderDays)

        if (olderDays <= 35){ // #Warning: Only considering a month old txn. Need to change this if we have yearly subscription
          purchasesNeedsToCheck.push(element)
        }
      });

      Utils.log('Total Purchases needs to check ' + purchasesNeedsToCheck)

      var response = []
      for (const i in purchasesNeedsToCheck) {
        const purchase = purchasesNeedsToCheck[i];

        if (Utils.isSubsProduct(purchase.productId)) {
          Utils.log('Calling Validating purchase for productID : ' + purchase.productId)
          const result = await this.storeTransaction(purchase)
          if (result && result.productId) {
            response.push(result.productId)            
            SessionManager.instance.updatePurchasedData(purchase)            
            await SharedPreferences.storePurchasesProducts(result.productId);
            break        
          }
        }
      }

      Utils.log('Valid Purchases ' + JSON.stringify(response))
      return response
    } catch (error) {
      FirebaseManager.instance.recordError(IAP_ERROR_CODE, error);
      throw error
    }
  }
aadityapaliwal94 commented 1 year ago

It's even not working with the older builds of TestFlight where I was using the older version of the IAP library v9.x.x. It's working in the production (App store) with the same account. It looks like TestFlight specific issue... :(

If I change the user from Media & Purchases, it seems working fine sometimes not always.

xiaoosnggao commented 1 year ago

I have the same problem

dhyey001 commented 1 year ago

Also I have the same error.

oussama1995 commented 1 year ago

I have the same problem on real ios device in sandbox mode! calling getAvailablePurchases On IOS sometimes gives me the expected array of purchases which i use to find the latestPurchase to check the purchase state(still valid or not) but sometimes it throws an error "Error: An unknown error occurred" while i had not changed anything in the code ! any suggestions please ! PS: i am using the method getAvailablePurchases which is exported by the hook useIAP and then using the value availablePurchases "react-native-iap": "12.7.3"

mjfre commented 1 year ago

Same. Also get the same error with getPurchaseHistory(). This error still occurs when run from a useEffect where getProducts(...) and getSubscriptions(...) are successfully called.

oussama1995 commented 1 year ago

any news please @andresesfm

andresesfm commented 1 year ago

Capture the native logs and see if there's a native exception

hszouszcz commented 1 year ago

The same problem occurs in the sandbox.

mjfre commented 1 year ago

Still occurring for me on 12.10.5

Prathameshlabde commented 1 year ago

https://github.com/dooboolab-community/react-native-iap/issues/2455 Can anyone please suggest on this issue Please ?

vishalhyperspace commented 1 year ago

I have same problem. Can anyone fix this issue? Please help

DwaveVito commented 1 year ago

Still occurring for me on 12.10.7

DwaveVito commented 1 year ago

I fix this issue.

[Why] I use SK2 mode by default but isIosStorekit2 always return false

[How] setup mode before you call initConnection.

import { setup } from 'react-native-iap'
setup({ storekitMode: 'STOREKIT2_MODE' })
cloud27 commented 1 year ago

Hi, Personally I use this : setup({ storekitMode: 'STOREKIT_HYBRID_MODE' })

keval7838 commented 9 months ago

if i include this than it's returning null array but i have purchased product in sandbox setup({ storekitMode: 'STOREKIT2_MODE' })

DwaveVito commented 9 months ago

@keval7169-ops

https://react-native-iap.dooboolab.com/docs/migrate_to_11.0.0#how-do-i-know-whats-the-minimum-version-of-ios-my-app-supports

Open ios/Podfile file and look for the following line: platform :ios, '15.0'

Check your iOS minimum version. Follow this docs try it.

miran248 commented 7 months ago

It's not just getAvailablePurchases, getPurchaseHistory also throws - in both cases it happens only if you set alsoPublishToEventListener to true (false by default).

I'm basically trying to implement the restore purchases.

App is (managed) expo dev-client build.

versions

"react-native-iap": "^12.13.1",
"expo": "^50.0.14",
"react-native": "^0.73.6",

env

sandbox account
iphone 13 mini
ios v17.3

init

export const initIap = async () => {
  setup({ storekitMode: "STOREKIT2_MODE" });

  setLoading(true);

  purchaseErrorListener((error) => {
    logError("iap purchaseErrorListener error", error);
  });
  purchaseUpdatedListener((purchase) => {
    logInfo("iap purchaseUpdatedListener purchase", purchase);

    processPurchase(purchase);
  });
  transactionListener((transaction) => {
    logInfo("iap transactionListener transaction", transaction);
  });

  try {
    // await initConnection();

    await Promise.all([
      getProducts({ skus: productSkus }).then(setProducts),
      getSubscriptions({ skus: subscriptionSkus }).then(setSubscriptions),
    ]);
  } catch (error) {
    logError("iap initIap error", error);
  }

  setLoading(false);
};

restore

export const restorePurchases = async () => {
  try {
    // const purchaseHistory = await getPurchaseHistory({
    //   onlyIncludeActiveItems: true,
    //   alsoPublishToEventListener: true,
    //   automaticallyFinishRestoredTransactions: false,
    // });
    // console.log("iap restorePurchases purchaseHistory", purchaseHistory);

    const availablePurchases = await getAvailablePurchases({
      onlyIncludeActiveItems: true,
      alsoPublishToEventListener: true,
      automaticallyFinishRestoredTransactions: false,
    });

    console.log("iap restorePurchases availablePurchases", availablePurchases);
  } catch (error) {
    console.log("iap restorePurchases error", error);
  }
};

image