mirror of
https://github.com/defold/extension-iap
synced 2025-06-27 10:27:46 +02:00
Add transactions handler to init method according ios documentation it's important to add handler on application:didFinishLaunchingWithOptions: (https://developer.apple.com/documentation/storekit/in-app_purchase/setting_up_the_transaction_observer_for_the_payment_queue?language=objc), move observable commands to separate queue so it can be processed separately and after listener setup, add IAP_ProcessPendingTransactions function to resolve pending transactions on iOS.
This commit is contained in:
parent
d6cc6f55f9
commit
cbc1f659c1
@ -50,6 +50,12 @@ struct IAP
|
|||||||
|
|
||||||
static IAP g_IAP;
|
static IAP g_IAP;
|
||||||
|
|
||||||
|
static int IAP_ProcessPendingTransactions(lua_State* L)
|
||||||
|
{
|
||||||
|
//todo handle pending transactions if there is such thing on Android
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int IAP_List(lua_State* L)
|
static int IAP_List(lua_State* L)
|
||||||
{
|
{
|
||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
@ -187,6 +193,7 @@ static const luaL_reg IAP_methods[] =
|
|||||||
{"restore", IAP_Restore},
|
{"restore", IAP_Restore},
|
||||||
{"set_listener", IAP_SetListener},
|
{"set_listener", IAP_SetListener},
|
||||||
{"get_provider_id", IAP_GetProviderId},
|
{"get_provider_id", IAP_GetProviderId},
|
||||||
|
{"process_pending_transactions", IAP_ProcessPendingTransactions},
|
||||||
{0, 0}
|
{0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -77,6 +77,11 @@ static void IAPList_Callback(void* luacallback, const char* result_json)
|
|||||||
dmScript::TeardownCallback(callback);
|
dmScript::TeardownCallback(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int IAP_ProcessPendingTransactions(lua_State* L)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int IAP_List(lua_State* L)
|
static int IAP_List(lua_State* L)
|
||||||
{
|
{
|
||||||
DM_LUA_STACK_CHECK(L, 0);
|
DM_LUA_STACK_CHECK(L, 0);
|
||||||
@ -210,6 +215,7 @@ static const luaL_reg IAP_methods[] =
|
|||||||
{"restore", IAP_Restore},
|
{"restore", IAP_Restore},
|
||||||
{"set_listener", IAP_SetListener},
|
{"set_listener", IAP_SetListener},
|
||||||
{"get_provider_id", IAP_GetProviderId},
|
{"get_provider_id", IAP_GetProviderId},
|
||||||
|
{"process_pending_transactions", IAP_ProcessPendingTransactions},
|
||||||
{0, 0}
|
{0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ struct IAP
|
|||||||
NSMutableDictionary* m_PendingTransactions;
|
NSMutableDictionary* m_PendingTransactions;
|
||||||
dmScript::LuaCallbackInfo* m_Listener;
|
dmScript::LuaCallbackInfo* m_Listener;
|
||||||
IAPCommandQueue m_CommandQueue;
|
IAPCommandQueue m_CommandQueue;
|
||||||
|
IAPCommandQueue m_ObservableQueue;
|
||||||
SKPaymentTransactionObserver* m_Observer;
|
SKPaymentTransactionObserver* m_Observer;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -324,28 +325,25 @@ static void HandlePurchaseResult(IAPCommand* cmd)
|
|||||||
assert(top == lua_gettop(L));
|
assert(top == lua_gettop(L));
|
||||||
}
|
}
|
||||||
|
|
||||||
@implementation SKPaymentTransactionObserver
|
static void processTransactions(IAP* m_IAP, NSArray* transactions) {
|
||||||
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
|
for (SKPaymentTransaction* transaction in transactions) {
|
||||||
{
|
if ((!m_IAP->m_AutoFinishTransactions) && (transaction.transactionState == SKPaymentTransactionStatePurchased)) {
|
||||||
for (SKPaymentTransaction* transaction in transactions) {
|
|
||||||
|
|
||||||
if ((!self.m_IAP->m_AutoFinishTransactions) && (transaction.transactionState == SKPaymentTransactionStatePurchased)) {
|
|
||||||
NSData *data = [transaction.transactionIdentifier dataUsingEncoding:NSUTF8StringEncoding];
|
NSData *data = [transaction.transactionIdentifier dataUsingEncoding:NSUTF8StringEncoding];
|
||||||
uint64_t trans_id_hash = dmHashBuffer64((const char*) [data bytes], [data length]);
|
uint64_t trans_id_hash = dmHashBuffer64((const char*) [data bytes], [data length]);
|
||||||
[self.m_IAP->m_PendingTransactions setObject:transaction forKey:[NSNumber numberWithInteger:trans_id_hash] ];
|
[m_IAP->m_PendingTransactions setObject:transaction forKey:[NSNumber numberWithInteger:trans_id_hash] ];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!self.m_IAP->m_Listener)
|
if (!m_IAP->m_Listener)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
IAPTransaction* iap_transaction = new IAPTransaction;
|
IAPTransaction* iap_transaction = new IAPTransaction;
|
||||||
CopyTransaction(transaction, iap_transaction);
|
CopyTransaction(transaction, iap_transaction);
|
||||||
|
|
||||||
IAPCommand cmd;
|
IAPCommand cmd;
|
||||||
cmd.m_Callback = self.m_IAP->m_Listener;
|
cmd.m_Callback = m_IAP->m_Listener;
|
||||||
cmd.m_Command = IAP_PURCHASE_RESULT;
|
cmd.m_Command = IAP_PURCHASE_RESULT;
|
||||||
cmd.m_Data = iap_transaction;
|
cmd.m_Data = iap_transaction;
|
||||||
IAP_Queue_Push(&self.m_IAP->m_CommandQueue, &cmd);
|
IAP_Queue_Push(&m_IAP->m_ObservableQueue, &cmd);
|
||||||
|
|
||||||
switch (transaction.transactionState)
|
switch (transaction.transactionState)
|
||||||
{
|
{
|
||||||
@ -363,7 +361,19 @@ static void HandlePurchaseResult(IAPCommand* cmd)
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int IAP_ProcessPendingTransactions(lua_State* L)
|
||||||
|
{
|
||||||
|
processTransactions(&g_IAP, [SKPaymentQueue defaultQueue].transactions);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation SKPaymentTransactionObserver
|
||||||
|
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
|
||||||
|
{
|
||||||
|
processTransactions(self.m_IAP, transactions);
|
||||||
}
|
}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@ -477,18 +487,6 @@ static int IAP_SetListener(lua_State* L)
|
|||||||
dmScript::DestroyCallback(iap->m_Listener);
|
dmScript::DestroyCallback(iap->m_Listener);
|
||||||
|
|
||||||
iap->m_Listener = dmScript::CreateCallback(L, 1);
|
iap->m_Listener = dmScript::CreateCallback(L, 1);
|
||||||
|
|
||||||
if (g_IAP.m_Observer == 0) {
|
|
||||||
SKPaymentTransactionObserver* observer = [[SKPaymentTransactionObserver alloc] init];
|
|
||||||
observer.m_IAP = &g_IAP;
|
|
||||||
// NOTE: We add the listener *after* a lua listener is set
|
|
||||||
// The payment queue is persistent and "old" transaction might be processed
|
|
||||||
// from previous session. We call "finishTransaction" when appropriate
|
|
||||||
// for all transaction and we must ensure that the result is delivered to lua.
|
|
||||||
[[SKPaymentQueue defaultQueue] addTransactionObserver: observer];
|
|
||||||
g_IAP.m_Observer = observer;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -506,6 +504,7 @@ static const luaL_reg IAP_methods[] =
|
|||||||
{"restore", IAP_Restore},
|
{"restore", IAP_Restore},
|
||||||
{"set_listener", IAP_SetListener},
|
{"set_listener", IAP_SetListener},
|
||||||
{"get_provider_id", IAP_GetProviderId},
|
{"get_provider_id", IAP_GetProviderId},
|
||||||
|
{"process_pending_transactions", IAP_ProcessPendingTransactions},
|
||||||
{0, 0}
|
{0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -520,6 +519,7 @@ static dmExtension::Result InitializeIAP(dmExtension::Params* params)
|
|||||||
g_IAP.m_InitCount++;
|
g_IAP.m_InitCount++;
|
||||||
|
|
||||||
IAP_Queue_Create(&g_IAP.m_CommandQueue);
|
IAP_Queue_Create(&g_IAP.m_CommandQueue);
|
||||||
|
IAP_Queue_Create(&g_IAP.m_ObservableQueue);
|
||||||
|
|
||||||
lua_State*L = params->m_L;
|
lua_State*L = params->m_L;
|
||||||
int top = lua_gettop(L);
|
int top = lua_gettop(L);
|
||||||
@ -535,6 +535,12 @@ static dmExtension::Result InitializeIAP(dmExtension::Params* params)
|
|||||||
|
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
assert(top == lua_gettop(L));
|
assert(top == lua_gettop(L));
|
||||||
|
|
||||||
|
SKPaymentTransactionObserver* observer = [[SKPaymentTransactionObserver alloc] init];
|
||||||
|
observer.m_IAP = &g_IAP;
|
||||||
|
[[SKPaymentQueue defaultQueue] addTransactionObserver: observer];
|
||||||
|
g_IAP.m_Observer = observer;
|
||||||
|
|
||||||
return dmExtension::RESULT_OK;
|
return dmExtension::RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -557,6 +563,9 @@ static void IAP_OnCommand(IAPCommand* cmd, void*)
|
|||||||
static dmExtension::Result UpdateIAP(dmExtension::Params* params)
|
static dmExtension::Result UpdateIAP(dmExtension::Params* params)
|
||||||
{
|
{
|
||||||
IAP_Queue_Flush(&g_IAP.m_CommandQueue, IAP_OnCommand, 0);
|
IAP_Queue_Flush(&g_IAP.m_CommandQueue, IAP_OnCommand, 0);
|
||||||
|
if (g_IAP.m_Observer) {
|
||||||
|
IAP_Queue_Flush(&g_IAP.m_ObservableQueue, IAP_OnCommand, 0);
|
||||||
|
}
|
||||||
return dmExtension::RESULT_OK;
|
return dmExtension::RESULT_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -585,6 +594,7 @@ static dmExtension::Result FinalizeIAP(dmExtension::Params* params)
|
|||||||
}
|
}
|
||||||
|
|
||||||
IAP_Queue_Destroy(&g_IAP.m_CommandQueue);
|
IAP_Queue_Destroy(&g_IAP.m_CommandQueue);
|
||||||
|
IAP_Queue_Destroy(&g_IAP.m_ObservableQueue);
|
||||||
|
|
||||||
return dmExtension::RESULT_OK;
|
return dmExtension::RESULT_OK;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user