From 099f79c6d1f0d07f41cc5a6f83a26c2636c41b26 Mon Sep 17 00:00:00 2001 From: Vladislav Shabanov <vshabanov88@gmail.com> Date: Sun, 10 Jun 2018 16:35:01 +0700 Subject: [PATCH 1/4] Android subscription upgrade/downgrade --- README.md | 2 +- .../main/java/com/dooboolab/RNIap/RNIapModule.java | 14 ++++++++++---- index.d.ts | 3 ++- index.js | 5 +++-- 4 files changed, 16 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index ecf5b2bb4..2dcca25b8 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ Lastly, this module also supports types for typescript users from `0.2.5`. | getSubscriptions | `string[]` Subscription IDs/skus | `Promise<Subscription[]>` | Get a list of subscriptions. Note: On iOS this method has the same output as `getProducts`. Because iOS does not differentiate between IAP products and subscriptions. | | getPurchaseHistory | | `Promise<Purchase[]>` | Gets an invetory of purchases made by the user regardless of consumption status (where possible) | | getAvailablePurchases | | `Promise<Purchase[]>` | Get all purchases made by the user (either non-consumable, or haven't been consumed yet) -| buySubscription | `string` Subscription ID/sku | `Promise<Purchase>` | Create (buy) a subscription to a sku | +| buySubscription | `string` Subscription ID/sku, `string` Old Subscription ID/sku (on Android) | `Promise<Purchase>` | Create (buy) a subscription to a sku. For upgrading/downgrading subscription on Android pass second parameter with current subscription ID, on iOS this is handled automatically by store. | | buyProduct | `string` Product ID/sku | `Promise<Purchase>` | Buy a product | | buyProductWithoutFinishTransaction | `string` Product ID/sku | `Promise<Purchase>` | Buy a product without finish transaction call (iOS only) | | finishTransaction | `void` | `void` | Send finishTransaction call to Apple IAP server. Call this function after receipt validation process | diff --git a/android/src/main/java/com/dooboolab/RNIap/RNIapModule.java b/android/src/main/java/com/dooboolab/RNIap/RNIapModule.java index 1fedb2421..574155f5f 100644 --- a/android/src/main/java/com/dooboolab/RNIap/RNIapModule.java +++ b/android/src/main/java/com/dooboolab/RNIap/RNIapModule.java @@ -308,19 +308,25 @@ public void onPurchaseHistoryResponse(@BillingClient.BillingResponse int respons } @ReactMethod - public void buyItemByType(String type, String sku, Promise promise) { + public void buyItemByType(String type, String sku, String oldSku, Promise promise) { final Activity activity = getCurrentActivity(); if (activity == null) { promise.reject(E_UNKNOWN, "getCurrentActivity returned null"); } else { addPromiseForKey(PROMISE_BUY_ITEM, promise); - BillingFlowParams flowParams = BillingFlowParams.newBuilder() - .setSku(sku) + BillingFlowParams.Builder builder = BillingFlowParams.newBuilder(); + + if (type == BillingClient.SkuType.SUBS && oldSku != null && !oldSku.isEmpty()) { + // Subscription upgrade/downgrade + builder.addOldSku(oldSku); + } + + BillingFlowParams flowParams = builder.setSku(sku) .setType(type) .build(); int responseCode = mBillingClient.launchBillingFlow(activity,flowParams); - Log.d(TAG, "buyItemByType (type: " + type + ", sku: " + sku + ") responseCode: " + responseCode + "(" + getBillingResponseCodeName(responseCode) + ")"); + Log.d(TAG, "buyItemByType (type: " + type + ", sku: " + sku + ", oldSku: " + oldSku + ") responseCode: " + responseCode + "(" + getBillingResponseCodeName(responseCode) + ")"); if (responseCode != BillingClient.BillingResponse.OK) { rejectPromisesWithBillingError(PROMISE_BUY_ITEM,responseCode); } diff --git a/index.d.ts b/index.d.ts index 199929cad..6b53034da 100644 --- a/index.d.ts +++ b/index.d.ts @@ -84,9 +84,10 @@ export function getAvailablePurchases() : Promise<Purchase[]>; /** * Create a subscription to a sku * @param {string} sku The product's sku/ID + * @param {string} oldSku Optional old product's ID for upgrade/downgrade (Android only) * @returns {Promise<Purchase>} */ -export function buySubscription(sku: string) : Promise<SubscriptionPurchase>; +export function buySubscription(sku: string, oldSku: string) : Promise<SubscriptionPurchase>; /** * Buy a product diff --git a/index.js b/index.js index 6869bf0ff..ec10a9a74 100644 --- a/index.js +++ b/index.js @@ -86,11 +86,12 @@ export const getAvailablePurchases = () => Platform.select({ /** * Create a subscription to a sku * @param {string} sku The product's sku/ID + * @param {string} oldSku Optional old product's ID for upgrade/downgrade (Android only) * @returns {Promise<SubscriptionPurchase>} */ -export const buySubscription = (sku) => Platform.select({ +export const buySubscription = (sku, oldSku) => Platform.select({ ios: () => RNIapIos.buyProduct(sku), - android: () => RNIapModule.buyItemByType(ANDROID_ITEM_TYPE_SUBSCRIPTION, sku) + android: () => RNIapModule.buyItemByType(ANDROID_ITEM_TYPE_SUBSCRIPTION, sku, oldSku) })(); /** From ed331e8b09746c9298dcb23c371810b56c833b38 Mon Sep 17 00:00:00 2001 From: Vladislav Shabanov <vshabanov88@gmail.com> Date: Sun, 10 Jun 2018 17:40:44 +0700 Subject: [PATCH 2/4] Fix type comparation --- android/src/main/java/com/dooboolab/RNIap/RNIapModule.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/android/src/main/java/com/dooboolab/RNIap/RNIapModule.java b/android/src/main/java/com/dooboolab/RNIap/RNIapModule.java index 574155f5f..56a92c0cb 100644 --- a/android/src/main/java/com/dooboolab/RNIap/RNIapModule.java +++ b/android/src/main/java/com/dooboolab/RNIap/RNIapModule.java @@ -316,7 +316,7 @@ public void buyItemByType(String type, String sku, String oldSku, Promise promis addPromiseForKey(PROMISE_BUY_ITEM, promise); BillingFlowParams.Builder builder = BillingFlowParams.newBuilder(); - if (type == BillingClient.SkuType.SUBS && oldSku != null && !oldSku.isEmpty()) { + if (type.equals(BillingClient.SkuType.SUBS) && oldSku != null && !oldSku.isEmpty()) { // Subscription upgrade/downgrade builder.addOldSku(oldSku); } From 11f68de8dbdfd966bd966616a4acee5a8519d91b Mon Sep 17 00:00:00 2001 From: Vladislav Shabanov <vshabanov88@gmail.com> Date: Mon, 11 Jun 2018 15:08:07 +0700 Subject: [PATCH 3/4] Make oldSku optional in TS definition --- index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 6b53034da..3610005c1 100644 --- a/index.d.ts +++ b/index.d.ts @@ -87,7 +87,7 @@ export function getAvailablePurchases() : Promise<Purchase[]>; * @param {string} oldSku Optional old product's ID for upgrade/downgrade (Android only) * @returns {Promise<Purchase>} */ -export function buySubscription(sku: string, oldSku: string) : Promise<SubscriptionPurchase>; +export function buySubscription(sku: string, oldSku?: string) : Promise<SubscriptionPurchase>; /** * Buy a product From 11b989af2803e84df8a3406ad974a9bde31b39d4 Mon Sep 17 00:00:00 2001 From: Vladislav Shabanov <vshabanov88@gmail.com> Date: Mon, 11 Jun 2018 15:08:54 +0700 Subject: [PATCH 4/4] Make oldSku optional in JSDoc --- index.d.ts | 2 +- index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 3610005c1..7226a4f35 100644 --- a/index.d.ts +++ b/index.d.ts @@ -84,7 +84,7 @@ export function getAvailablePurchases() : Promise<Purchase[]>; /** * Create a subscription to a sku * @param {string} sku The product's sku/ID - * @param {string} oldSku Optional old product's ID for upgrade/downgrade (Android only) + * @param {string} [oldSku] Optional old product's ID for upgrade/downgrade (Android only) * @returns {Promise<Purchase>} */ export function buySubscription(sku: string, oldSku?: string) : Promise<SubscriptionPurchase>; diff --git a/index.js b/index.js index ec10a9a74..4cc5ef667 100644 --- a/index.js +++ b/index.js @@ -86,7 +86,7 @@ export const getAvailablePurchases = () => Platform.select({ /** * Create a subscription to a sku * @param {string} sku The product's sku/ID - * @param {string} oldSku Optional old product's ID for upgrade/downgrade (Android only) + * @param {string} [oldSku] Optional old product's ID for upgrade/downgrade (Android only) * @returns {Promise<SubscriptionPurchase>} */ export const buySubscription = (sku, oldSku) => Platform.select({