cordova-plugin-inapppurchase
cordova-plugin-inapppurchase copied to clipboard
Purchase not always works on iOS
In very minor cases the purchase does 'not' work. As the 'not' means the user gets charged by Apple but the IAP is not unlocked. Tried lots of different versions already but all end up as a fail. The IPA's do not unlock. This occurs on different iPhones (5, 5s 6, 6s) and iOS. It are just 15 out of many K people now that have this problem and I am stuck how to fix this, been busy for weeks now solving this problem. Problem is, these are the people that will write an review. And offcourse if you pay, you want to have your purchase. I did invite the people to join the TestFlight to test the new version. All people say the IAP gets unlocked after the purchase, but as soon as the exact same version goes live in the app store, it just does not work again for them. I have seen they have paid. What can be the problem, is Apple sending some different details back in some cases? I cant do much in the live version as I dont have control of the device :)
I came in contact with one of the users that have the problem and we meet up, tried to install the app and restore the IPA with their iTUnes account in my iPhone, works great. Visa versa, works great. But their iTunes account on their iPhone just does not work. Why? This proves that the code is working otherwise I couldnt get it working with my iTunes account on their iPhone. Also if people have more devices, it works on one and sometimes not on the other (works on iPad but not on iPhone for instance).
I guess I am not the only one out there with this problem. But cant find an answer anywhere...... so all suggestions or ideas are very much welcome!
********** update New version, same version as the TestFlight, is live now. That version worked for all persons that tested it, but in the live situation, still same problem. When they want to purchase an item then the buy function says "you already own this item, do you want to restore it for free", click yes and then the "Buying..." spinner keeps on spinning. So somewhere it keeps stuck in the .buy() function and never gives an error back otherwise the .catch will fire. You have to close the app to continue. Same for restore, 1 item is restored, the other does not. Then press the buy button again and same story, already owned and nothing happens...
Your code / steps to reproduce
loadProducts = function () {
$ionicLoading.show({ template: spinner + 'Loading...' });
inAppPurchase
.getProducts(productIds)
.then(function (products) {
$ionicLoading.hide();
// Load all products by ID
products.forEach(function (product) {
// Add extra field to the product object
product.owned = false;
switch (product.productId) {
case ncProductProVer:
if (GlobalVars.vars.fullVersion == true) {
product.owned = true;
}
break;
case ncProductNoAds:
if (GlobalVars.vars.noAds == true) {
product.owned = true;
}
break;
}
});
//alert(products[0].productId + ' ' + products[1].productId);
$scope.products = products;
})
.catch(function (err) {
$ionicLoading.hide();
//$cordovaDialogs.alert('Error loading products. Details:\n- Code: ' + err.code + '\n- Message: ' + err.message, 'Error', 'OK')
$scope.CodeError = true;
});
};
// BUY a product
$scope.buy = function (productId) {
$ionicLoading.show({ template: spinner + 'Buying...' });
inAppPurchase
.buy(productId)
.then(function (data) {
$ionicLoading.hide();
enableIAP(productId, true);
})
.then(function () {
$ionicLoading.hide();
loadProducts();
})
.catch(function (err) {
$ionicLoading.hide();
errHandling(err.code, productId);
});
};
// RESTORE in app purchases
$scope.restore = function () {
$ionicLoading.show({ template: spinner + 'Restoring purchases...' });
inAppPurchase
.restorePurchases()
.then(function (purchases) {
$ionicLoading.hide();
purchases.forEach(function (purchase) {
// Unlock the relevant feature based on this product id, if any
// Store the purchase in localStorage
enableIAP(purchase.productId, true);
});
// Reload the productlist
loadProducts();
})
.catch(function (err) {
$ionicLoading.hide();
});
};
### Type of product you are working with consumable/non-consumable/subscription
There are 2 non-consumables
### Version of cordova
Latest
### Version of iOS/Android
Affects all versions of iOS
Still no luck. Complaints are increasing since last iOS update. My guess is, looking at the rmstore github page, that there must be a problem, reading there LOTS of issues. The .buy() function never returns a success of fail, just keeps hanging there.
If you can resolve this error, please write to here. Thank you.
Didn't find any solution, my knowledge for digging in the RMStore is just not enough. I ended up with two choices:
-
make all free....
-
Keeping in mind that the popup 'Buying' keeps spinning means there is no callback from that function. The actual purchase is made, people are charged, but it never unlocks. So the idea is that you can give a time to the popup and after that time expires, unlock the IAP (no ads for instance). For this the popup must be spinning. But there are 2 reasons why this popup keeps spinning. One there is a bug and two the user is not logged in. The last one is not that often and gives the user your choice of time to fill in their login details for the app store, for example 90 secs. Can make this longer as you wish. You can tell your customers that sometimes it takes a little longer... but as soon as somebody knows this, they can exploit it, but hey, the other option is option 1... all free. I choose for all free in my case and hope in the future there will be a working IAP for ionic.. this was my second one I tested and also failed to do the job. Other one was https://github.com/j3k0/cordova-plugin-purchase, started with that one but this one has same issues.... :(
// BUY a product $scope.buy = function (productId) { // 90 secs $ionicLoading.show({ template: spinner + 'Buying...' , duration: 90000}).then(function(){ enableIAP(productId, true); });
@Seoptics same issues here :( . What did you end up doing?
@juergengunz make the app free
I have the same problem as described by @Seoptics with an app which is in production. Some users report to have paid for the premium feature, but not having these features unlocked. They can show us screenshot of the payment receipt in iTunes, but we don't have any track of it in our system. I set up a lot of bug reporting regarding in-app purchase functions in my app, and everything seems to point to the fact that sometimes the buy function does not return any promise.
This bug is quite stressful as users can be very upset when they pay and don't have their premium content unlocked. We received 5 complaints last week, for 40 sells, so this bug happens quite often !
As a workaround, I got inspired by @Seoptics's idea. I validate the purchase in case I don't have any news from iTunes, but unvalidate it in case I have an error a long time after that. This is necessary for instance if the user take a long time to type their iTunes password and decide to cancel the purchase. This way they could have their premium feature activated without any payment.
A simplified version of the code look like this :
` solidBuy(productId:string):Promise< string >{
return new Promise((resolve,reject) => {
let order = this.inAppPurchase.buy(productId);
order.then((data)=> {
clearTimeout(this.orderTimeout);
this.activateProduct(productId);
resolve("Purchase complete");
})
.catch((err)=> {
clearTimeout(this.orderTimeout);
this.deActivateProduct(productId); // in case it would have been activated by the timeout below
reject(err.errorMessage);
});
this.orderTimeout = setTimeout(() => {
this.activateProduct(productId);
resolve("Purchase complete (maybe)");
},20000);
});
} `
Along this ugly workaround, I will also keep track of validated sells on the app side, and compare it to the sells on iTunes Connect. This way we should see if this approach lead to some unpaid premium activation.
Thanks @Seoptics for putting me on the track of this solution.
A little update here : the workaround described in my last post does the job in our project. We don't receive complaints anymore, and the number of premium unlocks allowed by the workaround correspond to the number of purchase in iTunes Connect.
Interestingly, my app monitoring tool shows that, in fact, the promise is sometime returned many minutes after the purchase on Apple side. In these cases, this means your loader (if you have one in your app) will continue to show for many minutes, waiting for the promise to be resolved. Most of the time your user will restart the app, avoiding all the logic related to the purchase to be executed on the app side.
I'm seeing this issue as well. Is there a more robust solution?
Currently having this issue still.. does anyone have any solutions??
@conor345 Check this thread: https://github.com/AlexDisler/cordova-plugin-inapppurchase/issues/170#issuecomment-397426544
The problem seems to be that some Promise doesn't return, if the user is required to change/update their payment infos.