IAPManager.mm 4.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. /******************************************************************************/
  2. #include "iOS.h"
  3. /******************************************************************************/
  4. namespace EE{
  5. /******************************************************************************/
  6. static Bool HasPurchases;
  7. static DateTime AppStartTime=DateTime().getUTC();
  8. IAPManager *IAPMgr;
  9. /******************************************************************************/
  10. }
  11. /******************************************************************************/
  12. @implementation IAPManager
  13. /******************************************************************************/
  14. -(void)productsRequest:(SKProductsRequest*)request didReceiveResponse:(SKProductsResponse*)response
  15. {
  16. NSNumberFormatter *nf=[[NSNumberFormatter alloc] init];
  17. [nf setFormatterBehavior:NSNumberFormatterBehavior10_4];
  18. [nf setNumberStyle:NSNumberFormatterCurrencyStyle];
  19. REP([response.products count])
  20. {
  21. SKProduct *product=[response.products objectAtIndex:i];
  22. [nf setLocale:product.priceLocale];
  23. NSString *price=[nf stringFromNumber:product.price];
  24. Str item_id=product.productIdentifier;
  25. PlatformStore::Item *item=ConstCast(Store.findItem(item_id)); if(!item)item=&Store._items.New();
  26. item->subscription=false;
  27. item->id =item_id;
  28. item->name =product.localizedTitle;
  29. item->desc =product.localizedDescription;
  30. item->price=price;
  31. //[price release]; we're not the owner so we can't release it
  32. }
  33. for(NSString *invalid in response.invalidProductIdentifiers)Store._items.removeData(Store.findItem(AppleString(invalid)), true);
  34. [nf release];
  35. [request release]; // release the request which we've created manually in 'Store.refreshItems'
  36. if(Store.callback)Store.callback(PlatformStore::REFRESHED_ITEMS, null);
  37. }
  38. -(void)paymentQueue:(SKPaymentQueue*)queue updatedTransactions:(NSArray*)transactions;
  39. {
  40. Bool response_from_server=false;
  41. for(SKPaymentTransaction *transaction in transactions)
  42. {
  43. if(transaction.transactionState!=SKPaymentTransactionStatePurchasing)
  44. {
  45. response_from_server=true;
  46. SKPaymentTransaction *org_trans=((transaction.transactionState==SKPaymentTransactionStateRestored) ? transaction.originalTransaction : transaction);
  47. PlatformStore::RESULT result=PlatformStore::PURCHASED;
  48. PlatformStore::Purchase purchase;
  49. purchase.date .from(org_trans.transactionDate); // use the original transaction
  50. purchase.id =transaction.payment.productIdentifier;
  51. purchase.token=transaction.transactionIdentifier;
  52. if(transaction.transactionState==SKPaymentTransactionStateFailed)
  53. {
  54. switch(transaction.error.code)
  55. {
  56. case SKErrorPaymentCancelled : result=PlatformStore::USER_CANCELED ; if(Store.findPurchase(purchase.id)){result=PlatformStore::ALREADY_OWNED; break;} break; // 'SKErrorPaymentCancelled' also stands for when we already own the item, so do these checks
  57. #if IOS
  58. case SKErrorStoreProductNotAvailable: result=PlatformStore::ITEM_UNAVAILABLE; break;
  59. #endif
  60. case SKErrorPaymentNotAllowed : result=PlatformStore::SERVICE_CANCELED; break;
  61. case SKErrorClientInvalid : result=PlatformStore::SERVICE_CANCELED; break;
  62. default : result=PlatformStore::UNKNOWN ; break;
  63. }
  64. [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; // automatically remove failed transactions
  65. }
  66. // first add to the list of purchases
  67. if(result==PlatformStore::PURCHASED && !Store.findPurchaseByToken(purchase.token))Store._purchases.add(purchase);
  68. // now call the callback
  69. if(Store.callback && (purchase.date>AppStartTime || result!=PlatformStore::PURCHASED || HasPurchases)) // this may receive purchases from the past, for which we don't want callback to get notified, so verify that its date is newer than when the app started (since failed purchases have no date, then list all failed too, also list it if we've already received purchases from the server)
  70. {
  71. HasPurchases=true; // if this was our first purchase, then set 'HasPurchases' to true, so 'REFRESHED_PURCHASES' won't be called right after that
  72. Store.callback(result, &purchase); // !! here don't pass purchase from '_purchases' !!
  73. }
  74. }
  75. }
  76. if(response_from_server && !HasPurchases) // if this was a response from server, then we can assume that we now know all of the transactions for this app
  77. {
  78. HasPurchases=true;
  79. if(Store.callback)Store.callback(PlatformStore::REFRESHED_PURCHASES, null);
  80. }
  81. }
  82. /******************************************************************************/
  83. @end
  84. /******************************************************************************/