diff --git a/RMStore/RMStore.h b/RMStore/RMStore.h index 1a7a6622..2959f614 100755 --- a/RMStore/RMStore.h +++ b/RMStore/RMStore.h @@ -48,6 +48,11 @@ extern NSInteger const RMStoreErrorCodeUnableToCompleteVerification; /// @name Calling StoreKit ///--------------------------------------------- +/** + This block should be called by a user in order to finish transaction + */ +typedef void (^RMStoreFinishTransactionBlock)(); + /** Returns whether the user is allowed to make payments. */ + (BOOL)canMakePayments; @@ -63,7 +68,7 @@ extern NSInteger const RMStoreErrorCodeUnableToCompleteVerification; @param failureBlock The block to be called if the payment fails or there isn't any product with the given identifier. Can be `nil`. */ - (void)addPayment:(NSString*)productIdentifier - success:(void (^)(SKPaymentTransaction *transaction))successBlock + success:(void (^)(SKPaymentTransaction *transaction, RMStoreFinishTransactionBlock finishBlock))successBlock failure:(void (^)(SKPaymentTransaction *transaction, NSError *error))failureBlock; /** Request payment of the product with the given product identifier. `successBlock` will be called if the payment is successful, `failureBlock` if it isn't. @@ -75,7 +80,7 @@ extern NSInteger const RMStoreErrorCodeUnableToCompleteVerification; */ - (void)addPayment:(NSString*)productIdentifier user:(NSString*)userIdentifier - success:(void (^)(SKPaymentTransaction *transaction))successBlock + success:(void (^)(SKPaymentTransaction *transaction, RMStoreFinishTransactionBlock finishBlock))successBlock failure:(void (^)(SKPaymentTransaction *transaction, NSError *error))failureBlock __attribute__((availability(ios,introduced=7.0))); /** Request localized information about a set of products from the Apple App Store. diff --git a/RMStore/RMStore.m b/RMStore/RMStore.m index 166d648a..a10c3349 100755 --- a/RMStore/RMStore.m +++ b/RMStore/RMStore.m @@ -57,7 +57,7 @@ #endif typedef void (^RMSKPaymentTransactionFailureBlock)(SKPaymentTransaction *transaction, NSError *error); -typedef void (^RMSKPaymentTransactionSuccessBlock)(SKPaymentTransaction *transaction); +typedef void (^RMSKPaymentTransactionSuccessBlock)(SKPaymentTransaction *transaction, RMStoreFinishTransactionBlock finishBlock); typedef void (^RMSKProductsRequestFailureBlock)(NSError *error); typedef void (^RMSKProductsRequestSuccessBlock)(NSArray *products, NSArray *invalidIdentifiers); typedef void (^RMStoreFailureBlock)(NSError *error); @@ -188,7 +188,7 @@ - (void)addPayment:(NSString*)productIdentifier } - (void)addPayment:(NSString*)productIdentifier - success:(void (^)(SKPaymentTransaction *transaction))successBlock + success:(void (^)(SKPaymentTransaction *transaction, RMStoreFinishTransactionBlock finishBlock))successBlock failure:(void (^)(SKPaymentTransaction *transaction, NSError *error))failureBlock { [self addPayment:productIdentifier user:nil success:successBlock failure:failureBlock]; @@ -196,7 +196,7 @@ - (void)addPayment:(NSString*)productIdentifier - (void)addPayment:(NSString*)productIdentifier user:(NSString*)userIdentifier - success:(void (^)(SKPaymentTransaction *transaction))successBlock + success:(void (^)(SKPaymentTransaction *transaction, RMStoreFinishTransactionBlock finishBlock))successBlock failure:(void (^)(SKPaymentTransaction *transaction, NSError *error))failureBlock { SKProduct *product = [self productForIdentifier:productIdentifier]; @@ -631,14 +631,21 @@ - (void)didDownloadSelfHostedContentForTransaction:(SKPaymentTransaction *)trans - (void)finishTransaction:(SKPaymentTransaction *)transaction queue:(SKPaymentQueue*)queue { SKPayment *payment = transaction.payment; - NSString* productIdentifier = payment.productIdentifier; - [queue finishTransaction:transaction]; - [self.transactionPersistor persistTransaction:transaction]; + NSString* productIdentifier = payment.productIdentifier; + + RMStoreFinishTransactionBlock finishBlock = ^{ + [queue finishTransaction:transaction]; + [self.transactionPersistor persistTransaction:transaction]; + }; RMAddPaymentParameters *wrapper = [self popAddPaymentParametersForIdentifier:productIdentifier]; if (wrapper.successBlock != nil) { - wrapper.successBlock(transaction); + wrapper.successBlock(transaction, finishBlock); + } + else + { + finishBlock(); } [self postNotificationWithName:RMSKPaymentTransactionFinished transaction:transaction userInfoExtras:nil]; diff --git a/RMStoreDemo/RMStoreViewController.m b/RMStoreDemo/RMStoreViewController.m index efd03232..7a1eba61 100644 --- a/RMStoreDemo/RMStoreViewController.m +++ b/RMStoreDemo/RMStoreViewController.m @@ -82,7 +82,11 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath NSString *productID = [_products objectAtIndex:indexPath.row]; [UIApplication sharedApplication].networkActivityIndicatorVisible = YES; - [[RMStore defaultStore] addPayment:productID success:^(SKPaymentTransaction *transaction) { + [[RMStore defaultStore] addPayment:productID success:^(SKPaymentTransaction *transaction, RMStoreFinishTransactionBlock finishBlock) { + + // Finish transaction + finishBlock(); + [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; } failure:^(SKPaymentTransaction *transaction, NSError *error) { [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; diff --git a/RMStoreTests/RMStoreTests.m b/RMStoreTests/RMStoreTests.m index 61093b0a..b84ba54f 100644 --- a/RMStoreTests/RMStoreTests.m +++ b/RMStoreTests/RMStoreTests.m @@ -143,10 +143,11 @@ - (void)testAddPayment_UnknownProduct_Nil_Nil - (void)testAddPayment_UnknownProduct_Block_Block { __block BOOL failureBlockCalled; - [_store addPayment:@"test" success:^(SKPaymentTransaction *transaction) { + [_store addPayment:@"test" success:^(SKPaymentTransaction *transaction, RMStoreFinishTransactionBlock finishBlock) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Warc-retain-cycles" XCTFail(@"Success block"); + finishBlock(); #pragma GCC diagnostic pop } failure:^(SKPaymentTransaction *transaction, NSError *error) { failureBlockCalled = YES; @@ -275,7 +276,7 @@ - (void)testPaymentQueueUpdatedDownloads_Empty - (void)testPaymentQueueUpdatedDownloads_Active { SKIP_IF_VERSION(NSFoundationVersionNumber_iOS_5_1) id download = [self mockDownloadWithState:SKDownloadStateActive]; - [[[download stub] andReturnValue:OCMOCK_VALUE(0.5f)] progress]; + [(SKDownload *)[[download stub] andReturnValue:OCMOCK_VALUE(0.5f)] progress]; id transaction = [self mockPaymentTransactionWithState:SKPaymentTransactionStatePurchased downloads:@[download]]; NSString *productID = [[transaction payment] productIdentifier]; @@ -288,7 +289,7 @@ - (void)testPaymentQueueUpdatedDownloads_Active XCTAssertEqualObjects(download, returnedDownload); XCTAssertEqualObjects(transaction, returnedTransaction); XCTAssertTrue([productID isEqualToString:returnedProductID]); - XCTAssertTrue([download progress] == downloadProgress); + XCTAssertTrue([(SKDownload *)download progress] == downloadProgress); return YES; }]]; [_store addStoreObserver:_observer]; @@ -691,7 +692,8 @@ - (void)testPaymentQueueUpdatedTransactions_Purchased__NoVerifier_Blocks id product = [OCMockObject mockForClass:[SKProduct class]]; [[[product stub] andReturn:@"test"] productIdentifier]; (_store.products)[@"test"] = product; - [_store addPayment:@"test" success:^(SKPaymentTransaction *transaction) { + [_store addPayment:@"test" success:^(SKPaymentTransaction *transaction, RMStoreFinishTransactionBlock finishBlock) { + finishBlock(); XCTAssertEqualObjects(transaction, originalTransaction, @""); } failure:^(SKPaymentTransaction *transaction, NSError *error) { XCTFail(@""); @@ -926,7 +928,8 @@ - (void)testPaymentQueueUpdatedTransactions_Failed__Blocks id product = [OCMockObject mockForClass:[SKProduct class]]; [[[product stub] andReturn:@"test"] productIdentifier]; (_store.products)[@"test"] = product; - [_store addPayment:@"test" success:^(SKPaymentTransaction *transaction) { + [_store addPayment:@"test" success:^(SKPaymentTransaction *transaction,RMStoreFinishTransactionBlock finishBlock) { + finishBlock(); XCTFail(@""); } failure:^(SKPaymentTransaction *transaction, NSError *error) { XCTAssertEqualObjects(transaction, originalTransaction, @"");