Add in-app purchase for MacOS
This commit is contained in:
		
					parent
					
						
							
								143816bee1
							
						
					
				
			
			
				commit
				
					
						f3ae566164
					
				
			
		
					 12 changed files with 593 additions and 0 deletions
				
			
		
							
								
								
									
										63
									
								
								atom/browser/api/atom_api_in_app_purchase.cc
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								atom/browser/api/atom_api_in_app_purchase.cc
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | ||||||
|  | // Copyright (c) 2017 Amaplex Software, Inc.
 | ||||||
|  | // Use of this source code is governed by the MIT license that can be
 | ||||||
|  | // found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | #include <utility> | ||||||
|  | #include <vector> | ||||||
|  | 
 | ||||||
|  | #include "atom/browser/api/atom_api_in_app_purchase.h" | ||||||
|  | #include "atom/common/native_mate_converters/callback.h" | ||||||
|  | #include "native_mate/dictionary.h" | ||||||
|  | 
 | ||||||
|  | #include "atom/common/node_includes.h" | ||||||
|  | 
 | ||||||
|  | namespace mate { | ||||||
|  | 
 | ||||||
|  | v8::Local<v8::Value> Converter<in_app_purchase::Payment>::ToV8( | ||||||
|  |     v8::Isolate* isolate, | ||||||
|  |     const in_app_purchase::Payment& payment) { | ||||||
|  |   mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); | ||||||
|  |   dict.SetHidden("simple", true); | ||||||
|  |   dict.Set("productIdentifier", payment.productIdentifier); | ||||||
|  |   dict.Set("quantity", payment.quantity); | ||||||
|  |   return dict.GetHandle(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | v8::Local<v8::Value> Converter<in_app_purchase::Transaction>::ToV8( | ||||||
|  |     v8::Isolate* isolate, | ||||||
|  |     const in_app_purchase::Transaction& transaction) { | ||||||
|  |   mate::Dictionary dict = mate::Dictionary::CreateEmpty(isolate); | ||||||
|  |   dict.SetHidden("simple", true); | ||||||
|  |   dict.Set("transactionIdentifier", transaction.transactionIdentifier); | ||||||
|  |   dict.Set("transactionDate", transaction.transactionDate); | ||||||
|  |   dict.Set("originalTransactionIdentifier", | ||||||
|  |            transaction.originalTransactionIdentifier); | ||||||
|  |   dict.Set("transactionState", transaction.transactionState); | ||||||
|  | 
 | ||||||
|  |   dict.Set("errorCode", transaction.errorCode); | ||||||
|  |   dict.Set("errorMessage", transaction.errorMessage); | ||||||
|  | 
 | ||||||
|  |   return dict.GetHandle(); | ||||||
|  | } | ||||||
|  | }  // namespace mate
 | ||||||
|  | 
 | ||||||
|  | namespace { | ||||||
|  | 
 | ||||||
|  | void Initialize(v8::Local<v8::Object> exports, | ||||||
|  |                 v8::Local<v8::Value> unused, | ||||||
|  |                 v8::Local<v8::Context> context, | ||||||
|  |                 void* priv) { | ||||||
|  |   mate::Dictionary dict(context->GetIsolate(), exports); | ||||||
|  | #if defined(OS_MACOSX) | ||||||
|  |   dict.SetMethod("canMakePayments", &in_app_purchase::CanMakePayments); | ||||||
|  |   dict.SetMethod("getReceiptURL", &in_app_purchase::GetReceiptURL); | ||||||
|  |   dict.SetMethod("purchaseProduct", &in_app_purchase::PurchaseProduct); | ||||||
|  |   dict.SetMethod("addTransactionListener", | ||||||
|  |                  &in_app_purchase::AddTransactionObserver); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | }  // namespace
 | ||||||
|  | 
 | ||||||
|  | NODE_MODULE_CONTEXT_AWARE_BUILTIN(atom_browser_in_app_purchase, Initialize) | ||||||
							
								
								
									
										36
									
								
								atom/browser/api/atom_api_in_app_purchase.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								atom/browser/api/atom_api_in_app_purchase.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | // Copyright (c) 2017 Amaplex Software, Inc.
 | ||||||
|  | // Use of this source code is governed by the MIT license that can be
 | ||||||
|  | // found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | #ifndef ATOM_BROWSER_API_ATOM_API_IN_APP_PURCHASE_H_ | ||||||
|  | #define ATOM_BROWSER_API_ATOM_API_IN_APP_PURCHASE_H_ | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | #include "atom/browser/in_app_purchase.h" | ||||||
|  | #include "atom/browser/in_app_purchase_observer.h" | ||||||
|  | #include "native_mate/dictionary.h" | ||||||
|  | 
 | ||||||
|  | namespace mate { | ||||||
|  | 
 | ||||||
|  | template <> | ||||||
|  | struct Converter<in_app_purchase::Payment> { | ||||||
|  |   static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, | ||||||
|  |                                    const in_app_purchase::Payment& val); | ||||||
|  |   static bool FromV8(v8::Isolate* isolate, | ||||||
|  |                      v8::Local<v8::Value> val, | ||||||
|  |                      in_app_purchase::Payment* out); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | template <> | ||||||
|  | struct Converter<in_app_purchase::Transaction> { | ||||||
|  |   static v8::Local<v8::Value> ToV8(v8::Isolate* isolate, | ||||||
|  |                                    const in_app_purchase::Transaction& val); | ||||||
|  |   static bool FromV8(v8::Isolate* isolate, | ||||||
|  |                      v8::Local<v8::Value> val, | ||||||
|  |                      in_app_purchase::Transaction* out); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | }  // namespace mate
 | ||||||
|  | 
 | ||||||
|  | #endif  // ATOM_BROWSER_API_ATOM_API_IN_APP_PURCHASE_H_
 | ||||||
							
								
								
									
										30
									
								
								atom/browser/in_app_purchase.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								atom/browser/in_app_purchase.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,30 @@ | ||||||
|  | // Copyright (c) 2017 Amaplex Software, Inc.
 | ||||||
|  | // Use of this source code is governed by the MIT license that can be
 | ||||||
|  | // found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | #ifndef ATOM_BROWSER_UI_IN_APP_PURCHASE_H_ | ||||||
|  | #define ATOM_BROWSER_UI_IN_APP_PURCHASE_H_ | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | #include "base/callback.h" | ||||||
|  | 
 | ||||||
|  | namespace in_app_purchase { | ||||||
|  | 
 | ||||||
|  | // --------------------------- Typedefs ---------------------------
 | ||||||
|  | 
 | ||||||
|  | typedef base::Callback<void(bool isProductValid)> InAppPurchaseCallback; | ||||||
|  | 
 | ||||||
|  | // --------------------------- Functions ---------------------------
 | ||||||
|  | 
 | ||||||
|  | bool CanMakePayments(void); | ||||||
|  | 
 | ||||||
|  | std::string GetReceiptURL(void); | ||||||
|  | 
 | ||||||
|  | void PurchaseProduct(const std::string& productID, | ||||||
|  |                      const int quantity, | ||||||
|  |                      const InAppPurchaseCallback& callback); | ||||||
|  | 
 | ||||||
|  | }  // namespace in_app_purchase
 | ||||||
|  | 
 | ||||||
|  | #endif  // ATOM_BROWSER_UI_IN_APP_PURCHASE_H_
 | ||||||
							
								
								
									
										149
									
								
								atom/browser/in_app_purchase_mac.mm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								atom/browser/in_app_purchase_mac.mm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,149 @@ | ||||||
|  | // Copyright (c) 2017 Amaplex Software, Inc. | ||||||
|  | // Use of this source code is governed by the MIT license that can be | ||||||
|  | // found in the LICENSE file. | ||||||
|  | 
 | ||||||
|  | #include "atom/browser/in_app_purchase.h" | ||||||
|  | #include "base/bind.h" | ||||||
|  | #include "base/strings/sys_string_conversions.h" | ||||||
|  | #include "content/public/browser/browser_thread.h" | ||||||
|  | 
 | ||||||
|  | #import <CommonCrypto/CommonCrypto.h> | ||||||
|  | #import <StoreKit/StoreKit.h> | ||||||
|  | 
 | ||||||
|  | // ============================================================================ | ||||||
|  | //                             InAppPurchase | ||||||
|  | // ============================================================================ | ||||||
|  | 
 | ||||||
|  | // --------------------------------- Interface -------------------------------- | ||||||
|  | 
 | ||||||
|  | @interface InAppPurchase : NSObject<SKProductsRequestDelegate> { | ||||||
|  |  @private | ||||||
|  |   in_app_purchase::InAppPurchaseCallback callback_; | ||||||
|  |   NSInteger quantity_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | - (id)initWithCallback:(const in_app_purchase::InAppPurchaseCallback&)callback | ||||||
|  |               quantity:(NSInteger)quantity; | ||||||
|  | 
 | ||||||
|  | - (void)purchaseProduct:(NSString*)productID; | ||||||
|  | 
 | ||||||
|  | @end | ||||||
|  | 
 | ||||||
|  | // ------------------------------- Implementation ----------------------------- | ||||||
|  | 
 | ||||||
|  | @implementation InAppPurchase | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Init with a callback. | ||||||
|  |  * | ||||||
|  |  * @param callback - The callback that will be called when the payment is added | ||||||
|  |  * to the queue. | ||||||
|  |  */ | ||||||
|  | - (id)initWithCallback:(const in_app_purchase::InAppPurchaseCallback&)callback | ||||||
|  |               quantity:(NSInteger)quantity { | ||||||
|  |   if ((self = [super init])) { | ||||||
|  |     callback_ = callback; | ||||||
|  |     quantity_ = quantity; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return self; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Start the in-app purchase process. | ||||||
|  |  * | ||||||
|  |  * @param productID - The id of the product to purchase (the id of | ||||||
|  |  * com.example.app.product1 is product1). | ||||||
|  |  */ | ||||||
|  | - (void)purchaseProduct:(NSString*)productID { | ||||||
|  |   // Retrieve the product information. (The products request retrieves, | ||||||
|  |   // information about valid products along with a list of the invalid product | ||||||
|  |   // identifiers, and then calls its delegate to process the result). | ||||||
|  |   SKProductsRequest* productsRequest; | ||||||
|  |   productsRequest = [[SKProductsRequest alloc] | ||||||
|  |       initWithProductIdentifiers:[NSSet setWithObject:productID]]; | ||||||
|  | 
 | ||||||
|  |   productsRequest.delegate = self; | ||||||
|  |   [productsRequest start]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Process product informations and start the payment. | ||||||
|  |  * | ||||||
|  |  * @param request - The product request. | ||||||
|  |  * @param response - The informations about the list of products. | ||||||
|  |  */ | ||||||
|  | - (void)productsRequest:(SKProductsRequest*)request | ||||||
|  |      didReceiveResponse:(SKProductsResponse*)response { | ||||||
|  |   // Get the first product. | ||||||
|  |   NSArray* products = response.products; | ||||||
|  |   SKProduct* product = [products count] == 1 ? [products firstObject] : nil; | ||||||
|  | 
 | ||||||
|  |   // Return if the product is not found or invalid. | ||||||
|  |   if (product == nil) { | ||||||
|  |     [self runCallback:false]; | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Start the payment process. | ||||||
|  |   [self checkout:product]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Submit a payment request to the App Store. | ||||||
|  |  * | ||||||
|  |  * @param product - The product to purchase. | ||||||
|  |  */ | ||||||
|  | - (void)checkout:(SKProduct*)product { | ||||||
|  |   // Add the payment to the transaction queue. (The observer will be called | ||||||
|  |   // when the transaction is finished). | ||||||
|  |   SKMutablePayment* payment = [SKMutablePayment paymentWithProduct:product]; | ||||||
|  |   payment.quantity = quantity_; | ||||||
|  | 
 | ||||||
|  |   [[SKPaymentQueue defaultQueue] addPayment:payment]; | ||||||
|  | 
 | ||||||
|  |   // Notify that the payment has been added to the queue with success. | ||||||
|  |   [self runCallback:true]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Submit a payment request to the App Store. | ||||||
|  |  * | ||||||
|  |  * @param product - The product to purchase. | ||||||
|  |  */ | ||||||
|  | - (void)runCallback:(bool)isProductValid { | ||||||
|  |   content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE, | ||||||
|  |                                    base::Bind(callback_, isProductValid)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @end | ||||||
|  | 
 | ||||||
|  | // ============================================================================ | ||||||
|  | //                             C++ in_app_purchase | ||||||
|  | // ============================================================================ | ||||||
|  | 
 | ||||||
|  | namespace in_app_purchase { | ||||||
|  | 
 | ||||||
|  | bool CanMakePayments() { | ||||||
|  |   return [SKPaymentQueue canMakePayments]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::string GetReceiptURL() { | ||||||
|  |   NSURL* receiptURL = [[NSBundle mainBundle] appStoreReceiptURL]; | ||||||
|  |   if (receiptURL != nil) { | ||||||
|  |     return [[receiptURL absoluteString] UTF8String]; | ||||||
|  |   } else { | ||||||
|  |     return ""; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void PurchaseProduct(const std::string& productID, | ||||||
|  |                      const int quantity, | ||||||
|  |                      const InAppPurchaseCallback& callback) { | ||||||
|  |   auto iap = | ||||||
|  |       [[InAppPurchase alloc] initWithCallback:callback quantity:quantity]; | ||||||
|  | 
 | ||||||
|  |   [iap purchaseProduct:base::SysUTF8ToNSString(productID)]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | }  // namespace in_app_purchase | ||||||
							
								
								
									
										41
									
								
								atom/browser/in_app_purchase_observer.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								atom/browser/in_app_purchase_observer.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | ||||||
|  | // Copyright (c) 2017 Amaplex Software, Inc.
 | ||||||
|  | // Use of this source code is governed by the MIT license that can be
 | ||||||
|  | // found in the LICENSE file.
 | ||||||
|  | 
 | ||||||
|  | #ifndef ATOM_BROWSER_UI_IN_APP_PURCHASE_OBSERVER_H_ | ||||||
|  | #define ATOM_BROWSER_UI_IN_APP_PURCHASE_OBSERVER_H_ | ||||||
|  | 
 | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | #include "base/callback.h" | ||||||
|  | 
 | ||||||
|  | namespace in_app_purchase { | ||||||
|  | 
 | ||||||
|  | // --------------------------- Structures ---------------------------
 | ||||||
|  | 
 | ||||||
|  | struct Payment { | ||||||
|  |   std::string productIdentifier = ""; | ||||||
|  |   int quantity = 1; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | struct Transaction { | ||||||
|  |   std::string transactionIdentifier = ""; | ||||||
|  |   std::string transactionDate = ""; | ||||||
|  |   std::string originalTransactionIdentifier = ""; | ||||||
|  |   int errorCode = 0; | ||||||
|  |   std::string errorMessage = ""; | ||||||
|  |   std::string transactionState = ""; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // --------------------------- Typedefs ---------------------------
 | ||||||
|  | 
 | ||||||
|  | typedef base::RepeatingCallback<void(const Payment, const Transaction)> | ||||||
|  |     InAppTransactionCallback; | ||||||
|  | 
 | ||||||
|  | // --------------------------- Functions ---------------------------
 | ||||||
|  | 
 | ||||||
|  | void AddTransactionObserver(const InAppTransactionCallback& callback); | ||||||
|  | 
 | ||||||
|  | }  // namespace in_app_purchase
 | ||||||
|  | 
 | ||||||
|  | #endif  // ATOM_BROWSER_UI_IN_APP_PURCHASE_OBSERVER_H_
 | ||||||
							
								
								
									
										182
									
								
								atom/browser/in_app_purchase_observer_mac.mm
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										182
									
								
								atom/browser/in_app_purchase_observer_mac.mm
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,182 @@ | ||||||
|  | // Copyright (c) 2017 Amaplex Software, Inc. | ||||||
|  | // Use of this source code is governed by the MIT license that can be | ||||||
|  | // found in the LICENSE file. | ||||||
|  | 
 | ||||||
|  | #include "atom/browser/in_app_purchase_observer.h" | ||||||
|  | #include "base/bind.h" | ||||||
|  | #include "base/strings/sys_string_conversions.h" | ||||||
|  | #include "content/public/browser/browser_thread.h" | ||||||
|  | 
 | ||||||
|  | #import <CommonCrypto/CommonCrypto.h> | ||||||
|  | #import <StoreKit/StoreKit.h> | ||||||
|  | 
 | ||||||
|  | // ============================================================================ | ||||||
|  | //                             InAppTransactionObserver | ||||||
|  | // ============================================================================ | ||||||
|  | 
 | ||||||
|  | @interface InAppTransactionObserver : NSObject<SKPaymentTransactionObserver> { | ||||||
|  |  @private | ||||||
|  |   in_app_purchase::InAppTransactionCallback callback_; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | - (id)initWithCallback: | ||||||
|  |     (const in_app_purchase::InAppTransactionCallback&)callback; | ||||||
|  | 
 | ||||||
|  | @end | ||||||
|  | 
 | ||||||
|  | @implementation InAppTransactionObserver | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Init with a callback. | ||||||
|  |  * | ||||||
|  |  * @param callback - The callback that will be called for each transaction | ||||||
|  |  * update. | ||||||
|  |  */ | ||||||
|  | - (id)initWithCallback: | ||||||
|  |     (const in_app_purchase::InAppTransactionCallback&)callback { | ||||||
|  |   if ((self = [super init])) { | ||||||
|  |     callback_ = callback; | ||||||
|  | 
 | ||||||
|  |     [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return self; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Run the callback in the browser thread. | ||||||
|  |  * | ||||||
|  |  * @param transaction - The transaction to pass to the callback. | ||||||
|  |  */ | ||||||
|  | - (void)runCallback:(SKPaymentTransaction*)transaction { | ||||||
|  |   if (transaction == nil) { | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   // Convert the payment. | ||||||
|  |   in_app_purchase::Payment paymentStruct; | ||||||
|  |   paymentStruct = [self skPaymentToStruct:transaction.payment]; | ||||||
|  | 
 | ||||||
|  |   // Convert the transaction. | ||||||
|  |   in_app_purchase::Transaction transactionStruct; | ||||||
|  |   transactionStruct = [self skPaymentTransactionToStruct:transaction]; | ||||||
|  | 
 | ||||||
|  |   // Send the callback to the browser thread. | ||||||
|  |   content::BrowserThread::PostTask( | ||||||
|  |       content::BrowserThread::UI, FROM_HERE, | ||||||
|  |       base::Bind(callback_, paymentStruct, transactionStruct)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Convert an NSDate to ISO String. | ||||||
|  |  * | ||||||
|  |  * @param date - The date to convert. | ||||||
|  |  */ | ||||||
|  | - (NSString*)dateToISOString:(NSDate*)date { | ||||||
|  |   NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init]; | ||||||
|  |   NSLocale* enUSPOSIXLocale = | ||||||
|  |       [NSLocale localeWithLocaleIdentifier:@"en_US_POSIX"]; | ||||||
|  |   [dateFormatter setLocale:enUSPOSIXLocale]; | ||||||
|  |   [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ssZZZZZ"]; | ||||||
|  | 
 | ||||||
|  |   return [dateFormatter stringFromDate:date]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Convert a SKPayment object to a Payment structure. | ||||||
|  |  * | ||||||
|  |  * @param payment - The SKPayment object to convert. | ||||||
|  |  */ | ||||||
|  | - (in_app_purchase::Payment)skPaymentToStruct:(SKPayment*)payment { | ||||||
|  |   in_app_purchase::Payment paymentStruct; | ||||||
|  | 
 | ||||||
|  |   if (payment == nil) { | ||||||
|  |     return paymentStruct; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (payment.productIdentifier != nil) { | ||||||
|  |     paymentStruct.productIdentifier = [payment.productIdentifier UTF8String]; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (payment.quantity >= 1) { | ||||||
|  |     paymentStruct.quantity = (int)payment.quantity; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return paymentStruct; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Convert a SKPaymentTransaction object to a Transaction structure. | ||||||
|  |  * | ||||||
|  |  * @param transaction - The SKPaymentTransaction object to convert. | ||||||
|  |  */ | ||||||
|  | - (in_app_purchase::Transaction)skPaymentTransactionToStruct: | ||||||
|  |     (SKPaymentTransaction*)transaction { | ||||||
|  |   in_app_purchase::Transaction transactionStruct; | ||||||
|  | 
 | ||||||
|  |   if (transaction == nil) { | ||||||
|  |     return transactionStruct; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (transaction.transactionIdentifier != nil) { | ||||||
|  |     transactionStruct.transactionIdentifier = | ||||||
|  |         [transaction.transactionIdentifier UTF8String]; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (transaction.transactionDate != nil) { | ||||||
|  |     transactionStruct.transactionDate = | ||||||
|  |         [[self dateToISOString:transaction.transactionDate] UTF8String]; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (transaction.originalTransaction != nil) { | ||||||
|  |     transactionStruct.originalTransactionIdentifier = | ||||||
|  |         [transaction.originalTransaction.transactionIdentifier UTF8String]; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (transaction.error != nil) { | ||||||
|  |     transactionStruct.errorCode = (int)transaction.error.code; | ||||||
|  |     transactionStruct.errorMessage = | ||||||
|  |         [[transaction.error localizedDescription] UTF8String]; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (transaction.transactionState < 5) { | ||||||
|  |     transactionStruct.transactionState = [[@[ | ||||||
|  |       @"SKPaymentTransactionStatePurchasing", | ||||||
|  |       @"SKPaymentTransactionStatePurchased", @"SKPaymentTransactionStateFailed", | ||||||
|  |       @"SKPaymentTransactionStateRestored", | ||||||
|  |       @"SKPaymentTransactionStateDeferred" | ||||||
|  |     ] objectAtIndex:transaction.transactionState] UTF8String]; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return transactionStruct; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #pragma mark - | ||||||
|  | #pragma mark SKPaymentTransactionObserver methods | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Executed when a transaction is updated. | ||||||
|  |  * | ||||||
|  |  * @param queue - The payment queue. | ||||||
|  |  * @param transactions - The list of transactions updated. | ||||||
|  |  */ | ||||||
|  | - (void)paymentQueue:(SKPaymentQueue*)queue | ||||||
|  |     updatedTransactions:(NSArray*)transactions { | ||||||
|  |   for (SKPaymentTransaction* transaction in transactions) { | ||||||
|  |     [self runCallback:transaction]; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | @end | ||||||
|  | 
 | ||||||
|  | // ============================================================================ | ||||||
|  | //                             C++ in_app_purchase | ||||||
|  | // ============================================================================ | ||||||
|  | 
 | ||||||
|  | namespace in_app_purchase { | ||||||
|  | 
 | ||||||
|  | void AddTransactionObserver(const InAppTransactionCallback& callback) { | ||||||
|  |   [[InAppTransactionObserver alloc] initWithCallback:callback]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | }  // namespace in_app_purchase | ||||||
|  | @ -40,6 +40,7 @@ REFERENCE_MODULE(atom_browser_desktop_capturer); | ||||||
| REFERENCE_MODULE(atom_browser_dialog); | REFERENCE_MODULE(atom_browser_dialog); | ||||||
| REFERENCE_MODULE(atom_browser_download_item); | REFERENCE_MODULE(atom_browser_download_item); | ||||||
| REFERENCE_MODULE(atom_browser_global_shortcut); | REFERENCE_MODULE(atom_browser_global_shortcut); | ||||||
|  | REFERENCE_MODULE(atom_browser_in_app_purchase); | ||||||
| REFERENCE_MODULE(atom_browser_menu); | REFERENCE_MODULE(atom_browser_menu); | ||||||
| REFERENCE_MODULE(atom_browser_net); | REFERENCE_MODULE(atom_browser_net); | ||||||
| REFERENCE_MODULE(atom_browser_power_monitor); | REFERENCE_MODULE(atom_browser_power_monitor); | ||||||
|  |  | ||||||
							
								
								
									
										36
									
								
								docs/api/in-app-purchase.md
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								docs/api/in-app-purchase.md
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,36 @@ | ||||||
|  | # inAppPurchase  _macOS_ | ||||||
|  | 
 | ||||||
|  | Your application should add a listener before to purchase a product. If there are no listener attached to the queue, the payment queue does not synchronize its list of pending transactions with the Apple App Store. | ||||||
|  | 
 | ||||||
|  | ## Methods  | ||||||
|  | 
 | ||||||
|  | The `inAppPurchase` module has the following methods: | ||||||
|  | 
 | ||||||
|  | ### `inAppPurchase.addTransactionListener(listener)` | ||||||
|  | 
 | ||||||
|  | * `listener` Function -  Called when transactions are updated by the payment queue. | ||||||
|  |   * `payment` Object | ||||||
|  |     * `productIdentifier` String | ||||||
|  |     * `quantity` Integer | ||||||
|  |   * `transaction` Object | ||||||
|  |     * `transactionIdentifier` String | ||||||
|  |     * `transactionDate` String | ||||||
|  |     * `originalTransactionIdentifier` String | ||||||
|  |     * `transactionState` String - The transaction sate (`"SKPaymentTransactionStatePurchasing"`, `"SKPaymentTransactionStatePurchased"`, `"SKPaymentTransactionStateFailed"`, `"SKPaymentTransactionStateRestored"`, or `"SKPaymentTransactionStateDeferred"`) | ||||||
|  |     * `errorCode` Integer | ||||||
|  |     * `errorMessage` String | ||||||
|  |     | ||||||
|  | 
 | ||||||
|  | ### `inAppPurchase.purchaseProduct(productID, quantity, callback)` | ||||||
|  | * `productID` String - The id of the product to purchase. (the id of `com.example.app.product1` is `product1`). | ||||||
|  | * `quantity` Integer (optional) - The number of items the user wants to purchase. | ||||||
|  | * `callback` Function (optional) - The callback called when the payment is added to the PaymentQueue. (You should add a listener with `inAppPurchase.addTransactionsListener` to get the transaction status). | ||||||
|  |   * `isProductValid` Boolean - Determine if the product is valid and added to the payment queue. | ||||||
|  | 
 | ||||||
|  | ### `inAppPurchase.canMakePayments()` | ||||||
|  | 
 | ||||||
|  | Returns `true` if the user can make a payment and `false` otherwise. | ||||||
|  | 
 | ||||||
|  | ### `inAppPurchase.getReceiptURL()` | ||||||
|  | 
 | ||||||
|  | Returns `String`, the path to the receipt. | ||||||
|  | @ -591,6 +591,7 @@ | ||||||
|               '$(SDKROOT)/System/Library/Frameworks/Security.framework', |               '$(SDKROOT)/System/Library/Frameworks/Security.framework', | ||||||
|               '$(SDKROOT)/System/Library/Frameworks/SecurityInterface.framework', |               '$(SDKROOT)/System/Library/Frameworks/SecurityInterface.framework', | ||||||
|               '$(SDKROOT)/System/Library/Frameworks/ServiceManagement.framework', |               '$(SDKROOT)/System/Library/Frameworks/ServiceManagement.framework', | ||||||
|  |               '$(SDKROOT)/System/Library/Frameworks/StoreKit.framework', | ||||||
|             ], |             ], | ||||||
|           }, |           }, | ||||||
|           'mac_bundle': 1, |           'mac_bundle': 1, | ||||||
|  |  | ||||||
|  | @ -20,6 +20,7 @@ | ||||||
|       'lib/browser/api/exports/electron.js', |       'lib/browser/api/exports/electron.js', | ||||||
|       'lib/browser/api/global-shortcut.js', |       'lib/browser/api/global-shortcut.js', | ||||||
|       'lib/browser/api/ipc-main.js', |       'lib/browser/api/ipc-main.js', | ||||||
|  |       'lib/browser/api/in-app-purchase.js', | ||||||
|       'lib/browser/api/menu-item-roles.js', |       'lib/browser/api/menu-item-roles.js', | ||||||
|       'lib/browser/api/menu-item.js', |       'lib/browser/api/menu-item.js', | ||||||
|       'lib/browser/api/menu.js', |       'lib/browser/api/menu.js', | ||||||
|  | @ -120,6 +121,8 @@ | ||||||
|       'atom/browser/api/atom_api_download_item.h', |       'atom/browser/api/atom_api_download_item.h', | ||||||
|       'atom/browser/api/atom_api_global_shortcut.cc', |       'atom/browser/api/atom_api_global_shortcut.cc', | ||||||
|       'atom/browser/api/atom_api_global_shortcut.h', |       'atom/browser/api/atom_api_global_shortcut.h', | ||||||
|  |       'atom/browser/api/atom_api_in_app_purchase.cc', | ||||||
|  |       'atom/browser/api/atom_api_in_app_purchase.h', | ||||||
|       'atom/browser/api/atom_api_menu.cc', |       'atom/browser/api/atom_api_menu.cc', | ||||||
|       'atom/browser/api/atom_api_menu.h', |       'atom/browser/api/atom_api_menu.h', | ||||||
|       'atom/browser/api/atom_api_menu_mac.h', |       'atom/browser/api/atom_api_menu_mac.h', | ||||||
|  | @ -184,6 +187,10 @@ | ||||||
|       'atom/browser/atom_browser_context.h', |       'atom/browser/atom_browser_context.h', | ||||||
|       'atom/browser/atom_download_manager_delegate.cc', |       'atom/browser/atom_download_manager_delegate.cc', | ||||||
|       'atom/browser/atom_download_manager_delegate.h', |       'atom/browser/atom_download_manager_delegate.h', | ||||||
|  |       'atom/browser/in_app_purchase.h', | ||||||
|  |       'atom/browser/in_app_purchase_mac.mm', | ||||||
|  |       'atom/browser/in_app_purchase_observer.h', | ||||||
|  |       'atom/browser/in_app_purchase_observer_mac.mm', | ||||||
|       'atom/browser/atom_browser_main_parts.cc', |       'atom/browser/atom_browser_main_parts.cc', | ||||||
|       'atom/browser/atom_browser_main_parts.h', |       'atom/browser/atom_browser_main_parts.h', | ||||||
|       'atom/browser/atom_browser_main_parts_mac.mm', |       'atom/browser/atom_browser_main_parts_mac.mm', | ||||||
|  |  | ||||||
							
								
								
									
										46
									
								
								lib/browser/api/in-app-purchase.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								lib/browser/api/in-app-purchase.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,46 @@ | ||||||
|  | 'use strict' | ||||||
|  | 
 | ||||||
|  | const binding = process.atomBinding('in_app_purchase') | ||||||
|  | const v8Util = process.atomBinding('v8_util') | ||||||
|  | 
 | ||||||
|  | module.exports = { | ||||||
|  | 
 | ||||||
|  |   canMakePayments: function() { | ||||||
|  |     return binding.canMakePayments(); | ||||||
|  |   }, | ||||||
|  | 
 | ||||||
|  |   getReceiptURL: function() { | ||||||
|  |     return binding.getReceiptURL(); | ||||||
|  |   }, | ||||||
|  | 
 | ||||||
|  |   purchaseProduct: function(productID, quantity, callback) { | ||||||
|  | 
 | ||||||
|  |     if (typeof productID !== 'string') { | ||||||
|  |       throw new TypeError('productID must be a string') | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (typeof quantity !== 'number') { | ||||||
|  |       quantity = 1 | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (typeof callback !== 'function') { | ||||||
|  |       callback = function() {}; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return binding.purchaseProduct(productID, quantity, callback) | ||||||
|  |   }, | ||||||
|  | 
 | ||||||
|  |   addTransactionListener: function(callback) { | ||||||
|  | 
 | ||||||
|  |     if (typeof callback !== 'function') { | ||||||
|  |       throw new TypeError('callback must be a function') | ||||||
|  |     } | ||||||
|  |     return binding.addTransactionListener(callback) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  |                  // Mark standard asynchronous functions.
 | ||||||
|  |                  v8Util.setHiddenValue( | ||||||
|  |                      module.exports.purchaseProduct, 'asynchronous', true) | ||||||
|  | v8Util.setHiddenValue( | ||||||
|  |     module.exports.addTransactionListener, 'asynchronous', true) | ||||||
|  | @ -8,6 +8,7 @@ module.exports = [ | ||||||
|   {name: 'dialog', file: 'dialog'}, |   {name: 'dialog', file: 'dialog'}, | ||||||
|   {name: 'globalShortcut', file: 'global-shortcut'}, |   {name: 'globalShortcut', file: 'global-shortcut'}, | ||||||
|   {name: 'ipcMain', file: 'ipc-main'}, |   {name: 'ipcMain', file: 'ipc-main'}, | ||||||
|  |   {name: 'inAppPurchase', file: 'in-app-purchase'}, | ||||||
|   {name: 'Menu', file: 'menu'}, |   {name: 'Menu', file: 'menu'}, | ||||||
|   {name: 'MenuItem', file: 'menu-item'}, |   {name: 'MenuItem', file: 'menu-item'}, | ||||||
|   {name: 'net', file: 'net'}, |   {name: 'net', file: 'net'}, | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Adrien Fery
				Adrien Fery