From eb50007c510720028a5559bc02ad3d216d590d11 Mon Sep 17 00:00:00 2001 From: Sibelius Seraphini Date: Fri, 23 Dec 2016 11:31:36 -0200 Subject: [PATCH 01/35] add info of how to do monthly subscription with this package (#56) --- Readme.md | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 394329c..890f951 100644 --- a/Readme.md +++ b/Readme.md @@ -16,8 +16,8 @@ A react-native wrapper for handling in-app purchases. 2. Install with rnpm: `rnpm install react-native-in-app-utils` -3. Whenever you want to use it within React code now you just have to do: `var InAppUtils = require('NativeModules').InAppUtils;` - or for ES6: +3. Whenever you want to use it within React code now you just have to do: `var InAppUtils = require('NativeModules').InAppUtils;` + or for ES6: ``` import { NativeModules } from 'react-native' import { InAppUtils } from 'NativeModules' @@ -124,3 +124,28 @@ To test your in-app purchases, you have to *run the app on an actual device*. Us 2. Run your app on an actual iOS device. To do so, first [run the react-native server on the local network](https://facebook.github.io/react-native/docs/runningondevice.html) instead of localhost. Then connect your iDevice to your Mac via USB and [select it from the list of available devices and simulators](https://i.imgur.com/6ifsu8Q.jpg) in the very top bar. (Next to the build and stop buttons) 3. Open the app and buy something with your Sandbox Tester Apple Account! + +## Monthly Subscriptions + +You can check if the receipt is still valid using [iap-receipt-validator](https://github.com/sibelius/iap-receipt-validator) package + +```jsx +import iapReceiptValidator from 'iap-receipt-validator'; + +const password = 'b212549818ff42ecb65aa45c'; // Shared Secret from iTunes connect +const production = false; // use sandbox or production url for validation +const validateReceipt = iapReceiptValidator(password, production); + +async validate(receiptData) { + try { + const validationData = await validateReceipt(receiptData); + + // check if Auto-Renewable Subscription is still valid + // validationData['latest_receipt_info'][0].expires_date > today + } catch(err) { + console.log(err.valid, err.error, err.message) + } +} +``` + +This works on both react native and backend server, you should setup a cron job that run everyday to check if the receipt is still valid From e81612faefa4b9c03f28416cdec3f2722a7083aa Mon Sep 17 00:00:00 2001 From: Andrew Nicolaou Date: Sun, 15 Jan 2017 18:22:13 +0100 Subject: [PATCH 02/35] Add MIT license to package.json (#59) This allows tools like [`yarn licenses`](https://yarnpkg.com/en/docs/cli/licenses) to automatically output the MIT license. --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index ae44395..5c79076 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "email": "jain_chirag04@yahoo.com", "url": "http://chiragjain.tumblr.com" }, + "license": "MIT", "repository": { "type": "git", "url": "git@github.com:chirag04/react-native-in-app-utils.git" From 33bdaddcd44c701e33b2a1ae13b59c89446a0c78 Mon Sep 17 00:00:00 2001 From: "Sat Mandir S. Khalsa" Date: Wed, 18 Jan 2017 12:02:09 -0800 Subject: [PATCH 03/35] Update iOS headers for RN 0.40 (#61) * Update iOS headers for RN 0.40 * Update iOS headers for RN 0.40 * remove header search paths --- InAppUtils.xcodeproj/project.pbxproj | 4 ---- InAppUtils/InAppUtils.h | 4 ++-- InAppUtils/InAppUtils.m | 4 ++-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/InAppUtils.xcodeproj/project.pbxproj b/InAppUtils.xcodeproj/project.pbxproj index 2d99fb0..dad2eb5 100644 --- a/InAppUtils.xcodeproj/project.pbxproj +++ b/InAppUtils.xcodeproj/project.pbxproj @@ -306,8 +306,6 @@ HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/node_modules/react-native/React/**", - "$(SRCROOT)/../react-native/React/**", ); OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -321,8 +319,6 @@ HEADER_SEARCH_PATHS = ( "$(inherited)", /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, - "$(SRCROOT)/node_modules/react-native/React/**", - "$(SRCROOT)/../react-native/React/**", ); OTHER_LDFLAGS = "-ObjC"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/InAppUtils/InAppUtils.h b/InAppUtils/InAppUtils.h index 7e1f805..a3a95ff 100644 --- a/InAppUtils/InAppUtils.h +++ b/InAppUtils/InAppUtils.h @@ -1,8 +1,8 @@ #import #import -#import "RCTBridgeModule.h" +#import @interface InAppUtils : NSObject -@end \ No newline at end of file +@end diff --git a/InAppUtils/InAppUtils.m b/InAppUtils/InAppUtils.m index a463173..90613c2 100644 --- a/InAppUtils/InAppUtils.m +++ b/InAppUtils/InAppUtils.m @@ -1,7 +1,7 @@ #import "InAppUtils.h" #import -#import "RCTLog.h" -#import "RCTUtils.h" +#import +#import #import "SKProduct+StringPrice.h" @implementation InAppUtils From dd479308ef569770cbe853358f904784a80d7f77 Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Thu, 19 Jan 2017 01:48:28 +0530 Subject: [PATCH 04/35] 5.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5c79076..56ed2bc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-in-app-utils", - "version": "4.0.0", + "version": "5.0.0", "description": "A react-native wrapper for handling in-app payments.", "author": { "name": "Chirag Jain", From c8fe1b75328de586de3dcead3f9920f627c20208 Mon Sep 17 00:00:00 2001 From: Chirag Date: Thu, 19 Jan 2017 01:51:56 +0530 Subject: [PATCH 05/35] add note about breaking change in rn 40. --- Readme.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Readme.md b/Readme.md index 890f951..a0bdd83 100644 --- a/Readme.md +++ b/Readme.md @@ -2,6 +2,11 @@ A react-native wrapper for handling in-app purchases. +# Breaking Change + +- Due to a major breaking change in RN 0.40+, Use v5.x of this lib when installing from npm. + + # Notes - You need an Apple Developer account to use in-app purchases. From 940ff3d0d6d5c9e0e297ffa18b010ea069f9cb49 Mon Sep 17 00:00:00 2001 From: Raymond Penners Date: Mon, 30 Jan 2017 17:00:27 +0100 Subject: [PATCH 06/35] Expose transaction receipt (#58) --- InAppUtils/InAppUtils.m | 6 ++++-- Readme.md | 20 +++++++++++--------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/InAppUtils/InAppUtils.m b/InAppUtils/InAppUtils.m index 90613c2..3825066 100644 --- a/InAppUtils/InAppUtils.m +++ b/InAppUtils/InAppUtils.m @@ -49,7 +49,8 @@ - (void)paymentQueue:(SKPaymentQueue *)queue if (callback) { NSDictionary *purchase = @{ @"transactionIdentifier": transaction.transactionIdentifier, - @"productIdentifier": transaction.payment.productIdentifier + @"productIdentifier": transaction.payment.productIdentifier, + @"transactionReceipt": [[transaction transactionReceipt] base64EncodedStringWithOptions:0] }; callback(@[[NSNull null], purchase]); [_callbacks removeObjectForKey:key]; @@ -119,7 +120,8 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue NSDictionary *purchase = @{ @"originalTransactionIdentifier": transaction.originalTransaction.transactionIdentifier, @"transactionIdentifier": transaction.transactionIdentifier, - @"productIdentifier": transaction.payment.productIdentifier + @"productIdentifier": transaction.payment.productIdentifier, + @"transactionReceipt": [[transaction transactionReceipt] base64EncodedStringWithOptions:0] }; [productsArrayForJS addObject:purchase]; diff --git a/Readme.md b/Readme.md index a0bdd83..64ec27a 100644 --- a/Readme.md +++ b/Readme.md @@ -76,10 +76,11 @@ InAppUtils.purchaseProduct(productIdentifier, (error, response) => { **Response fields:** -| Field | Type | Description | -| --------------------- | ------ | -------------------------- | -| transactionIdentifier | string | The transaction identifier | -| productIdentifier | string | The product identifier | +| Field | Type | Description | +| --------------------- | ------ | -------------------------------------------------- | +| transactionIdentifier | string | The transaction identifier | +| productIdentifier | string | The product identifier | +| transactionReceipt | string | The transaction receipt as a base64 encoded string | ### Restore payments @@ -97,11 +98,12 @@ InAppUtils.restorePurchases((error, response)=> { **Response:** An array of transactions with the following fields: -| Field | Type | Description | -| --------------------- | ------ | -------------------------- | -| originalTransactionIdentifier | string | The original transaction identifier | -| transactionIdentifier | string | The transaction identifier | -| productIdentifier | string | The product identifier | +| Field | Type | Description | +| ------------------------------ | ------ | -------------------------------------------------- | +| originalTransactionIdentifier | string | The original transaction identifier | +| transactionIdentifier | string | The transaction identifier | +| productIdentifier | string | The product identifier | +| transactionReceipt | string | The transaction receipt as a base64 encoded string | ### Receipts From 5254e3918199f75f90adce03e4a6fc35864f1919 Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Mon, 30 Jan 2017 11:01:09 -0500 Subject: [PATCH 07/35] 5.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 56ed2bc..7d8eb16 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-in-app-utils", - "version": "5.0.0", + "version": "5.1.0", "description": "A react-native wrapper for handling in-app payments.", "author": { "name": "Chirag Jain", From 0424a4957bf7707680a1417902d0a3261f986c47 Mon Sep 17 00:00:00 2001 From: Martin Lundberg Date: Thu, 16 Feb 2017 13:04:00 +0100 Subject: [PATCH 08/35] Update Readme.md (#68) --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 64ec27a..f903245 100644 --- a/Readme.md +++ b/Readme.md @@ -25,7 +25,7 @@ A react-native wrapper for handling in-app purchases. or for ES6: ``` import { NativeModules } from 'react-native' - import { InAppUtils } from 'NativeModules' +   const { InAppUtils } = NativeModules ``` From 59a1d5e21a087eed4917c1ac3ca5bdbc2307cbfa Mon Sep 17 00:00:00 2001 From: Scott Kyle Date: Fri, 17 Feb 2017 18:18:29 -0800 Subject: [PATCH 09/35] Expose original transaction date (#69) * Expose original transaction date (#66) * Add transactionDate property --- InAppUtils/InAppUtils.m | 17 +++++++++++------ Readme.md | 3 +++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/InAppUtils/InAppUtils.m b/InAppUtils/InAppUtils.m index 3825066..f41e7a2 100644 --- a/InAppUtils/InAppUtils.m +++ b/InAppUtils/InAppUtils.m @@ -48,6 +48,7 @@ - (void)paymentQueue:(SKPaymentQueue *)queue RCTResponseSenderBlock callback = _callbacks[key]; if (callback) { NSDictionary *purchase = @{ + @"transactionDate": @(transaction.transactionDate.timeIntervalSince1970 * 1000), @"transactionIdentifier": transaction.transactionIdentifier, @"productIdentifier": transaction.payment.productIdentifier, @"transactionReceipt": [[transaction transactionReceipt] base64EncodedStringWithOptions:0] @@ -117,12 +118,16 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue NSMutableArray *productsArrayForJS = [NSMutableArray array]; for(SKPaymentTransaction *transaction in queue.transactions){ if(transaction.transactionState == SKPaymentTransactionStateRestored) { - NSDictionary *purchase = @{ - @"originalTransactionIdentifier": transaction.originalTransaction.transactionIdentifier, - @"transactionIdentifier": transaction.transactionIdentifier, - @"productIdentifier": transaction.payment.productIdentifier, - @"transactionReceipt": [[transaction transactionReceipt] base64EncodedStringWithOptions:0] - }; + SKPaymentTransaction *originalTransaction = transaction.originalTransaction; + + NSDictionary *purchase = @{ + @"originalTransactionDate": @(originalTransaction.transactionDate.timeIntervalSince1970 * 1000), + @"originalTransactionIdentifier": originalTransaction.transactionIdentifier, + @"transactionDate": @(transaction.transactionDate.timeIntervalSince1970 * 1000), + @"transactionIdentifier": transaction.transactionIdentifier, + @"productIdentifier": transaction.payment.productIdentifier, + @"transactionReceipt": [[transaction transactionReceipt] base64EncodedStringWithOptions:0] + }; [productsArrayForJS addObject:purchase]; [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; diff --git a/Readme.md b/Readme.md index f903245..4f95d6b 100644 --- a/Readme.md +++ b/Readme.md @@ -78,6 +78,7 @@ InAppUtils.purchaseProduct(productIdentifier, (error, response) => { | Field | Type | Description | | --------------------- | ------ | -------------------------------------------------- | +| transactionDate | number | The transaction date (ms since epoch) | | transactionIdentifier | string | The transaction identifier | | productIdentifier | string | The product identifier | | transactionReceipt | string | The transaction receipt as a base64 encoded string | @@ -100,7 +101,9 @@ InAppUtils.restorePurchases((error, response)=> { | Field | Type | Description | | ------------------------------ | ------ | -------------------------------------------------- | +| originalTransactionDate | number | The original transaction date (ms since epoch) | | originalTransactionIdentifier | string | The original transaction identifier | +| transactionDate | number | The transaction date (ms since epoch) | | transactionIdentifier | string | The transaction identifier | | productIdentifier | string | The product identifier | | transactionReceipt | string | The transaction receipt as a base64 encoded string | From 84b3719a28836d59b759f3cc78969e19658b6d99 Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Tue, 7 Mar 2017 14:24:59 -0500 Subject: [PATCH 10/35] 5.2.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7d8eb16..6585627 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-in-app-utils", - "version": "5.1.0", + "version": "5.2.0", "description": "A react-native wrapper for handling in-app payments.", "author": { "name": "Chirag Jain", From c4b080e76d9958d0c43a8aadb4f70e1645715b70 Mon Sep 17 00:00:00 2001 From: Joshua Pinter Date: Wed, 15 Mar 2017 19:40:06 -0400 Subject: [PATCH 11/35] Built out restorePurchase example a little more. (#42) To show handling of the array of restored products and dealing with an individual product. --- Readme.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 4f95d6b..8c55e0b 100644 --- a/Readme.md +++ b/Readme.md @@ -92,7 +92,17 @@ InAppUtils.restorePurchases((error, response)=> { AlertIOS.alert('itunes Error', 'Could not connect to itunes store.'); } else { AlertIOS.alert('Restore Successful', 'Successfully restores all your purchases.'); - //unlock store here again. + + if (response.length == 0) { + Alert.alert('No Purchases', "We didn't find any purchases to restore."); + return; + } + + response.forEach( function(purchase) { + if (purchase.productIdentifier == "com.xyz.abc") { + // Handle purchased product. + } + }); } }); ``` From 00e5fa27a5daea102c46c2b5866efc041b3ca96f Mon Sep 17 00:00:00 2001 From: chrisbianca Date: Tue, 28 Mar 2017 15:38:45 +0200 Subject: [PATCH 12/35] Add podspec (#76) --- react-native-in-app-utils.podspec | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 react-native-in-app-utils.podspec diff --git a/react-native-in-app-utils.podspec b/react-native-in-app-utils.podspec new file mode 100644 index 0000000..ce26c4a --- /dev/null +++ b/react-native-in-app-utils.podspec @@ -0,0 +1,18 @@ +require 'json' +pjson = JSON.parse(File.read('package.json')) + +Pod::Spec.new do |s| + + s.name = pjson["name"] + s.version = pjson["version"] + s.homepage = "https://github.com/chirag04/react-native-in-app-utils" + s.summary = pjson["description"] + s.license = pjson["license"] + s.author = { "Chirag Jain" => "jain_chirag04@yahoo.com" } + s.platform = :ios, "7.0" + s.source = { :git => "https://github.com/chirag04/react-native-in-app-utils", :tag => "#{s.version}" } + s.source_files = 'InAppUtils/*.{h,m}' + + s.dependency 'React' + +end From 65a92908842ff0f445bdcff295d32c2b2b97acba Mon Sep 17 00:00:00 2001 From: Christian Genco Date: Wed, 29 Mar 2017 06:00:32 -0500 Subject: [PATCH 13/35] fix code formatting (#77) --- Readme.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index 8c55e0b..2c8f848 100644 --- a/Readme.md +++ b/Readme.md @@ -23,10 +23,11 @@ A react-native wrapper for handling in-app purchases. 3. Whenever you want to use it within React code now you just have to do: `var InAppUtils = require('NativeModules').InAppUtils;` or for ES6: - ``` - import { NativeModules } from 'react-native' -   const { InAppUtils } = NativeModules - ``` + +``` +import { NativeModules } from 'react-native' +const { InAppUtils } = NativeModules +``` ## API From 23b8c92bbdc9dcb251dbe8a9b0938b723d20f536 Mon Sep 17 00:00:00 2001 From: Chirag Date: Wed, 29 Mar 2017 09:26:03 -0400 Subject: [PATCH 14/35] check original transaction (#78) * check original transaction * fix typo --- InAppUtils/InAppUtils.m | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/InAppUtils/InAppUtils.m b/InAppUtils/InAppUtils.m index f41e7a2..3d4193b 100644 --- a/InAppUtils/InAppUtils.m +++ b/InAppUtils/InAppUtils.m @@ -118,17 +118,20 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue NSMutableArray *productsArrayForJS = [NSMutableArray array]; for(SKPaymentTransaction *transaction in queue.transactions){ if(transaction.transactionState == SKPaymentTransactionStateRestored) { - SKPaymentTransaction *originalTransaction = transaction.originalTransaction; NSDictionary *purchase = @{ - @"originalTransactionDate": @(originalTransaction.transactionDate.timeIntervalSince1970 * 1000), - @"originalTransactionIdentifier": originalTransaction.transactionIdentifier, @"transactionDate": @(transaction.transactionDate.timeIntervalSince1970 * 1000), @"transactionIdentifier": transaction.transactionIdentifier, @"productIdentifier": transaction.payment.productIdentifier, @"transactionReceipt": [[transaction transactionReceipt] base64EncodedStringWithOptions:0] }; + SKPaymentTransaction *originalTransaction = transaction.originalTransaction; + if (originalTransaction) { + purchase[@"originalTransactionDate"] = @(originalTransaction.transactionDate.timeIntervalSince1970 * 1000); + purchase[@"originalTransactionIdentifier"] = originalTransaction.transactionIdentifier; + } + [productsArrayForJS addObject:purchase]; [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; } From 2b290af07b878db9567e36f2a8cfc2633e773df9 Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Wed, 29 Mar 2017 09:26:19 -0400 Subject: [PATCH 15/35] 5.2.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6585627..300600b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-in-app-utils", - "version": "5.2.0", + "version": "5.2.1", "description": "A react-native wrapper for handling in-app payments.", "author": { "name": "Chirag Jain", From 6a1ff08dc5d92b075b7cb3178930c8c2761c6d18 Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Wed, 29 Mar 2017 09:37:40 -0400 Subject: [PATCH 16/35] mutable dict --- InAppUtils/InAppUtils.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/InAppUtils/InAppUtils.m b/InAppUtils/InAppUtils.m index 3d4193b..f72de0a 100644 --- a/InAppUtils/InAppUtils.m +++ b/InAppUtils/InAppUtils.m @@ -119,7 +119,7 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue for(SKPaymentTransaction *transaction in queue.transactions){ if(transaction.transactionState == SKPaymentTransactionStateRestored) { - NSDictionary *purchase = @{ + NSMutableDictionary *purchase = @{ @"transactionDate": @(transaction.transactionDate.timeIntervalSince1970 * 1000), @"transactionIdentifier": transaction.transactionIdentifier, @"productIdentifier": transaction.payment.productIdentifier, From f951a0a5d175b6c0f9861c7eb9ba076098799715 Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Wed, 29 Mar 2017 09:38:06 -0400 Subject: [PATCH 17/35] 5.2.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 300600b..b84aef2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-in-app-utils", - "version": "5.2.1", + "version": "5.2.2", "description": "A react-native wrapper for handling in-app payments.", "author": { "name": "Chirag Jain", From 00130c7f9ad5215f89483e98f3fba0d9516a0960 Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Wed, 29 Mar 2017 09:57:35 -0400 Subject: [PATCH 18/35] NSMutableDictionary --- InAppUtils/InAppUtils.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/InAppUtils/InAppUtils.m b/InAppUtils/InAppUtils.m index f72de0a..fe5af5c 100644 --- a/InAppUtils/InAppUtils.m +++ b/InAppUtils/InAppUtils.m @@ -119,12 +119,12 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue for(SKPaymentTransaction *transaction in queue.transactions){ if(transaction.transactionState == SKPaymentTransactionStateRestored) { - NSMutableDictionary *purchase = @{ + NSMutableDictionary *purchase = [NSMutableDictionary dictionaryWithDictionary: @{ @"transactionDate": @(transaction.transactionDate.timeIntervalSince1970 * 1000), @"transactionIdentifier": transaction.transactionIdentifier, @"productIdentifier": transaction.payment.productIdentifier, @"transactionReceipt": [[transaction transactionReceipt] base64EncodedStringWithOptions:0] - }; + }]; SKPaymentTransaction *originalTransaction = transaction.originalTransaction; if (originalTransaction) { From c1ba12c036561a1d8e0f3df6fe0f568a6743edf1 Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Wed, 29 Mar 2017 09:57:43 -0400 Subject: [PATCH 19/35] 5.2.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b84aef2..175af41 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-in-app-utils", - "version": "5.2.2", + "version": "5.2.3", "description": "A react-native wrapper for handling in-app payments.", "author": { "name": "Chirag Jain", From 022de31a5de429df3e4c7f6ec21e6eed063b5135 Mon Sep 17 00:00:00 2001 From: Ken Date: Fri, 21 Apr 2017 22:48:19 +0900 Subject: [PATCH 20/35] add information about in-app-purchase free trial period (#83) * add information about in-app-purchase free trial period --- Readme.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Readme.md b/Readme.md index 2c8f848..89cb74a 100644 --- a/Readme.md +++ b/Readme.md @@ -170,3 +170,13 @@ async validate(receiptData) { ``` This works on both react native and backend server, you should setup a cron job that run everyday to check if the receipt is still valid + +## Free trial period for in-app-purchase +There is nothing to set up related to this library. +Instead, If you want to set up a free trial period for in-app-purchase, you have to set it up at +iTunes Connect > your app > your in-app-purchase > free trial period (say 3-days or any period you can find from the pulldown menu) + +The flow we know at this point seems to be (auto-renewal case): +1. FIRST, user have to 'purchase' no matter the free trial period is set or not. +2. If the app is configured to have a free trial period, THEN user can use the app in that free trial period without being charged. +3. When the free trial period is over, Apple's system will start to auto-renew user's purchase, therefore user can continue to use the app, but user will be charged from that point on. From 10dbc0fd83b1b9ff61d0d2000e9f78ca4bceacf2 Mon Sep 17 00:00:00 2001 From: Johan Date: Tue, 23 May 2017 19:55:36 +0100 Subject: [PATCH 21/35] Added canMakePurhases (#90) * Added canMakePayments --- InAppUtils/InAppUtils.m | 6 ++++++ Readme.md | 17 +++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/InAppUtils/InAppUtils.m b/InAppUtils/InAppUtils.m index fe5af5c..2ac37d2 100644 --- a/InAppUtils/InAppUtils.m +++ b/InAppUtils/InAppUtils.m @@ -164,6 +164,12 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue } } +RCT_EXPORT_METHOD(canMakePayments: (RCTResponseSenderBlock)callback) +{ + BOOL canMakePayments = [SKPaymentQueue canMakePayments]; + callback(@[@(canMakePayments)]); +} + RCT_EXPORT_METHOD(receiptData:(RCTResponseSenderBlock)callback) { NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL]; diff --git a/Readme.md b/Readme.md index 89cb74a..2975a9c 100644 --- a/Readme.md +++ b/Readme.md @@ -136,6 +136,23 @@ InAppUtils.receiptData((error, receiptData)=> { **Response:** The receipt as a base64 encoded string. +### Can make purchases + +Check if in-app purchases are enabled/disabled. + +```javascript +InAppUtils.canMakePurchases((enabled) => { + if(enabled) { + AlertIOS.alert('IAP enabled'); + } else { + AlertIOS.alert('IAP disabled'); + } +}); +``` + +**Response:** The receipt as a base64 encoded string. + + ## Testing To test your in-app purchases, you have to *run the app on an actual device*. Using the iOS Simulator, they will always fail as the simulator cannot connect to the iTunes Store. However, you can do certain tasks like using `loadProducts` without the need to run on a real device. From 31c4623c42cb728996ad85469b36e5962cbe8a4a Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Tue, 23 May 2017 14:56:09 -0400 Subject: [PATCH 22/35] 5.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 175af41..53fde19 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-in-app-utils", - "version": "5.2.3", + "version": "5.3.0", "description": "A react-native wrapper for handling in-app payments.", "author": { "name": "Chirag Jain", From d534b11eb689f994b24bcc81092f772b1e3b286c Mon Sep 17 00:00:00 2001 From: Mostafa Gaafar Date: Wed, 14 Jun 2017 17:48:11 +0400 Subject: [PATCH 23/35] docs: correct canMakePurchases -> canMakePayments (#94) fix the method name in docs to match the code --- Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 2975a9c..90872fb 100644 --- a/Readme.md +++ b/Readme.md @@ -136,12 +136,12 @@ InAppUtils.receiptData((error, receiptData)=> { **Response:** The receipt as a base64 encoded string. -### Can make purchases +### Can make payments Check if in-app purchases are enabled/disabled. ```javascript -InAppUtils.canMakePurchases((enabled) => { +InAppUtils.canMakePayments((enabled) => { if(enabled) { AlertIOS.alert('IAP enabled'); } else { From 60e047948619aa0186e75170438576de5080b870 Mon Sep 17 00:00:00 2001 From: skylerfenn Date: Wed, 14 Jun 2017 17:13:41 -0600 Subject: [PATCH 24/35] Update Readme.md (#95) Fix typo availble => available --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 90872fb..c1209e6 100644 --- a/Readme.md +++ b/Readme.md @@ -65,7 +65,7 @@ InAppUtils.loadProducts(products, (error, products) => { ```javascript var productIdentifier = 'com.xyz.abc'; InAppUtils.purchaseProduct(productIdentifier, (error, response) => { - // NOTE for v3.0: User can cancel the payment which will be availble as error object here. + // NOTE for v3.0: User can cancel the payment which will be available as error object here. if(response && response.productIdentifier) { AlertIOS.alert('Purchase Successful', 'Your Transaction ID is ' + response.transactionIdentifier); //unlock store here. From c6cdf6e2185a67b3a1e9efc53526d2410b787c9c Mon Sep 17 00:00:00 2001 From: Danilo Figueiredo Date: Thu, 22 Jun 2017 12:22:10 +0100 Subject: [PATCH 25/35] Clarify API responses (#97) --- Readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Readme.md b/Readme.md index c1209e6..6435a62 100644 --- a/Readme.md +++ b/Readme.md @@ -45,7 +45,7 @@ InAppUtils.loadProducts(products, (error, products) => { }); ``` -**Response fields:** +**Response:** An array of product objects with the following fields: | Field | Type | Description | | -------------- | ------- | ------------------------------------------- | @@ -75,7 +75,7 @@ InAppUtils.purchaseProduct(productIdentifier, (error, response) => { **NOTE:** Call `loadProducts` prior to calling `purchaseProduct`, otherwise this will return `invalid_product`. If you're calling them right after each other, you will need to call `purchaseProduct` inside of the `loadProducts` callback to ensure it has had a chance to complete its call. -**Response fields:** +**Response:** A transaction object with the following fields: | Field | Type | Description | | --------------------- | ------ | -------------------------------------------------- | @@ -108,7 +108,7 @@ InAppUtils.restorePurchases((error, response)=> { }); ``` -**Response:** An array of transactions with the following fields: +**Response:** An array of transaction objects with the following fields: | Field | Type | Description | | ------------------------------ | ------ | -------------------------------------------------- | @@ -150,7 +150,7 @@ InAppUtils.canMakePayments((enabled) => { }); ``` -**Response:** The receipt as a base64 encoded string. +**Response:** The enabled boolean flag. ## Testing From 306fce23c107b857e10f4610b0992bb282944d62 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Dusseaut Date: Mon, 26 Jun 2017 15:27:02 +0200 Subject: [PATCH 26/35] detecting loadProducts network errors (#99) --- InAppUtils/InAppUtils.m | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/InAppUtils/InAppUtils.m b/InAppUtils/InAppUtils.m index 2ac37d2..f05e9eb 100644 --- a/InAppUtils/InAppUtils.m +++ b/InAppUtils/InAppUtils.m @@ -210,6 +210,16 @@ - (void)productsRequest:(SKProductsRequest *)request } } +// SKProductsRequestDelegate network error +- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{ + NSString *key = RCTKeyForInstance(request); + RCTResponseSenderBlock callback = _callbacks[key]; + if(callback) { + callback(@[RCTJSErrorFromNSError(error)]); + [_callbacks removeObjectForKey:key]; + } +} + - (void)dealloc { [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; From 3d6e4dba5a09e32bea6d87567711ade69f2553fc Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Mon, 26 Jun 2017 09:41:52 -0400 Subject: [PATCH 27/35] 5.4.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 53fde19..366db87 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-in-app-utils", - "version": "5.3.0", + "version": "5.4.0", "description": "A react-native wrapper for handling in-app payments.", "author": { "name": "Chirag Jain", From 25692d9b4b25582c4a23c70c799c8f18894dc074 Mon Sep 17 00:00:00 2001 From: Dominic Adams Date: Tue, 4 Jul 2017 21:26:02 +0100 Subject: [PATCH 28/35] Update Readme.md (#100) Update to clarify steps needed from tutorial --- Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Readme.md b/Readme.md index 6435a62..7e205d4 100644 --- a/Readme.md +++ b/Readme.md @@ -11,7 +11,7 @@ A react-native wrapper for handling in-app purchases. - You need an Apple Developer account to use in-app purchases. -- You have to set up your in-app purchases in iTunes Connect first. Follow this [tutorial](http://stackoverflow.com/questions/19556336/how-do-you-add-an-in-app-purchase-to-an-ios-application) for an easy explanation. +- You have to set up your in-app purchases in iTunes Connect first. Follow steps 1-13 in this [tutorial](http://stackoverflow.com/questions/19556336/how-do-you-add-an-in-app-purchase-to-an-ios-application) for an easy explanation. - You have to test your in-app purchases on a real device, in-app purchases will always fail on the Simulator. From d52ae125896fbd82f6df0f19f734f3ef09029608 Mon Sep 17 00:00:00 2001 From: Christian Brevik Date: Fri, 14 Jul 2017 17:52:07 +0200 Subject: [PATCH 29/35] Add user cancelled error for restore purchase (#45) Simple change to make it obvious if user cancels login dialog when you try to restore purchases. --- InAppUtils/InAppUtils.m | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/InAppUtils/InAppUtils.m b/InAppUtils/InAppUtils.m index f05e9eb..073d174 100644 --- a/InAppUtils/InAppUtils.m +++ b/InAppUtils/InAppUtils.m @@ -103,7 +103,16 @@ - (void)paymentQueue:(SKPaymentQueue *)queue NSString *key = RCTKeyForInstance(@"restoreRequest"); RCTResponseSenderBlock callback = _callbacks[key]; if (callback) { - callback(@[@"restore_failed"]); + switch (error.code) + { + case SKErrorPaymentCancelled: + callback(@[@"user_cancelled"]); + break; + default: + callback(@[@"restore_failed"]); + break; + } + [_callbacks removeObjectForKey:key]; } else { RCTLogWarn(@"No callback registered for restore product request."); From 74289e756346e2f4ff53a51dd8fb5860564938f5 Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Fri, 14 Jul 2017 11:52:52 -0400 Subject: [PATCH 30/35] 5.5.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 366db87..84882f4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-in-app-utils", - "version": "5.4.0", + "version": "5.5.0", "description": "A react-native wrapper for handling in-app payments.", "author": { "name": "Chirag Jain", From 54ff695ff041eb24eec99ac33a04becaf69c1939 Mon Sep 17 00:00:00 2001 From: Han Lin Yap Date: Sun, 16 Jul 2017 20:34:26 +0200 Subject: [PATCH 31/35] Typo (#105) * Typo --- Readme.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Readme.md b/Readme.md index 7e205d4..a6818f1 100644 --- a/Readme.md +++ b/Readme.md @@ -67,7 +67,7 @@ var productIdentifier = 'com.xyz.abc'; InAppUtils.purchaseProduct(productIdentifier, (error, response) => { // NOTE for v3.0: User can cancel the payment which will be available as error object here. if(response && response.productIdentifier) { - AlertIOS.alert('Purchase Successful', 'Your Transaction ID is ' + response.transactionIdentifier); + Alert.alert('Purchase Successful', 'Your Transaction ID is ' + response.transactionIdentifier); //unlock store here. } }); @@ -88,19 +88,19 @@ InAppUtils.purchaseProduct(productIdentifier, (error, response) => { ### Restore payments ```javascript -InAppUtils.restorePurchases((error, response)=> { +InAppUtils.restorePurchases((error, response) => { if(error) { - AlertIOS.alert('itunes Error', 'Could not connect to itunes store.'); + Alert.alert('itunes Error', 'Could not connect to itunes store.'); } else { - AlertIOS.alert('Restore Successful', 'Successfully restores all your purchases.'); + Alert.alert('Restore Successful', 'Successfully restores all your purchases.'); - if (response.length == 0) { + if (response.length === 0) { Alert.alert('No Purchases', "We didn't find any purchases to restore."); return; } - response.forEach( function(purchase) { - if (purchase.productIdentifier == "com.xyz.abc") { + response.forEach((purchase) => { + if (purchase.productIdentifier === 'com.xyz.abc') { // Handle purchased product. } }); @@ -127,7 +127,7 @@ iTunes receipts are associated to the users iTunes account and can be retrieved ```javascript InAppUtils.receiptData((error, receiptData)=> { if(error) { - AlertIOS.alert('itunes Error', 'Receipt not found.'); + Alert.alert('itunes Error', 'Receipt not found.'); } else { //send to validation server } @@ -143,9 +143,9 @@ Check if in-app purchases are enabled/disabled. ```javascript InAppUtils.canMakePayments((enabled) => { if(enabled) { - AlertIOS.alert('IAP enabled'); + Alert.alert('IAP enabled'); } else { - AlertIOS.alert('IAP disabled'); + Alert.alert('IAP disabled'); } }); ``` From 97a8ddd3c039af0c307f1fc00f32f7685d7dd27d Mon Sep 17 00:00:00 2001 From: RalfNieuwenhuizen Date: Thu, 24 Aug 2017 17:57:26 +0200 Subject: [PATCH 32/35] Implement purchaseProductForUser and restorePurchasesForUser methods (#119) * Implement purchaseProductForUser and restorePurchasesForUser methods --- InAppUtils/InAppUtils.m | 32 +++++++++++++++++++++++++++++++- Readme.md | 7 +++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/InAppUtils/InAppUtils.m b/InAppUtils/InAppUtils.m index 073d174..d726603 100644 --- a/InAppUtils/InAppUtils.m +++ b/InAppUtils/InAppUtils.m @@ -76,8 +76,22 @@ - (void)paymentQueue:(SKPaymentQueue *)queue } } +RCT_EXPORT_METHOD(purchaseProductForUser:(NSString *)productIdentifier + username:(NSString *)username + callback:(RCTResponseSenderBlock)callback) +{ + [self doPurchaseProduct:productIdentifier username:username callback:callback]; +} + RCT_EXPORT_METHOD(purchaseProduct:(NSString *)productIdentifier callback:(RCTResponseSenderBlock)callback) +{ + [self doPurchaseProduct:productIdentifier username:nil callback:callback]; +} + +- (void) doPurchaseProduct:(NSString *)productIdentifier + username:(NSString *)username + callback:(RCTResponseSenderBlock)callback { SKProduct *product; for(SKProduct *p in products) @@ -89,7 +103,10 @@ - (void)paymentQueue:(SKPaymentQueue *)queue } if(product) { - SKPayment *payment = [SKPayment paymentWithProduct:product]; + SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:product]; + if(username) { + payment.applicationUsername = username; + } [[SKPaymentQueue defaultQueue] addPayment:payment]; _callbacks[RCTKeyForInstance(payment.productIdentifier)] = callback; } else { @@ -159,6 +176,18 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue [[SKPaymentQueue defaultQueue] restoreCompletedTransactions]; } +RCT_EXPORT_METHOD(restorePurchasesForUser:(NSString *)username + callback:(RCTResponseSenderBlock)callback) +{ + NSString *restoreRequest = @"restoreRequest"; + _callbacks[RCTKeyForInstance(restoreRequest)] = callback; + if(!username) { + callback(@[@"username_required"]); + return; + } + [[SKPaymentQueue defaultQueue] restoreCompletedTransactionsWithApplicationUsername:username]; +} + RCT_EXPORT_METHOD(loadProducts:(NSArray *)productIdentifiers callback:(RCTResponseSenderBlock)callback) { @@ -206,6 +235,7 @@ - (void)productsRequest:(SKProductsRequest *)request @"currencySymbol": [item.priceLocale objectForKey:NSLocaleCurrencySymbol], @"currencyCode": [item.priceLocale objectForKey:NSLocaleCurrencyCode], @"priceString": item.priceString, + @"countryCode": [item.priceLocale objectForKey: NSLocaleCountryCode], @"downloadable": item.downloadable ? @"true" : @"false" , @"description": item.localizedDescription ? item.localizedDescription : @"", @"title": item.localizedTitle ? item.localizedTitle : @"", diff --git a/Readme.md b/Readme.md index a6818f1..359cba3 100644 --- a/Readme.md +++ b/Readme.md @@ -54,6 +54,7 @@ InAppUtils.loadProducts(products, (error, products) => { | currencySymbol | string | The currency symbol, i.e. "$" or "SEK" | | currencyCode | string | The currency code, i.e. "USD" of "SEK" | | priceString | string | Localised string of price, i.e. "$1,234.00" | +| countryCode | string | Country code of the price, i.e. "GB" or "FR"| | downloadable | boolean | Whether the purchase is downloadable | | description | string | Description string | | title | string | Title string | @@ -75,6 +76,9 @@ InAppUtils.purchaseProduct(productIdentifier, (error, response) => { **NOTE:** Call `loadProducts` prior to calling `purchaseProduct`, otherwise this will return `invalid_product`. If you're calling them right after each other, you will need to call `purchaseProduct` inside of the `loadProducts` callback to ensure it has had a chance to complete its call. +**NOTE:** `purchaseProductForUser(productIdentifier, username, callback)` is also available. +https://stackoverflow.com/questions/29255568/is-there-any-way-to-know-purchase-made-by-which-itunes-account-ios/29280858#29280858 + **Response:** A transaction object with the following fields: | Field | Type | Description | @@ -108,6 +112,9 @@ InAppUtils.restorePurchases((error, response) => { }); ``` +**NOTE:** `restorePurchasesForUser(username, callback)` is also available. +https://stackoverflow.com/questions/29255568/is-there-any-way-to-know-purchase-made-by-which-itunes-account-ios/29280858#29280858 + **Response:** An array of transaction objects with the following fields: | Field | Type | Description | From 08e18ead3bb246e8a0a2c93a9e4c793a7436fb13 Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Thu, 24 Aug 2017 11:57:58 -0400 Subject: [PATCH 33/35] 5.6.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 84882f4..9e0f046 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-in-app-utils", - "version": "5.5.0", + "version": "5.6.0", "description": "A react-native wrapper for handling in-app payments.", "author": { "name": "Chirag Jain", From 6bf387bb2a831f8e097547ca0fe025702d86bfa9 Mon Sep 17 00:00:00 2001 From: Akshet Pandey Date: Wed, 27 Sep 2017 09:12:07 -0700 Subject: [PATCH 34/35] Allow products to be fetched even if purchases are restricted (#123) Restricting IAPs doesn't prevent us from fetching product information. A better way to handle this is to check canMakePayments method and show appropriate message on the payment screen. Update README to include canMakePayments Also add note about calling canMakePayments before purchaseProduct to show a better error message to users. --- InAppUtils/InAppUtils.m | 14 +++++--------- Readme.md | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/InAppUtils/InAppUtils.m b/InAppUtils/InAppUtils.m index d726603..f382e75 100644 --- a/InAppUtils/InAppUtils.m +++ b/InAppUtils/InAppUtils.m @@ -191,15 +191,11 @@ - (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue RCT_EXPORT_METHOD(loadProducts:(NSArray *)productIdentifiers callback:(RCTResponseSenderBlock)callback) { - if([SKPaymentQueue canMakePayments]){ - SKProductsRequest *productsRequest = [[SKProductsRequest alloc] - initWithProductIdentifiers:[NSSet setWithArray:productIdentifiers]]; - productsRequest.delegate = self; - _callbacks[RCTKeyForInstance(productsRequest)] = callback; - [productsRequest start]; - } else { - callback(@[@"not_available"]); - } + SKProductsRequest *productsRequest = [[SKProductsRequest alloc] + initWithProductIdentifiers:[NSSet setWithArray:productIdentifiers]]; + productsRequest.delegate = self; + _callbacks[RCTKeyForInstance(productsRequest)] = callback; + [productsRequest start]; } RCT_EXPORT_METHOD(canMakePayments: (RCTResponseSenderBlock)callback) diff --git a/Readme.md b/Readme.md index 359cba3..46b5757 100644 --- a/Readme.md +++ b/Readme.md @@ -61,6 +61,18 @@ InAppUtils.loadProducts(products, (error, products) => { **Troubleshooting:** If you do not get back your product(s) then there's a good chance that something in your iTunes Connect or Xcode is not properly configured. Take a look at this [StackOverflow Answer](http://stackoverflow.com/a/11707704/293280) to determine what might be the issue(s). +### Checking if payments are allowed + +```javascript +InAppUtils.canMakePayments((canMakePayments) => { + if(!canMakePayments) { + Alert.alert('Not Allowed', 'This device is not allowed to make purchases. Please check restrictions on device'); + } +}) +``` + +**NOTE:** canMakePayments may return false because of country limitation or parental contol/restriction setup on the device. + ### Buy product ```javascript @@ -76,6 +88,8 @@ InAppUtils.purchaseProduct(productIdentifier, (error, response) => { **NOTE:** Call `loadProducts` prior to calling `purchaseProduct`, otherwise this will return `invalid_product`. If you're calling them right after each other, you will need to call `purchaseProduct` inside of the `loadProducts` callback to ensure it has had a chance to complete its call. +**NOTE:** Call `canMakePurchases` prior to calling `purchaseProduct` to ensure that the user is allowed to make a purchase. It is generally a good idea to inform the user that they are not allowed to make purchases from their account and what they can do about it instead of a cryptic error message from iTunes. + **NOTE:** `purchaseProductForUser(productIdentifier, username, callback)` is also available. https://stackoverflow.com/questions/29255568/is-there-any-way-to-know-purchase-made-by-which-itunes-account-ios/29280858#29280858 From 8cf764dbd9670f39fed383fddb6fa45ff5576df5 Mon Sep 17 00:00:00 2001 From: Chirag Jain Date: Wed, 27 Sep 2017 12:12:38 -0400 Subject: [PATCH 35/35] 6.0.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9e0f046..d128aed 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-in-app-utils", - "version": "5.6.0", + "version": "6.0.0", "description": "A react-native wrapper for handling in-app payments.", "author": { "name": "Chirag Jain",