expo: [expo-in-app-purchases] purchaseItemAsync() never resolves on Android
🐛 Bug Report
On Android, the promise returned by InAppPurchases.purchaseItemAsync() never seems to resolve, regardless of whether the Google Play purchase prompt succeeds or is canceled.
This is in a bare build with expo-in-app-purchases@^7.0.0 that was ejected from Expo SDK 35 and uses react-native@0.59.10.
In my reading of BillingManager.java, it looks like the promise passed to purchaseItemAsync() isn’t remembered anywhere that it could later be resolved?
Environment
Expo CLI 3.1.2 environment info: System: OS: macOS 10.14.6 Shell: 3.2.57 - /bin/bash Binaries: Node: 12.9.1 - /usr/local/bin/node Yarn: 1.17.3 - /usr/local/bin/yarn IDEs: Android Studio: 3.5 AI-191.8026.42.35.5900203 Xcode: 11.1/11A1027 - /usr/bin/xcodebuild npmPackages: @sentry/react-native: ^1.0.7 => 1.0.7 @types/expo: ^32.0.0 => 32.0.13 @types/react-native: ^0.60.19 => 0.60.19 expo: ^35.0.0 => 35.0.0 react: 16.8.3 => 16.8.3 react-native: 0.59.10 => 0.59.10 react-navigation: ^3.13.0 => 3.13.0
Steps to Reproduce
In an Android bare-built app, after initializing the InAppPurchase module with connectAsync(), setPurchaseListener(), and getProductsAsync(), attempt a purchase as follows:
await InAppPurchases.purchaseItemAsync(productId);
Expected Behavior
The promise returned by purchaseItemAsync() resolves as soon as the Google Play billing UI disappears, regardless of whether the purchase succeeded or not, as documented.
Actual Behavior
The Google Play billing UI appears, but after it finishes, the app appears “stuck” because the purchaseItemAsync() promise does not resolve.
Reproducible Demo
(sorry, I can’t think of an easy way to create a repro case due to the large size of the Google Play Store infrastructure)
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 9
- Comments: 24 (9 by maintainers)
@ferrannp Did you make a PR ? It would be indeed very nice to get this resolved. It’s hard to believe after all this time Expo team havn’t looked into it. I find this bug kind of ‘major’
As a work-around, you can wrap
purchaseItemAsync()with code that creates and returns your own promise, which you can then store in a global variable and resolve from inside your purchase listener function. Even thoughpurchaseItemAsync()won’t resolve, you will still get a listener callback.