"react-native": "0.55.4"
"react-native-iap": "^2.3.2"
Android
Please help me, I need to fix this immediately. Because there are already +2k users
App crashes because of rniap in many devices. In play console, I saw this error causes the crash :
java.lang.RuntimeException:
here is the report from play console :
https://ibb.co/gDxZQA
I don't know what to do, I used rniap like in example.
in componentDidMount :
try {
const result = await RNIap.initConnection();
} catch (err) {
console.log(err);
}
in componentWillUnmount:
RNIap.endConnection();
Could you try our recent version 2.3.19
and comeback?
I can't. Because it was an immediate situation. So, I changed the iap package. Now there are no crashes in +3k users. But, thank you. I will try it in my next project.
Hi, can you reopen this issue? I have the same problem and I'm using version 2.3.21
java.lang.RuntimeException:
at com.facebook.react.bridge.CallbackImpl.invoke (CallbackImpl.java:28)
at com.facebook.react.bridge.PromiseImpl.resolve (PromiseImpl.java:30)
at com.dooboolab.RNIap.RNIapModule$4.run (RNIapModule.java:155)
at com.dooboolab.RNIap.RNIapModule$3.onBillingSetupFinished (RNIapModule.java:124)
at com.android.billingclient.api.BillingClientImpl$BillingServiceConnection.onServiceConnected (BillingClientImpl.java:903)
at android.app.LoadedApk$ServiceDispatcher.doConnected (LoadedApk.java:1658)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run (LoadedApk.java:1687)
at android.os.Handler.handleCallback (Handler.java:789)
at android.os.Handler.dispatchMessage (Handler.java:98)
at android.os.Looper.loop (Looper.java:164)
at android.app.ActivityThread.main (ActivityThread.java:6938)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:327)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1374)
this is my componentDidMount
const itemSKus = Platform.select({
ios: [
...
],
android: [
...
]
});
try {
const message = await RNIap.initConnection();
//console.log(`message = ${message}`);
const items = await RNIap.getProducts(itemSKus);
//console.log(`items = ${items.length}`);
//console.log(items);
this.props.storeInAppPurchaseList(items);
} catch (errorCode) {
console.log(`error rniap = ${errorCode}`);
}
@LinusU Could you help us out here? Why would callback.run()
crashes in release? Should we check whether callback
is null in ensureConnection
? Hm. it is a runtime exception
.
Hmmm, what does RuntimeException
mean here, is there no more info? @hyochan why do you think that callback
was null
? 🤔
@LinusU Thanks for your feedback. I've no idea currently. I've just saw issue line below.
In RNIapModule.java
line 124,
callback.run();
Do you have any further idea?
@LinusU If you don't have any idea about this one, I'd consider rolling this back to where we were at previously.
Okay, here is the problem:
For some reason we are calling the callback more than once, should be easy to fix!
@LinusU Looks great because you are in a track! Could you give us a PR
for this?
Why is there a RuntimeException in that method?
if (!mInvoked) {
mJSInstance.invokeCallback(mCallbackId, Arguments.fromJavaArgs(args));
mInvoked = true;
}
is not something like this enough?
@hyochan sorry, didn't get time to look at this yesterday, hopefully I can take a look soon
@Ilario17 It's probably to flag that there is a logic error somewhere, to be fair, we shouldn't call that method multiple times
edit: ah, the problem comes when onBillingSetupFinished
happens more than once. In the ensureConnection
we need to remove the listener when we are done (i.e. when we call callback.run()
or reject the promise passed in). Should be an easy PR if anyone is up for some free karma! Otherwise I'll try to get to it soon
@LinusU So do you mean onBillingSetupFinished
, we should remove the billingClientStateListener
? Would someone try this one out to be part of us?
If you want a quick and dirty solution, I would add a local variable to that function, didCallCallback = false
. Then guard the call to callback.run()
behind if (didCallCallback) { didCallCallback = true; callback.run() }
.
A cleaner solution would simply be to deregister the listener after the first call altogether...
Log.d(TAG, "billing client ready");
callback.run();
//deregister the listener here?
I've just released 2.4.0-beta2
to make fixes on this. Please try.
@hyochan I will try this new version
Please try 2.4.0-beta3 since beta2 had regression issue.
@hyochan after the update the error is still there :(
@Ilario17 What about 2.4.0-beta5
? Since I can't reproduce this in my side, I need your test :(
@hyochan why not just remove the listener, as @LinusU said?
@Ilario17 I was curious if that's the right solution. Also, I feel onBillingServiceDisconnected
should be notified. You may try to remove it and test this in your side and see if it works.
I don't know if this is related but I'm getting this crash in 2.4.0-beta5. It's easy to reproduce in emulator:
I mount the component where IAP loads, unmount it and then mount it again, boom crash.
EDIT: I downgraded to this commit and it no longer crashes https://github.com/dooboolab/react-native-iap/commit/2db337ac770a93508507ec046f31085ddbb346fb
Attempt to invoke virtual method 'void com.android.billingclient.api.BillingClient.querySkuDetailsAsync(com.android.billingclient.api.SkuDetailsParams, com.android.billingclient.api.SkuDetailsResponseListener)' on a null object reference
run
RNIapModule.java:223
ensureConnection
RNIapModule.java:113
getItemsByType
RNIapModule.java:218
invoke
Method.java
invoke
JavaMethodWrapper.java:372
invoke
JavaModuleWrapper.java:160
run
NativeRunnable.java
handleCallback
Handler.java:789
dispatchMessage
Handler.java:98
dispatchMessage
MessageQueueThreadHandler.java:29
loop
Looper.java:164
run
MessageQueueThreadImpl.java:192
run
Thread.java:764
Here's the code that cause the crash on 2nd mount (2.4.0-beta5):
componentDidMount() {
this.loadIAPProducts()
}
componentWillUnmount() {
RNIap.endConnection();
}
loadIAPProducts = async () => {
const itemSkus = ['XXXX_id']
const result = await RNIap.initConnection();
if(result) {
try {
const products = await RNIap.getProducts(itemSkus);
if (products) {
this.setState({ iapProducts: products })
}
} catch (err) {
//console.log(err); // standardized err.code and err.message available
}
this.restoreIAPPurchases()
}
}
restoreIAPPurchases = async () => {
try {
const purchases = await RNIap.getAvailablePurchases()
if(purchases) {
purchases.forEach(purchase => {
if (purchase.productId === 'XXXX_id') {
try {
RNIap.consumePurchase(purchase.purchaseToken);
} catch(err) {
}
}
})
}
} catch (err) {
//console.log(err)
}
}
@rom1k Well this would not work in android emulator. Please try in real device.
@hyochan I notice that the version 2.4.0-beta3 has a 50% less crash, but still not enough
For 2.4.0-beta3 on Android I am getting error "Purchase failed with code: 0 (OK)" just from calling getProducts. beta 4 and 5 actually cause it to crash. I downgraded to 2.3.5 and it works fine, but I need the ios listener bug fixes in the 2.4.0-beta
```
componentDidMount() {
this.getProductDetails();
}
getProductDetails = async () => {
try {
await RNIap.initConnection();
const details = await RNIap.getProducts(products);
this.setState({
title: details[0].title,
description: details[0].description,
price: details[0].localizedPrice,
loading: false
});
} catch (err) {
console.log(err.message)
}
};
Could you try beta5 and comeback? There was mistake in that version so I quickly fixed
@hyochan @LinusU with version 2.4.0-beta5 the error is still there.
I have some information relevant to this discussion.
On 2.4.0-beta5, I am getting the following error
Attempt to invoke virtual method void com.android.billingclient.api.BillingClient.querySkuDetailsAsync(...) on a null object reference
pointing to RNIapModule.java
line 223. This implies that mBillingClient
is unexpectedly null
here.
To reproduce: mount a react-native component that calls RNIap.getProducts()
on componentDidMount
and RNIap.endConnection()
on componentWillUnmount
. Unmount the component and mount it again. The above error should occur.
The variable clientReady
is being used to track if the billing client setup has been completed, by setting it to false
in the onBillingServiceDisconnected()
callback. But mBillingClient
itself is set to null immediately when endConnection()
is called. This is a mismatch. It's possible for clientReady
to remain set to true
, even if mBillingClient
is null. I believe this is what is happening, at least for my error. It seems that something is preventing onBillingServiceDisconnected()
from being called.
I can confirm that I'm not getting "billing client disconnected"
in logcat on unmount as expected, so onBillingServiceDisconnected()
is indeed not being called.
Potential Fix: set clientReady = false
within the endConnection()
method (e.g. after line 179). I've tested this on device and it seems to work. Re-mountoing the in-app purchase component multiple times doesn't seem to result in any errors or crashes. Also, think about if it's necessary to set mBillingClient
to null? I don't have any experience here so I can't say, but it does seem a little odd. I also don't see any other projects on Github nulling out the billing client in this callback.
@mitchellmcm27 Thanks for your catch. This is very promising and I agree with you. It was hard for me to fix the problem without any minimal reproduction. Also, I'd like to solve the problems together.
Please give us any PR
if you have any thought of enhancing this problem.
Best, regards.
I've released 2.4.0-beta6 in the latest version of my app, with a few thousand upgrades so far. No crashes yet 👍
Sounds great. Thank you so much for the fix! I will close this issue for now then.
I already have some crash with the same stacktrace but much less than before.
java.lang.RuntimeException:
at com.facebook.react.bridge.CallbackImpl.invoke (CallbackImpl.java:28)
at com.facebook.react.bridge.PromiseImpl.resolve (PromiseImpl.java:30)
at com.dooboolab.RNIap.RNIapModule$4.run (RNIapModule.java:155)
at com.dooboolab.RNIap.RNIapModule$3.onBillingSetupFinished (RNIapModule.java:124)
at com.android.billingclient.api.BillingClientImpl$BillingServiceConnection.onServiceConnected (BillingClientImpl.java:903)
at android.app.LoadedApk$ServiceDispatcher.doConnected (LoadedApk.java:1658)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run (LoadedApk.java:1687)
at android.os.Handler.handleCallback (Handler.java:789)
at android.os.Handler.dispatchMessage (Handler.java:98)
at android.os.Looper.loop (Looper.java:164)
at android.app.ActivityThread.main (ActivityThread.java:6944)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.Zygote$MethodAndArgsCaller.run (Zygote.java:327)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1374)
Also still getting same stacktrace on 2.4.0-beta6
I think this bug should be reopened.
120 crash in less than 24 hours.
I'm not sure that the recent changes didn't cause their own problems, e.g. if mBillingClient
isn't null, but it isn't yet ready, the ensureConnection
function will simply overwrite mBillingClient
with a new client, throwing away the old one 🤔
I would like to know which version started showing this error, so that I can roll back to a stable version.
I too think the issue should be reopened. The original issue had to do with the callback, and the fixes for that surfaced the "null object reference" error. Although the latter may have been fixed (I agree with @LinusU that there may be more problems there), we are still dealing with the original issue.
I've gotten a few crashes related to the callback in beta6 as well.
I've reopened this. Hope someone can give PR
for this.
Do you guys know when this was introduced? I'd be more than happy to roll back.
I can confirm the crashes exist on beta6 as well as 2.3.23 on Android. Fairly easy to recreate per this [1] comment.
Edit: Now that I'm at home, I'm debugging into the Android native code for beta6. In case this is helpful, this is what's going on (at least in my app, calling getAvailablePurchases):
I'll experiment with killing off the listener once it's no longer needed.
[1]
https://github.com/googlesamples/android-play-billing/issues/45#issuecomment-324466519
I've merged #379 and released to beta8
. Please try that.
Is this fixed in the latest version? Is it safe to upgrade to latest?
@hyochan this issue still appears in 3.0.0-rc-2 any idea?
java.lang.RuntimeException
com.dooboolab.RNIap.RNIapModule$3.onBillingSetupFinished
java.lang.RuntimeException:
at com.facebook.react.bridge.CallbackImpl.invoke (CallbackImpl.java:28)
at com.facebook.react.bridge.PromiseImpl.resolve (PromiseImpl.java:30)
at com.dooboolab.RNIap.RNIapModule$3.onBillingSetupFinished (RNIapModule.java:129)
at com.android.billingclient.api.BillingClientImpl$BillingServiceConnection$1.run (BillingClientImpl.java:1518)
at android.os.Handler.handleCallback (Handler.java:739)
at android.os.Handler.dispatchMessage (Handler.java:95)
at android.os.Looper.loop (Looper.java:148)
at android.app.ActivityThread.main (ActivityThread.java:7325)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run (ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1120)
@fokoz Could you try 3.0.0-rc-4
? It will work perfectly (hopefully).
@hyochan If I use try catch
this runtime error won't occur, I think rc-4 should resolve this.
Thank you !
Most helpful comment
@hyochan sorry, didn't get time to look at this yesterday, hopefully I can take a look soon
@Ilario17 It's probably to flag that there is a logic error somewhere, to be fair, we shouldn't call that method multiple times
edit: ah, the problem comes when
onBillingSetupFinished
happens more than once. In theensureConnection
we need to remove the listener when we are done (i.e. when we callcallback.run()
or reject the promise passed in). Should be an easy PR if anyone is up for some free karma! Otherwise I'll try to get to it soon