From aef51e19fd2f70bece5c02dcd1fbdbede743cc85 Mon Sep 17 00:00:00 2001 From: Hyo Chan Jang Date: Sat, 2 Nov 2019 00:48:43 +0900 Subject: [PATCH] Enhanced `finishTransaction` method to be more useful (#833) - Resolve #797. --- CHANGELOG.md | 2 ++ IapExample/App.js | 34 ++++++++++++++++------------- README.md | 3 +++ index.ts | 54 ++++++++++++++++++++++++++++++++--------------- package.json | 2 +- 5 files changed, 62 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dad6d697..3047eb6af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ ## Changelogs +- **[4.1.0]** + - `finishTransaction` has been renewed by the request in [#797](https://github.com/dooboolab/react-native-iap/issues/797) - **[4.0.8]** - Added subs to the list of unconsumed purchases [#807](https://github.com/dooboolab/react-native-iap/pull/807) - Fixed promise never returned from requestSubscription() [#806](https://github.com/dooboolab/react-native-iap/pull/806) diff --git a/IapExample/App.js b/IapExample/App.js index 01cc65eda..ff6304bd2 100644 --- a/IapExample/App.js +++ b/IapExample/App.js @@ -7,10 +7,13 @@ import { View, } from 'react-native'; import RNIap, { - Product, - ProductPurchase, + InAppPurchase, PurchaseError, + SubscriptionPurchase, acknowledgePurchaseAndroid, + consumePurchaseAndroid, + finishTransaction, + finishTransactionIOS, purchaseErrorListener, purchaseUpdatedListener, } from 'react-native-iap'; @@ -120,24 +123,25 @@ class Page extends Component { } purchaseUpdateSubscription = purchaseUpdatedListener( - async (purchase: ProductPurchase) => { - console.log('purchaseUpdatedListener', purchase); - if ( - purchase.purchaseStateAndroid === 1 && - !purchase.isAcknowledgedAndroid - ) { + async (purchase: InAppPurchase | SubscriptionPurchase) => { + const receipt = purchase.transactionReceipt; + if (receipt) { try { - const ackResult = await acknowledgePurchaseAndroid( - purchase.purchaseToken, - ); - console.log('ackResult', ackResult); + // if (Platform.OS === 'ios') { + // finishTransactionIOS(purchase.transactionId); + // } else if (Platform.OS === 'android') { + // // If consumable (can be purchased again) + // consumePurchaseAndroid(purchase.purchaseToken); + // // If not consumable + // acknowledgePurchaseAndroid(purchase.purchaseToken); + // } + const ackResult = await finishTransaction(purchase); } catch (ackErr) { console.warn('ackErr', ackErr); } + + this.setState({ receipt }, () => this.goNext()); } - this.setState({ receipt: purchase.transactionReceipt }, () => - this.goNext(), - ); }, ); diff --git a/README.md b/README.md index cc4ca2093..d8bdc8dcd 100644 --- a/README.md +++ b/README.md @@ -362,6 +362,9 @@ class RootComponent extends Component<*> { // If not consumable RNIap.acknowledgePurchaseAndroid(purchase.purchaseToken); } + + // From react-native-iap@4.1.0 you can simplify above `method`. Try to wrap the statement with `try` and `catch` to also grab the `error` message. + RNIap.finishTransaction(purchase); } else { // Retry / conclude the purchase is fraudulent, etc... } diff --git a/index.ts b/index.ts index fea8da544..35b86df47 100644 --- a/index.ts +++ b/index.ts @@ -71,7 +71,13 @@ export interface Subscription extends Common { freeTrialPeriodAndroid?: string; } -export interface ProductPurchase { +export enum PurchaseStateAndroid { + Purchased = 0, + Canceled = 1, + Pending = 2, +} + +interface ProductPurchase { productId: string; transactionId?: string; transactionDate: number; @@ -80,7 +86,7 @@ export interface ProductPurchase { dataAndroid?: string; signatureAndroid?: string; autoRenewingAndroid?: boolean; - purchaseStateAndroid?: number; + purchaseStateAndroid?: PurchaseStateAndroid; originalTransactionDateIOS?: string; originalTransactionIdentifierIOS?: string; isAcknowledgedAndroid?: boolean; @@ -398,26 +404,36 @@ export const finishTransactionIOS = (transactionId: string): Promise => * @returns {Promise } */ export const finishTransaction = ( - transactionId: string, + purchase: InAppPurchase | ProductPurchase, isConsumable?: boolean, developerPayloadAndroid?: string, ): Promise => { return Platform.select({ ios: async () => { checkNativeiOSAvailable(); - return RNIapIos.finishTransaction(transactionId); + return RNIapIos.finishTransaction(purchase.transactionId); }, android: async () => { - if (isConsumable) { - return RNIapModule.consumeProduct( - transactionId, - developerPayloadAndroid, - ); + if (purchase) { + if (isConsumable) { + return RNIapModule.consumeProduct( + purchase.purchaseToken, + developerPayloadAndroid, + ); + } else if ( + !purchase.isAcknowledgedAndroid && + purchase.purchaseStateAndroid === PurchaseStateAndroid.Purchased + ) { + return RNIapModule.acknowledgePurchase( + purchase.purchaseToken, + developerPayloadAndroid, + ); + } else { + throw new Error('purchase is not suitable to be purchased'); + } + } else { + throw new Error('purchase is not assigned'); } - return RNIapModule.acknowledgePurchase( - transactionId, - developerPayloadAndroid, - ); }, })(); }; @@ -613,9 +629,11 @@ export const validateReceiptAndroid = async ( /** * Add IAP purchase event in ios. - * @returns {callback(e: ProductPurchase)} + * @returns {callback(e: InAppPurchase | ProductPurchase)} */ -export const purchaseUpdatedListener = (e): EmitterSubscription => { +export const purchaseUpdatedListener = ( + e: InAppPurchase | ProductPurchase | any, +): EmitterSubscription => { if (Platform.OS === 'ios') { checkNativeiOSAvailable(); const myModuleEvt = new NativeEventEmitter(RNIapIos); @@ -632,9 +650,11 @@ export const purchaseUpdatedListener = (e): EmitterSubscription => { /** * Add IAP purchase error event in ios. - * @returns {callback(e: ProductPurchase)} + * @returns {callback(e: PurchaseError)} */ -export const purchaseErrorListener = (e): EmitterSubscription => { +export const purchaseErrorListener = ( + e: PurchaseError | any, +): EmitterSubscription => { if (Platform.OS === 'ios') { checkNativeiOSAvailable(); const myModuleEvt = new NativeEventEmitter(RNIapIos); diff --git a/package.json b/package.json index 41e54a15c..2e41927dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-native-iap", - "version": "4.0.8", + "version": "4.1.0", "description": "React Native In App Purchase Module.", "main": "index.js", "types": "index.d.ts",