Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

iOS 14: requestSubscription() issues #1120

Closed
the-dut opened this issue Sep 20, 2020 · 63 comments
Closed

iOS 14: requestSubscription() issues #1120

the-dut opened this issue Sep 20, 2020 · 63 comments
Labels
🙏 help wanted Extra attention is needed 📱 iOS Related to iOS 🍚 need contribution Need PR Stale

Comments

@the-dut
Copy link

the-dut commented Sep 20, 2020

Version of react-native-iap

4.4.9

Version of react-native

.62.2

Platforms you faced the error (IOS or Android or both?)

iOS only. Not testing on Android yet.

Expected behavior

Purchase dialog pops up to complete buy and then purchaseUpdatedListener called.

Actual behavior

call requestSubscription(). No purchase dialogs. PurchaseUpdatedListener called immediately with no purchase dialogs or valid receipt.

Tested environment (Emulator? Real Device?)

Real iOS 14 device using TestFlight.

Steps to reproduce the behavior

call RNIap.requestSubscription().

Notes:

  • XCode 12
  • using Sign In with Apple Id.
  • testing in sandbox with real Apple id (not test user)
  • works fine on iPad running iOS 13.7.
  • have applied iOS 14 promise fix.
@the-dut the-dut changed the title requestSubscription hangs on ios 14 requestSubscription hangs in ios 14 Sep 20, 2020
@the-dut the-dut changed the title requestSubscription hangs in ios 14 requestSubscription hangs in iOS 14 Sep 20, 2020
@the-dut the-dut changed the title requestSubscription hangs in iOS 14 iOS 14: requestSubscription hangs Sep 20, 2020
@the-dut the-dut changed the title iOS 14: requestSubscription hangs iOS 14: requestSubscription() hangs Sep 20, 2020
@Somnus007
Copy link

Same here. Any one can helps?

@sidferreira
Copy link

Not hanging, but returns []

@garrettjoecox
Copy link

For us the purchase dialog shows, and the purchase listener gets called correctly, but the requestSubscription call returns a promise that is never resolved.

@garrettjoecox
Copy link

Seems like this might have been resolved here #1064

@the-dut
Copy link
Author

the-dut commented Sep 21, 2020

I applied that promise fix previously, so that's not the problem here.

@compelling
Copy link

compelling commented Sep 22, 2020

Works for me with iOS14, here's how I did it:
// request purchase, listener registered above will receive notification when processing done RNIap.requestSubscription(this.productIds[0]).catch(err => { console.log(err.code, err.message); });

@the-dut
Copy link
Author

the-dut commented Sep 22, 2020

I was calling the method with the boolean parameter false, which I think is the recommendation. I removed that and am still seeing very strange behavior on iOS14 no matter how I call the method, and it works fine on an iPhone and iPad running iOS 13 via TestFlight. I tested requestSubscription with and without the boolean and I am never getting the purchase dialogs on iOS 14. Now most times it calls RequestUpdatedListener immediately with what looks like an invalid receipt.

Are there others who are having no problems with their subscriptions in iOS14 and xCode 12 using TestFlight?

@the-dut the-dut changed the title iOS 14: requestSubscription() hangs iOS 14: requestSubscription() issues Sep 23, 2020
@Eyal-A
Copy link

Eyal-A commented Sep 23, 2020

Hey, do you any of you use getPurchaseHistory() or getAvailablePurchases() just before requestSubscription()? if so, this seem to be the problem on iOS 14.

@the-dut
Copy link
Author

the-dut commented Sep 23, 2020

I do getAvailablePurchases() earlier in the flow - on app load, the screen right before my Subscription Screen.

@Eyal-A
Copy link

Eyal-A commented Sep 23, 2020

yeah, unfortunately this seem to be a bug in iOS 14. No fault of this plugin. I've checked in native code and it is the same issue.

@the-dut
Copy link
Author

the-dut commented Sep 23, 2020

That was the problem. I removed the call to getAvailablePurchases() and the purchase popups occurred and purchase was successful. Regrettably, I need to make that call to getAvailablePurchases, since I check the status of their subscription on App Load. So looks like we need to wait for a iOS 14 patch to fix this? Nothing else anyone can do? By the way, thank you so much theDev23!

@Eyal-A
Copy link

Eyal-A commented Sep 23, 2020

You're welcome, the-dut. Your best bet is probably relying on a server-based check.

@the-dut
Copy link
Author

the-dut commented Sep 23, 2020

I was hoping to avoid having a server do this. Is it as easy as copying the code from my react into something like a Firebase Cloud Function? Or is this something that needs to be re-architectured? Probably a dumb question, but hey.. we all started out asking dumb questions. :)

@tomerdev
Copy link

@the-dut You can use iaphub to take care of the server receipt validation

@the-dut
Copy link
Author

the-dut commented Sep 24, 2020

Beverage of your choice if you're ever in the Midwest US. :)

@nicknjpconsultingllc
Copy link

Same issue here affecting live users. @theDev23 do you happen to have a link any discussions about the issue in iOS? Are there any timelines for a fix?

@Eyal-A
Copy link

Eyal-A commented Sep 24, 2020

@nicknjpconsultingllc no link, sorry. I did the digging myself.

@the-dut I am using Firebase Cloud Functions as well. Check out this repo.

@the-dut
Copy link
Author

the-dut commented Sep 26, 2020

I ended up saving the receipt to a database on successful purchase in the purchaseUpdatedListener, then on app load I pull the receipt from the database, validate it again and check to see if it's expired or not. That allowed me to get rid of the call to getAvailablePurchases() is it works great in iOS14. It's worked really well so far and is much faster. Now a question on how far I need to take this. If this is all I do, will the UpdatedPurchaseListener get called on all updates to the subscription (basically the auto-renewals) until I finish the transactions? Or do I need to implement the server-to-server notifications to get informed of the auto-renewals? It almost seems like using the UpdatedPurchaseListener is a better (and simpler) solution since I have been reading the server-to-server integration isn't perfect.

@HamzaIkram2727
Copy link

Still getting this issue after removing getPurchaseHistory and applying the promise fix. Can't get to make the purchase dialog pop up. Can anybody help?

@the-dut
Copy link
Author

the-dut commented Sep 28, 2020

I'd say take a look at any/all calls you are making to AIP before doing the request to purchase. Are you calling getAvailablePurchases() as well?

@HamzaIkram2727
Copy link

I can't exclude the calls to getAvailablePurchases() and getPurchaseHistory(), is there anyway to make it requestSubscription() pop up the purchase menu with these calls?

@Somnus007
Copy link

Hi @HamzaIkram2727 , if I am not wrong, you can just create a new sandbox account to use and delete the old one. It should works.

@codeapp17
Copy link

@the-dut Even I am not using any getAvailablePurchases() and getPurchaseHistory() calls, still i am facing same problem. It does not show purchase dialog but purchased sucess automatically.

I am also calling finishTrsanactionIOS and finishTransation functions

@vjeranc
Copy link

vjeranc commented Oct 2, 2020

I managed to get the iOS native purchase dialog by exiting the app. This looks to me like some promises finally resolved. I'm not sure if there's any promise dependencies in react-native-iap but the behavior seems weird. Calling requestSubscription resolves in the app but there's no dialog until I exit the app.

@asobralr
Copy link

asobralr commented Oct 4, 2020

I'm having the same problem with getAvailblePruchases(), most of the times the promise does not resolve or reject. It started happening when testing on iOS 14 devices.

@acostalima
Copy link

acostalima commented Dec 17, 2020

Well, after a day of "having fun" this is what I've concluded so far... I have various devices on different OS versions and I have this problem on each one of them. I've contacted Apple in regards to this and we're still following up the case, however, without any solid conclusions. I do not believe it is a problem with the package, it must be something on the Apple's side. I've tried everything people are mentioning on this thread and in other threads that have reported a similar problem. The In App Purchase dialog is just inconsistent on showing up and until now, I cannot find a valid reason for it because the outcome are always different. Sometimes I get an E_UNKNOWN error, other times I get zero feedback, sometimes the pop up shows after 10 mins of waiting and other times it just works... I've tried with sandbox users, non sandbox users, I've had the same different outcomes for the same user and device and not even an error or a conclusive/insightful log is shown. This is just frustrating to debug because you can't find pretty much anything... Well, if you guys have any sort of advice or insight, I'm listening ... In the meantime, if I have some news from Apple, I'll keep you posted...
P.S EDIT. after reading the last comment, one thing is consistent and I can confirm it, on iOS 14 the thing seems more inconsistent even though it happens on every OS version that I've tested this (12, 13.7, 14). However, I'm still with the impression that the problem is not solely related the OS version and that's why I'm thinking that it must be something with the Sandbox server or any other thing in the Apple's end ..

Exactly what I'm experiencing on my end, even after the fix suggested by @andresordonezfm (#1120 (comment)). @106firestarter, did Apple ever reply?

I'll see what I can find in the developer forums meanwhile.

For the issue of purchases coming as SKPaymentTransactionStateRestored that happens after restoring, I created a new account and made a few purchases and it's not happening for that account. I'm able to call RNIap.getAvailablePurchases() and RNIap.requestSubscription() afterwards.

It seems that it may be related with the amount of purchases a user has? I haven't run any tests on production yet.

I'll try that, but production is a concern as well, indeed.

For the record, I'm also calling getAvailablePurchases() before requestSubscription().

@acostalima
Copy link

Possibly related:

@acostalima
Copy link

acostalima commented Dec 17, 2020

I can confirm as well that with a brand new account the issue is no longer as @Paduado stated (#1120 (comment)).

Correction: using a brand new account together with the fix suggested by @andresordonezfm makes it work on my end. Without the fix, after the very first subscription, the same behavior I was experiencing before emerges again and I can no longer subscribe again. One more thing I noticed after applying the fix is that subscriptions appear to no longer auto-renew automatically, not even once, although using sandbox they are expected to renew 5 times.

andresordonezfm added a commit to andresordonezfm/react-native-iap that referenced this issue Dec 29, 2020
Added a promise to the clearTransaction function, to wait until it finishes clearing open transactions

dooboolab-community#1120
andresordonezfm added a commit to andresordonezfm/react-native-iap that referenced this issue Dec 29, 2020
Added a promise to the clearTransaction function, to wait until it finishes clearing open transactions

dooboolab-community#1120
andresordonezfm added a commit to andresordonezfm/react-native-iap that referenced this issue Dec 29, 2020
Added a promise to the clearTransaction function, to wait until it finishes clearing open transactions

dooboolab-community#1120
@andresordonezfm
Copy link
Contributor

@andresordonezfm would you be willing to create a PR for these changes?

Hi, dude sorry for the delay again. I created a pull request to react-native iap

@andresordonezfm
Copy link
Contributor

I can confirm as well that with a brand new account the issue is no longer as @Paduado stated (#1120 (comment)).

Correction: using a brand new account together with the fix suggested by @andresordonezfm makes it work on my end. Without the fix, after the very first subscription, the same behavior I was experiencing before emerges again and I can no longer subscribe again. One more thing I noticed after applying the fix is that subscriptions appear to no longer auto-renew automatically, not even once, although using sandbox they are expected to renew 5 times.

Hi dude I think it is a sandbox problem. Do you keep giving that behavior?

@acostalima
Copy link

acostalima commented Dec 29, 2020

@andresordonezfm yes, I too suspect it is an issue with Apple's sandbox. I didn't perform any more tests since my last comment and I'm yet to check production. However, to date, I didn't receive any complaints from customers.

hyochan pushed a commit that referenced this issue Dec 30, 2020
* Bug Fix clearTransaction promise

Added a promise to the clearTransaction function, to wait until it finishes clearing open transactions

#1120

* BigFix clearTransaction promise

Added a promise to the clearTransaction function, to wait until it finishes clearing open transactions

#1120
@acostalima
Copy link

The sandbox appears to be back on track on my end when using a brand new account, as previous reported by @Paduado, without any making any changes to the code. 🤷‍♂️ 😕

@rusty120
Copy link

rusty120 commented Jan 5, 2021

@andresordonezfm I encountered the same thing and your patch seams to fix it. However, I think I see subtle bug in your code that could potentially cause cleartTransactionsIOS() to hang. removeTransactions may be called with 1 or more transactions to be removed. So in removeTransactions, I think we want:

        countPendingTransaction -= [transactions count];

In practice, I've only seen removedTransactions called with one transaction, but apple docs say it could be one or more. Nice find by the way! I was stuck on this for a while.

andresordonezfm added a commit to andresordonezfm/react-native-iap that referenced this issue Jan 7, 2021
Solution recommended by rusty120 to avoid a possible deadlock in the promise of the clearTransactionsIOS

dooboolab-community#1120 (comment)
@andresordonezfm
Copy link
Contributor

@andresordonezfm I encountered the same thing and your patch seams to fix it. However, I think I see subtle bug in your code that could potentially cause cleartTransactionsIOS() to hang. removeTransactions may be called with 1 or more transactions to be removed. So in removeTransactions, I think we want:

        countPendingTransaction -= [transactions count];

In practice, I've only seen removedTransactions called with one transaction, but apple docs say it could be one or more. Nice find by the way! I was stuck on this for a while.

Hi dude, thank you for you recommendation. I tested your propose and it works well for me. I made a pull request with that change.

Note: Yes, I reviewed that documentation but since it only is fired from transaction to transaction I did not implement it. But it is a very good recommendation. Thank you!

hyochan pushed a commit that referenced this issue Jan 8, 2021
Solution recommended by rusty120 to avoid a possible deadlock in the promise of the clearTransactionsIOS

#1120 (comment)
@PazuC10
Copy link

PazuC10 commented Mar 25, 2021

Hey, do you any of you use getPurchaseHistory() or getAvailablePurchases() just before requestSubscription()? if so, this seem to be the problem on iOS 14.

I use getPurchaseHistory(). when i use this, no purchase dialogs in requestSubscription.

@PazuC10
Copy link

PazuC10 commented Apr 2, 2021

Hey, do you any of you use getPurchaseHistory() or getAvailablePurchases() just before requestSubscription()? if so, this seem to be the problem on iOS 14.

I use getPurchaseHistory(). when i use this, no purchase dialogs in requestSubscription.

I find that there's no problem, it's just extremely slow, like 5 - 10mins to init the iap, or get the history or clear transaction, the first time purchase is ok, after the first time purchase, dont know why it's so slow

@stale
Copy link

stale bot commented Jul 8, 2021

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as "For Discussion" or "Good first issue" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale label Jul 8, 2021
@rb162215
Copy link

Hi Guys sorry for the delay.

I was reviewing and I found a solution for this problem. The problem is that before calling the restore purchases, the newly opened transactions of the same restore purchases do not close properly. Then I forcibly close them.

Then the clearTransactionIOS function of the library, the promise must be added to wait for the transactions to be closed using the function removedTransactions

Here is my code:

File: react-native-iap/ios/RNIapIos.m

  1. Replace the function RCT_EXPORT_METHOD(clearTransaction) with the following code
RCT_EXPORT_METHOD(clearTransaction:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject) {  
    
    NSLog(@"\n\n\n  ***  clear remaining Transactions. Call this before make a new transaction   \n\n.");

    NSArray *pendingTrans = [[SKPaymentQueue defaultQueue] transactions];
    countPendingTransaction = (NSInteger)(pendingTrans.count);
    
    if (countPendingTransaction > 0) {
        [self addPromiseForKey:@"cleaningTransactions" resolve:resolve reject:reject];

        for (SKPaymentTransaction *transaction in pendingTrans) {
            [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
        }
        
    } else {
        resolve(nil);
    }
}
  1. Add the following new function (I added this function at the end of the RNIapIos.m file. Before the line "@EnD" )
-(void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions {
    NSLog(@"removedTransactions");
    if (countPendingTransaction != nil && countPendingTransaction > 0) {
        countPendingTransaction--;
        if (countPendingTransaction == 0) {
            [self resolvePromisesForKey:@"cleaningTransactions" value:nil];
            countPendingTransaction = nil;
        }
    }
}

File: react-native-iap/ios/RNIapIos.h

  1. Under the code "SKProduct * promotedProduct;" add the following line
  NSInteger countPendingTransaction;

Finally before calling the "RNIap.requestSubscription (productId, false)" function.
The clearTransactionIOS function must be called, for example:

    if (Platform.OS === 'ios') {
      await RNIap.clearTransactionIOS();
    }
    await RNIap.requestSubscription(productId, false);

I hope it helps. The strange behavior of restore purchases I have not been able to find the reason. But this solved for me testing in Sandbox.

If you have any suggestions please let me know.

Working solution,First and Second steps code was already in my llibrary.
Only adding one line before requestSubscription -

if (Platform.OS === 'ios') { await RNIap.clearTransactionIOS(); }

works for me. Thanks a ton

@stale stale bot removed the Stale label Jul 20, 2021
@rajngarg
Copy link

Fixed by adding 5 second delay before requestSubscription

@stale
Copy link

stale bot commented Apr 27, 2022

Hey there, it looks like there has been no activity on this issue recently. Has the issue been fixed, or does it still require the community's attention? This issue may be closed if no further activity occurs. You may also label this issue as "For Discussion" or "Good first issue" and I will leave it open. Thank you for your contributions.

@stale stale bot added the Stale label Apr 27, 2022
marzuq-adebayo-dev added a commit to marzuq-adebayo-dev/React-Native-iap that referenced this issue May 20, 2023
* Bug Fix clearTransaction promise

Added a promise to the clearTransaction function, to wait until it finishes clearing open transactions

dooboolab-community/react-native-iap#1120

* BigFix clearTransaction promise

Added a promise to the clearTransaction function, to wait until it finishes clearing open transactions

dooboolab-community/react-native-iap#1120
marzuq-adebayo-dev added a commit to marzuq-adebayo-dev/React-Native-iap that referenced this issue May 20, 2023
Solution recommended by rusty120 to avoid a possible deadlock in the promise of the clearTransactionsIOS

dooboolab-community/react-native-iap#1120 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🙏 help wanted Extra attention is needed 📱 iOS Related to iOS 🍚 need contribution Need PR Stale
Projects
None yet
Development

No branches or pull requests