196 lines
		
	
	
	
		
			5.5 KiB
			
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			196 lines
		
	
	
	
		
			5.5 KiB
			
		
	
	
	
		
			Text
		
	
	
	
	
	
// 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 "shell/browser/mac/in_app_purchase_observer.h"
 | 
						|
 | 
						|
#include <vector>
 | 
						|
 | 
						|
#include "base/bind.h"
 | 
						|
#include "base/strings/sys_string_conversions.h"
 | 
						|
#include "base/task/post_task.h"
 | 
						|
#include "content/public/browser/browser_task_traits.h"
 | 
						|
#include "content/public/browser/browser_thread.h"
 | 
						|
 | 
						|
#import <CommonCrypto/CommonCrypto.h>
 | 
						|
#import <StoreKit/StoreKit.h>
 | 
						|
 | 
						|
// ============================================================================
 | 
						|
//                             InAppTransactionObserver
 | 
						|
// ============================================================================
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
using InAppTransactionCallback = base::RepeatingCallback<void(
 | 
						|
    const std::vector<in_app_purchase::Transaction>&)>;
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
@interface InAppTransactionObserver : NSObject <SKPaymentTransactionObserver> {
 | 
						|
 @private
 | 
						|
  InAppTransactionCallback callback_;
 | 
						|
}
 | 
						|
 | 
						|
- (id)initWithCallback:(const InAppTransactionCallback&)callback;
 | 
						|
 | 
						|
@end
 | 
						|
 | 
						|
@implementation InAppTransactionObserver
 | 
						|
 | 
						|
/**
 | 
						|
 * Init with a callback.
 | 
						|
 *
 | 
						|
 * @param callback - The callback that will be called for each transaction
 | 
						|
 * update.
 | 
						|
 */
 | 
						|
- (id)initWithCallback:(const InAppTransactionCallback&)callback {
 | 
						|
  if ((self = [super init])) {
 | 
						|
    callback_ = callback;
 | 
						|
 | 
						|
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
 | 
						|
  }
 | 
						|
 | 
						|
  return self;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Cleanup.
 | 
						|
 */
 | 
						|
- (void)dealloc {
 | 
						|
  [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
 | 
						|
  [super dealloc];
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * Run the callback in the browser thread.
 | 
						|
 *
 | 
						|
 * @param transaction - The transaction to pass to the callback.
 | 
						|
 */
 | 
						|
- (void)runCallback:(NSArray*)transactions {
 | 
						|
  // Convert the transaction.
 | 
						|
  std::vector<in_app_purchase::Transaction> converted;
 | 
						|
  converted.reserve([transactions count]);
 | 
						|
  for (SKPaymentTransaction* transaction in transactions) {
 | 
						|
    converted.push_back([self skPaymentTransactionToStruct:transaction]);
 | 
						|
  }
 | 
						|
 | 
						|
  // Send the callback to the browser thread.
 | 
						|
  base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
 | 
						|
                           base::BindOnce(callback_, converted));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
 * 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.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.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 =
 | 
						|
        [[@[ @"purchasing", @"purchased", @"failed", @"restored", @"deferred" ]
 | 
						|
            objectAtIndex:transaction.transactionState] UTF8String];
 | 
						|
  }
 | 
						|
 | 
						|
  if (transaction.payment != nil) {
 | 
						|
    transactionStruct.payment = [self skPaymentToStruct:transaction.payment];
 | 
						|
  }
 | 
						|
 | 
						|
  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 {
 | 
						|
  [self runCallback:transactions];
 | 
						|
}
 | 
						|
 | 
						|
@end
 | 
						|
 | 
						|
// ============================================================================
 | 
						|
//                             C++ in_app_purchase
 | 
						|
// ============================================================================
 | 
						|
 | 
						|
namespace in_app_purchase {
 | 
						|
 | 
						|
Transaction::Transaction() = default;
 | 
						|
Transaction::Transaction(const Transaction&) = default;
 | 
						|
Transaction::~Transaction() = default;
 | 
						|
 | 
						|
TransactionObserver::TransactionObserver() : weak_ptr_factory_(this) {
 | 
						|
  obeserver_ = [[InAppTransactionObserver alloc]
 | 
						|
      initWithCallback:base::BindRepeating(
 | 
						|
                           &TransactionObserver::OnTransactionsUpdated,
 | 
						|
                           weak_ptr_factory_.GetWeakPtr())];
 | 
						|
}
 | 
						|
 | 
						|
TransactionObserver::~TransactionObserver() {
 | 
						|
  [obeserver_ release];
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace in_app_purchase
 |