Not sure if this helps, but these users are international users.
"Are you certain these users are logged in using a real production environment"
Yes, they are real end users, not testers.
"Can you purchase an IAP in the production environment?"
Yes, we had a production user help us test this out by purchasing one of our IAPs. We checked, and his credit card was in fact charged.
"If not, is your IAP approved and marked 'cleared for sale'"
Yes, all of my IAPs are both "approved" and marked "cleared for sale."
"Are you certain these users are really trying to make a purchase?"
I can't be so sure, but from my remote logs, I do know that they are:
1.) Initiating a purchase in my UI which triggers addPayment on the defaultQueue SKPaymentQueue as such:
- (void)InitiatePurchase:(NSString*)product_name
RLOGI(@"IAP: OBJC initiatePurchase: %@", product_name);
if (!products_initialized) {
RLOGE(@"IAP: Could not initiatePurchase, products not initialized!");
return;
}
if (!product_name) {
RLOGE(@"IAP: Could not initiatePurchase, nil product_name!");
return;
}
if (!user_email) {
RLOGE(@"IAP: Could not initiatePurchase, user not logged in!");
return;
}
if (![[products_dict allKeys] containsObject:product_name]) {
RLOGE(@"IAP: Could not find productToPurchase in dict!");
return;
}
SKProduct *productToPurchase = products_dict[product_name];
if (!productToPurchase) {
RLOGE(@"IAP: Invalid productToPurchase in dict!");
return;
}
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:productToPurchase];
payment.quantity = 1;
payment.applicationUsername = [self hashedValueForAccountName:user_email];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
^ note that no error conditions were logged.
2.) The purchase shows up in updatedTransactions as an SKPaymentTransaction with transactionState SKPaymentTransactionStatePurchasing:
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing: {
RLOGW(@"IAP: Purchase purchasing");
break;
}
case SKPaymentTransactionStateDeferred: {
RLOGW(@"IAP: Purchase deferred");
break;
}
case SKPaymentTransactionStateFailed: {
RLOGE(@"IAP: Purchase failed: error=%@", transaction.error);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Purchase failed"
message:@"You were not charged."
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
if (self.gameUIRef != nil) { [self.gameUIRef OnPurchaseFailedCallback]; }
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
break;
}
case SKPaymentTransactionStatePurchased: {
RLOGI(@"IAP: Purchase purchased");
[self validatePurchase:transaction];
break;
}
case SKPaymentTransactionStateRestored: {
RLOGW(@"IAP: Purchase restored");
[self validatePurchase:transaction];
break;
}
default:
RLOGE(@"IAP: Unexpected transaction state %@", @(transaction.transactionState));
}
}
}
3.) The purchase shows up in updatedTransactions as an SKPaymentTransaction with transactionState SKPaymentTransactionStateFailed and the error field is as shown:
At any rate, none of these suggestions would seem like resolutions that would come to mind as possible resolutions to a reasonable person upon seeing the error message: "Cannot connect to iTunes Store." As feedback, for example, one of the suggestions was that my product may not have been "approved"; if the IAP product is not approved, perhaps a more descriptive error message such as "IAP product is not approved" instead of the ambiguously vague (if not misleading) error message: "Cannot connect to iTunes Store," which suggests there either that there is an Internet connectivity problem or that the iTunes Store is down.