Hello I am am trying to utilize react-native-iap in my react-native expo app and no matter what I try I am getting the error "E_IAP_NOT_AVAILABLE" which after doing some digging is being cause by StokeKit not being available (1 or 2). I added react-native-iap to my plugins in app.json. What other setup step am I missing. I have tried through both expo go (i hear it wont work there but I tried) and by exporting to testflight and then trying from there. I don’t know what else to try. Below I have added my packages and the bulk of my code that tries to setup iap and causes the error.
Edit: I created a snack showing the error (not sure if react-native-iap would even work in a snack, but just trying to be helpful):
https://snack.expo.dev/@tristan-neateworks/expo-react-native-iap-e_iap_not_available
Packages:
"dependencies": {
"@expo/vector-icons": "^14.0.0",
"@expo/metro-runtime": "~3.2.1",
"@react-native-community/slider": "4.5.2",
"@react-native-picker/picker": "2.7.5",
"@shopify/react-native-skia": "1.2.3",
"expo-asset": "~10.0.8",
"expo-constants": "~16.0.2",
"expo-image": "~1.12.11",
"expo-linear-gradient": "~13.0.2",
"expo-linking": "~6.3.1",
"expo-router": "~3.5.16",
"expo-secure-store": "~13.0.1",
"expo-status-bar": "~1.12.1",
"react-native-bouncy-checkbox": "^4.0.1",
"react-native-dialog": "^9.3.0",
"react-native-gesture-handler": "~2.16.1",
"react-native-gifted-charts": "^1.4.10",
"react-native-iap": "^12.13.2",
"react-native-reanimated": "~3.10.1",
"react-native-safe-area-context": "4.10.1",
"react-native-screens": "3.31.1",
"react-native-svg": "15.2.0",
"expo-dev-client": "~4.0.16",
"react-native-linear-gradient": "*"
},
iap setup
import React from "react-native";
import {View} from "react-native";
import {
withIAPContext, setup,
initConnection,
purchaseErrorListener,
purchaseUpdatedListener,
flushFailedPurchasesCachedAsPendingAndroid, finishTransaction,
} from 'react-native-iap';
import {useEffect} from "react";
import {api, getUser} from "../../be";
import * as SecureStore from "expo-secure-store";
function Listener({children}) {
// eslint-disable-next-line no-unused-vars
let purchaseUpdateSubscription = null;
// eslint-disable-next-line no-unused-vars
let purchaseErrorSubscription = null;
useEffect(() => {
void (async () => {
console.log('t2')
await initConnection().then(() => {
// we make sure that "ghost" pending payment are removed
// (ghost = failed pending payment that are still marked as pending in Google's native Vending module cache)
console.log('t3')
flushFailedPurchasesCachedAsPendingAndroid()
.catch(() => {
console.log('t4')
// exception can happen here if:
// - there are pending purchases that are still pending (we can't consume a pending purchase)
// in any case, you might not want to do anything special with the error
})
.then(() => {
console.log('t5')
purchaseUpdateSubscription = purchaseUpdatedListener(
(purchase) => {
console.log('purchaseUpdatedListener', purchase);
const receipt = purchase.transactionReceipt;
if (receipt) {
console.log(receipt)
api('iap/receipt/', 'POST', purchase.transactionReceipt)
.then(async (deliveryResult) => {
if (deliveryResult.success === true) {
// Tell the store that you have delivered what has been paid for.
// Failure to do this will result in the purchase being refunded on Android and
// the purchase event will reappear on every relaunch of the app until you succeed
// in doing the below. It will also be impossible for the user to purchase consumables
// again until you do this.
// If consumable (can be purchased again)
// await finishTransaction({purchase, isConsumable: true});
// If not consumable
await finishTransaction({purchase, isConsumable: false});
// mark subscription as active
} else {
// Retry / conclude the purchase is fraudulent, etc...
}
});
}
},
);
purchaseErrorSubscription = purchaseErrorListener(
(error) => {
console.log('t6')
console.warn('purchaseErrorListener', error);
},
);
});
}).catch((e) => {
console.log('t10')
console.log(e)
// exception can happen here if:
// - there are pending purchases that are still pending (we can't consume a pending purchase)
// in any case, you might not want to do anything special with the error
});
})()
}, [])
useEffect(() => {
return () => {
console.log('t7')
// Anything in here is fired on component unmount.
if (purchaseUpdateSubscription) {
purchaseUpdateSubscription.remove();
purchaseUpdateSubscription = null;
}
if (purchaseErrorSubscription) {
purchaseErrorSubscription.remove();
purchaseErrorSubscription = null;
}
console.log('t7.5')
}
}, [])
return <View>{children}</View>
}
console.log('t1')
setup({storekitMode: 'STOREKIT2_MODE'})
export default withIAPContext(Listener)
2
Answers
Delete the ios folder, then npx expo run:ios
Were you able to solve it? I am interested in