Skip to content

Commit

Permalink
iOS 13 crash when requesting iap product info
Browse files Browse the repository at this point in the history
http://community.stencyl.com/index.php?issue=1674.0

Xcode 11 + iOS 13 makes the purchase callback take place from a foreign thread.
https://github.com/HaxeFoundation/hxcpp/blob/master/docs/ThreadsAndStacks.md
HaxeExtension/extension-iap#55

We may want to eventually update our iap implementation to the HaxeExtension one.
https://github.com/HaxeExtension/extension-iap
  • Loading branch information
justin-espedal committed Apr 8, 2020
1 parent f5663f3 commit 944b3c9
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 18 deletions.
51 changes: 41 additions & 10 deletions project/common/ExternalInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,57 +31,65 @@ DEFINE_PRIM (purchases_initialize, 0);

static void purchases_restore()
{
restorePurchases();
restorePurchases();
}
DEFINE_PRIM (purchases_restore, 0);

static void purchases_buy(value productID)
{
purchaseProduct(val_string(productID));
purchaseProduct(val_string(productID));
}
DEFINE_PRIM(purchases_buy, 1);

static void purchases_requestProductInfo(value productIDcommalist)
{
requestProductInfo(val_string(productIDcommalist));
requestProductInfo(val_string(productIDcommalist));
}
DEFINE_PRIM(purchases_requestProductInfo, 1);

static value purchases_title(value productID)
{
return alloc_string(getTitle(val_string(productID)));
value toReturn = alloc_string(getTitle(val_string(productID)));

return toReturn;
}
DEFINE_PRIM(purchases_title, 1);

static value purchases_desc(value productID)
{
return alloc_string(getDescription(val_string(productID)));
value toReturn = alloc_string(getDescription(val_string(productID)));

return toReturn;
}
DEFINE_PRIM(purchases_desc, 1);

static value purchases_price(value productID)
{
return alloc_string(getPrice(val_string(productID)));
value toReturn = alloc_string(getPrice(val_string(productID)));

return toReturn;
}
DEFINE_PRIM(purchases_price, 1);

static value purchases_canbuy()
{
return alloc_bool(canPurchase());
value toReturn = alloc_bool(canPurchase());

return toReturn;
}
DEFINE_PRIM (purchases_canbuy, 0);

static void purchases_release()
{
releaseInAppPurchase();
releaseInAppPurchase();
}
DEFINE_PRIM (purchases_release, 0);

static value purchases_validate(value receipt,value password, value inproductionurl)
{
value toReturn = alloc_bool(validateReceipt(val_string(receipt),val_string(password), val_bool(inproductionurl)));

return alloc_bool(validateReceipt(val_string(receipt),val_string(password), val_bool(inproductionurl)));

return toReturn;
}
DEFINE_PRIM (purchases_validate, 3);

Expand All @@ -108,11 +116,34 @@ extern "C" void sendPurchaseEvent(const char* type, const char* data)

extern "C" void sendPurchaseFinishEvent(const char* type, const char* data, const char* receiptString, const char* transactionID)
{
value o = alloc_empty_object();
alloc_field(o,val_id("type"),alloc_string(type));
alloc_field(o,val_id("data"),alloc_string(data));
alloc_field(o,val_id("receiptString"),alloc_string(receiptString));
alloc_field(o,val_id("transactionID"),alloc_string(transactionID));
val_call1(purchaseEventHandle->get(), o);
}

extern "C" void sendPurchaseEventForeign(const char* type, const char* data)
{
int t0;
gc_set_top_of_stack(&t0, true);
value o = alloc_empty_object();
alloc_field(o,val_id("type"),alloc_string(type));
alloc_field(o,val_id("data"),alloc_string(data));
val_call1(purchaseEventHandle->get(), o);
gc_set_top_of_stack(0, true);
}

extern "C" void sendPurchaseFinishEventForeign(const char* type, const char* data, const char* receiptString, const char* transactionID)
{
int t0;
gc_set_top_of_stack(&t0, true);
value o = alloc_empty_object();
alloc_field(o,val_id("type"),alloc_string(type));
alloc_field(o,val_id("data"),alloc_string(data));
alloc_field(o,val_id("receiptString"),alloc_string(receiptString));
alloc_field(o,val_id("transactionID"),alloc_string(transactionID));
val_call1(purchaseEventHandle->get(), o);
gc_set_top_of_stack(0, true);
}
24 changes: 16 additions & 8 deletions project/iphone/Purchases.mm
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
#import <CoreFoundation/CoreFoundation.h>
#import <UIKit/UIKit.h>
#import <StoreKit/StoreKit.h>
#import <Foundation/Foundation.h>
#include <Availability.h>
#include "Purchases.h"
#include "PurchaseEvent.h"

extern "C" void sendPurchaseEvent(const char* type, const char* data);
extern "C" void sendPurchaseFinishEvent(const char* type, const char* data, const char* receiptString, const char* transactionID);
extern "C" void sendPurchaseEventForeign(const char* type, const char* data);
extern "C" void sendPurchaseFinishEventForeign(const char* type, const char* data, const char* receiptString, const char* transactionID);

#define IOS_13 ([[[UIDevice currentDevice] systemVersion] compare:@"13.0" options:NSNumericSearch] != NSOrderedAscending)
#define spe(type, data) if(IOS_13) sendPurchaseEventForeign(type, data); else sendPurchaseEvent(type, data);
#define spfe(type, data, receipt, transaction) if(IOS_13) sendPurchaseFinishEventForeign(type, data, receipt, transaction); else sendPurchaseFinishEvent(type, data, receipt, transaction);

@interface InAppPurchase: NSObject <SKProductsRequestDelegate, SKPaymentTransactionObserver>
{
Expand Down Expand Up @@ -44,7 +52,7 @@ - (void)initInAppPurchase
{
NSLog(@"Purchases initialize");
[[SKPaymentQueue defaultQueue] addTransactionObserver:self];
sendPurchaseEvent("started", "");
spe("started", "");
productsRequest = nil;
authorizedProducts = [[NSMutableDictionary alloc] init];
arePurchasesEnabled = NO;
Expand All @@ -65,7 +73,7 @@ - (void)purchaseProduct:(NSString*)productId
{
if(!arePurchasesEnabled || ![SKPaymentQueue canMakePayments])
{
sendPurchaseEvent("failed", [productId UTF8String]);
spe("failed", [productId UTF8String]);
return;
}

Expand All @@ -77,7 +85,7 @@ - (void)purchaseProduct:(NSString*)productId
return;
}

sendPurchaseEvent("failed", [productId UTF8String]);
spe("failed", [productId UTF8String]);
}

// Multiple requests can be made, they'll be added into authorized list if not already there.
Expand Down Expand Up @@ -252,7 +260,7 @@ - (void)productsRequest:(SKProductsRequest*)request didReceiveResponse:(SKProduc
[productsRequest release];
productsRequest = nil;
arePurchasesEnabled = YES;
sendPurchaseEvent("productsVerified", "");
spe("productsVerified", "");
}

#pragma mark - SKPaymentTransactionObserver and Purchase helper methods
Expand All @@ -272,7 +280,7 @@ - (void)finishTransaction:(SKPaymentTransaction*)transaction wasSuccessful:(BOOL
return;
}

sendPurchaseFinishEvent("success", [transaction.payment.productIdentifier UTF8String],[jsonObjectString UTF8String],[transaction.transactionIdentifier UTF8String]);
spfe("success", [transaction.payment.productIdentifier UTF8String],[jsonObjectString UTF8String],[transaction.transactionIdentifier UTF8String]);
}

else
Expand All @@ -282,7 +290,7 @@ - (void)finishTransaction:(SKPaymentTransaction*)transaction wasSuccessful:(BOOL
{
NSLog(@"Transaction error: %@", transaction.error.localizedDescription);
}
sendPurchaseEvent("failed", [transaction.payment.productIdentifier UTF8String]);
spe("failed", [transaction.payment.productIdentifier UTF8String]);
}

[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
Expand All @@ -306,7 +314,7 @@ - (void)restoreTransaction:(SKPaymentTransaction*)transaction
return;
}

sendPurchaseFinishEvent("restore", [transaction.payment.productIdentifier UTF8String],[jsonObjectString UTF8String],[transaction.transactionIdentifier UTF8String]);
spfe("restore", [transaction.payment.productIdentifier UTF8String],[jsonObjectString UTF8String],[transaction.transactionIdentifier UTF8String]);

//sendPurchaseEvent("restore", [transaction.originalTransaction.payment.productIdentifier UTF8String]);
//[self finishTransaction:transaction wasSuccessful:YES];
Expand Down Expand Up @@ -340,7 +348,7 @@ - (void)failedTransaction:(SKPaymentTransaction*)transaction

else
{
sendPurchaseEvent("cancel", [transaction.payment.productIdentifier UTF8String]);
spe("cancel", [transaction.payment.productIdentifier UTF8String]);
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
}
Expand Down

0 comments on commit 944b3c9

Please sign in to comment.