In my app, I have one in app purchase which basically allows the user to unlock some restricted functionality for life.
So at the start I want to check if the user have purchased the item before. (via get history)
If they have I unlock the functionality.
On my signed APK file (android), I have the following issues:
-the purchase never acknowledges (although it does when run via react-native run-android)
-if you press the purchase button twice the error “already connected to app store appears”
-I don’t think its getting the purchase history when running from the signed file (although I can print out the result in the console in debug mode)
I am not entirely sure when to call await InAppPurchases.connectAsync(); so this could be one potential source of issues
So this is my code in my “Inner App” . My App component is just the InnerApp wrapped in the provider component from redux. The inner app contains all the navigation stacks so the purchase listener should be global.
e.g.
export default function App (){
…more code
return(
< Provider store={store} >
< InnerApp />
</ Provider >
}
Inner app code
import * as InAppPurchases from ‘expo-in-app-purchases’;
export default function InnerApp (){
…some more code
//gets purchase history
const getHistory = async ()=>{
await InAppPurchases.connectAsync();
let found=false
const { responseCode, results } = await InAppPurchases.getPurchaseHistoryAsync();if (responseCode === InAppPurchases.IAPResponseCode.OK) {
results.forEach(result => {if (result.acknowledged) {
found =true
// this is just saving to local storage (in case they are using the app offline)
savePurchaseHistory(true)
}else{savePurchaseHistory(false)
}
});
}
if( found){
//updates a state in the redux store
dispatch(purchaseIAP() )
}else if(responseCode === IAPResponseCode.USER_CANCELED ){dispatch(removeIAP() )
savePurchaseHistory(false)
}
await InAppPurchases.disconnectAsync();
}
//listens for purchases
const setUpIAP = async() => {
// Set purchase listener
await InAppPurchases.connectAsync();
await InAppPurchases.setPurchaseListener(({ responseCode, results, errorCode }) => {
// Purchase was successful
if (responseCode === InAppPurchases.IAPResponseCode.OK) {
results.forEach(purchase => {
if (!purchase.acknowledged) {// Process transaction here and unlock content... dispatch(purchaseIAP() ) // Then when you're done InAppPurchases.finishTransactionAsync(purchase, false); } }); } // Else find out what went wrong if (responseCode === InAppPurchases.IAPResponseCode.USER_CANCELED) { } else if (responseCode === InAppPurchases.IAPResponseCode.DEFERRED) { console.log('User does not have permissions to buy but requested parental approval (iOS only)'); } else { console.warn(`Something went wrong with the purchase. Received errorCode ${errorCode}`); } });
}
//The in app stuff is called when the component is mounted
useEffect(() => {setUpIAP()
getHistory()
}, })
Further in my app I have a button that calls the following function when pressed
const unlockModes = async () => {
try {
const items = Platform.select({
ios: [
‘dev.products.all_modes’
],
android: [‘all_modes’],
});
await connectAsync();
const products = await InAppPurchases.getProductsAsync(items);if (products.results.length > 0) { await InAppPurchases.purchaseItemAsync("all_modes"); }
} catch (err) {
alert("error occured while trying to purchase: " + err);
}
};