• Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

iOS iOS In app purchases on iOS14 are throwing exceptions

clee2005

Member
I've been getting a bunch of reports of crashing on iOS 14 devices. I checked the crash logs in Xcode to see that it's consistently crashing here (on iOS 14 only) :

Line 61 of iOS_TransactionListener.mm file in the iOS IAP Extension.

GML:
- (void)paymentQueue:(nonnull SKPaymentQueue *)queue updatedTransactions:(nonnull NSArray<SKPaymentTransaction *> *)transactions
{
    NSMutableArray<SKPaymentTransaction*>* mTransactions = [[NSMutableArray alloc] initWithArray:transactions];
 
   NSString* jsonResponse = [self parsePaymentTransactionsIntoJson:mTransactions];
When I tested on our devices I was only able to create this crash when I tried to purchase something and then hit CANCEL to back out of it. Then it would crash to the icons on the device. I've had a number of users report that they cannot open any of our games any more on iOS 14. I could be something completely unrelated that they are reporting, or maybe it's a pending purchase transaction stuck in the queue that shows up when the extension first runs (when the game starts up).

I'm not really sure what's happening on this line of code specifically that's throwing the exception (it's the last line where the exception is actually thrown on). Perhaps mTransactions is null or something unexpected suddenly? I'm just raising this hoping that others might have seen it or have some ideas around it.

Thanks,
Chris
 
Last edited:

IvanKorol

Member
Hi! We have same issues.
In ios 14 canceled transaction may have NULL transactionIdentifier.
Solution - add some null check to handleFailedTransaction in iOS_TransactionListener
Like this:
Objective-C:
/// Handles failed purchase transactions.
-(NSString*)handleFailedTransaction:(SKPaymentTransaction*)transaction
{
    if(transaction.transactionIdentifier)    [m_activeTransactions setValue:transaction forKey:transaction.transactionIdentifier];
    const char* product = [transaction.payment.productIdentifier cStringUsingEncoding:NSUTF8StringEncoding];
    const char* receipt = [[self getReceiptData:transaction] cStringUsingEncoding:NSUTF8StringEncoding];
    const char* token = [transaction.transactionIdentifier cStringUsingEncoding:NSUTF8StringEncoding];
    if(token==NULL) token="";
    // Receipt data could be quite large so don't risk overrunning a fixed sized buffer
    char* json = (char*)alloca(strlen(product) + strlen(receipt) + strlen(token) + 256);
    sprintf(json, "{ \"productId\":\"%s\", \"purchaseState\":%d, \"responseCode\":%d, \"purchaseToken\":\"%s\", \"receipt\":\"%s\" }", product, (int)purchase_failed, (int)transaction.transactionState, token, receipt);
    return [[[NSString alloc] initWithCString:json encoding:NSASCIIStringEncoding] autorelease];
}
 
Top