>('products');
// noinspection UnnecessaryLocalVariableJS
diff --git a/plugin/src/plugin/SkuDetails.ts b/plugin/src/plugin/SkuDetails.ts
index 06e5b0d..236c625 100644
--- a/plugin/src/plugin/SkuDetails.ts
+++ b/plugin/src/plugin/SkuDetails.ts
@@ -1,3 +1,6 @@
+/**
+ * @deprecated
+ */
export class SkuDetails {
description: string;
freeTrialPeriod: string;
diff --git a/plugin/src/plugin/SubscriptionPeriod.ts b/plugin/src/plugin/SubscriptionPeriod.ts
new file mode 100644
index 0000000..ade833b
--- /dev/null
+++ b/plugin/src/plugin/SubscriptionPeriod.ts
@@ -0,0 +1,31 @@
+import {SubscriptionPeriodUnit} from "./enums";
+
+/**
+ * A class describing a subscription period
+ */
+export class SubscriptionPeriod {
+ /**
+ * A count of subsequent intervals.
+ */
+ unitCount: number;
+
+ /**
+ * Interval unit.
+ */
+ unit: SubscriptionPeriodUnit;
+
+ /**
+ * ISO 8601 representation of the period, e.g. "P7D", meaning 7 days period.
+ */
+ iso: string;
+
+ constructor(
+ unitCount: number,
+ unit: SubscriptionPeriodUnit,
+ iso: string,
+ ) {
+ this.unitCount = unitCount;
+ this.unit = unit;
+ this.iso = iso;
+ }
+}
diff --git a/plugin/src/plugin/enums.ts b/plugin/src/plugin/enums.ts
index a8cac40..20df961 100644
--- a/plugin/src/plugin/enums.ts
+++ b/plugin/src/plugin/enums.ts
@@ -1,47 +1,84 @@
export enum LaunchMode {
ANALYTICS = 'Analytics',
- SUBSCRIPTION_MANAGEMENT = 'SubscriptionManagement'
+ SUBSCRIPTION_MANAGEMENT = 'SubscriptionManagement',
}
export enum Environment {
SANDBOX = "Sandbox",
- PRODUCTION = "Production"
+ PRODUCTION = "Production",
}
-export const ProductType = {
- "0": "TRIAL",
- "1": "DIRECT_SUBSCRIPTION",
- "2": "ONE_TIME",
-} as const;
+export enum ProductType {
+ TRIAL = "Trial",
+ INTRO = "Intro", /** Currently works for Android only. iOS support will be added soon. */
+ SUBSCRIPTION = "Subscription",
+ IN_APP = "InApp",
+ UNKNOWN = "Unknown",
+}
+
+export enum SubscriptionPeriodUnit {
+ DAY = "Day",
+ WEEK = "Week",
+ MONTH = "Month",
+ YEAR = "Year",
+ UNKNOWN = "Unknown",
+}
-export type ProductTypes = typeof ProductType[keyof typeof ProductType];
+/**
+ * Recurrence mode of the pricing phase.
+ */
+export enum PricingPhaseRecurrenceMode {
+ /**
+ * The billing plan payment recurs for infinite billing periods unless canceled.
+ */
+ INFINITE_RECURRING = "InfiniteRecurring",
-export const ProductDuration = {
- 0: "WEEKLY",
- 1: "MONTHLY",
- 2: "3_MONTHS",
- 3: "6_MONTHS",
- 4: "ANNUAL",
- 5: "LIFETIME",
-} as const;
+ /**
+ * The billing plan payment recurs for a fixed number of billing periods
+ * set in {@link ProductPricingPhase.billingCycleCount}.
+ */
+ FINITE_RECURRING = "FiniteRecurring",
-export type ProductDurations = typeof ProductDuration[keyof typeof ProductDuration];
-
-export const TrialDuration = {
- "-1": "NOT_AVAILABLE",
- "0": "UNKNOWN",
- "1": "THREE_DAYS",
- "2": "WEEK",
- "3": "TWO_WEEKS",
- "4": "MONTH",
- "5": "TWO_MONTHS",
- "6": "THREE_MONTHS",
- "7": "SIX_MONTHS",
- "8": "YEAR",
- "9": "OTHER",
-} as const;
+ /**
+ * The billing plan payment is a one-time charge that does not repeat.
+ */
+ NON_RECURRING = "NonRecurring",
+
+ /**
+ * Unknown recurrence mode.
+ */
+ UNKNOWN = "Unknown",
+}
+
+/**
+ * Type of the pricing phase.
+ */
+export enum PricingPhaseType {
+ /**
+ * Regular subscription without any discounts like trial or intro offers.
+ */
+ REGULAR = "Regular",
-export type TrialDurations = typeof TrialDuration[keyof typeof TrialDuration];
+ /**
+ * A free phase.
+ */
+ FREE_TRIAL = "FreeTrial",
+
+ /**
+ * A phase with a discounted payment for a single period.
+ */
+ DISCOUNTED_SINGLE_PAYMENT = "DiscountedSinglePayment",
+
+ /**
+ * A phase with a discounted payment for several periods, described in {@link ProductPricingPhase.billingCycleCount}.
+ */
+ DISCOUNTED_RECURRING_PAYMENT = "DiscountedRecurringPayment",
+
+ /**
+ * Unknown pricing phase type.
+ */
+ UNKNOWN = "Unknown",
+}
export enum EntitlementRenewState {
NON_RENEWABLE = 'non_renewable',
@@ -108,12 +145,47 @@ export enum AttributionProvider {
APPLE_AD_SERVICES = "AppleAdServices", // ios only
}
-export enum ProrationMode {
- UNKNOWN_SUBSCRIPTION_UPGRADE_DOWNGRADE_POLICY = 0,
- IMMEDIATE_WITH_TIME_PRORATION = 1,
- IMMEDIATE_AND_CHARGE_PRORATED_PRICE = 2,
- IMMEDIATE_WITHOUT_PRORATION = 3,
- DEFERRED = 4,
+/**
+ * A policy used for purchase updates on Android, which describes
+ * how to migrate from purchased plan to a new one.
+ *
+ * Used in {@link PurchaseUpdateModel} class for purchase updates.
+ */
+export enum PurchaseUpdatePolicy {
+ /**
+ * The new plan takes effect immediately, and the user is charged full price of new plan
+ * and is given a full billing cycle of subscription, plus remaining prorated time
+ * from the old plan.
+ */
+ CHARGE_FULL_PRICE = 'ChargeFullPrice',
+
+ /**
+ * The new plan takes effect immediately, and the billing cycle remains the same.
+ */
+ CHARGE_PRORATED_PRICE = 'ChargeProratedPrice',
+
+ /**
+ * The new plan takes effect immediately, and the remaining time will be prorated
+ * and credited to the user.
+ */
+ WITH_TIME_PRORATION = 'WithTimeProration',
+
+ /**
+ * The new purchase takes effect immediately, the new plan will take effect
+ * when the old item expires.
+ */
+ DEFERRED = 'Deferred',
+
+ /**
+ * The new plan takes effect immediately, and the new price will be charged
+ * on next recurrence time.
+ */
+ WITHOUT_PRORATION = 'WithoutProration',
+
+ /**
+ * Unknown police.
+ */
+ UNKNOWN = 'Unknown',
}
export enum EntitlementsCacheLifetime {
@@ -124,7 +196,7 @@ export enum EntitlementsCacheLifetime {
THREE_MONTHS = "ThreeMonths",
SIX_MONTHS = "SixMonths",
YEAR = "Year",
- UNLIMITED = "Unlimited"
+ UNLIMITED = "Unlimited",
}
export const SKPeriodUnit = {
@@ -163,6 +235,25 @@ export enum IntroEligibilityStatus {
INELIGIBLE = "intro_or_trial_ineligible",
}
+export enum ExperimentGroupType {
+ UNKNOWN = "unknown",
+ CONTROL = "control",
+ TREATMENT = "treatment",
+}
+
+export enum RemoteConfigurationSourceType {
+ UNKNOWN = "unknown",
+ EXPERIMENT_CONTROL_GROUP = "experiment_control_group",
+ EXPERIMENT_TREATMENT_GROUP = "experiment_treatment_group",
+ REMOTE_CONFIGURATION = "remote_configuration",
+}
+
+export enum RemoteConfigurationAssignmentType {
+ UNKNOWN = "unknown",
+ AUTO = "auto",
+ MANUAL = "manual",
+}
+
export enum ActionResultType {
UNKNOWN = "unknown",
URL = "url",
@@ -192,22 +283,3 @@ export enum AutomationsEventType {
SUBSCRIPTION_DOWNGRADED = "subscription_downgraded",
SUBSCRIPTION_PRODUCT_CHANGED = "subscription_product_changed",
}
-
-export enum ExperimentGroupType {
- UNKNOWN = "unknown",
- CONTROL = "control",
- TREATMENT = "treatment",
-}
-
-export enum RemoteConfigurationSourceType {
- UNKNOWN = "unknown",
- EXPERIMENT_CONTROL_GROUP = "experiment_control_group",
- EXPERIMENT_TREATMENT_GROUP = "experiment_treatment_group",
- REMOTE_CONFIGURATION = "remote_configuration",
-}
-
-export enum RemoteConfigurationAssignmentType {
- UNKNOWN = "unknown",
- AUTO = "auto",
- MANUAL = "manual",
-}
diff --git a/sample/package.json b/sample/package.json
index ead7ecf..1f5272d 100644
--- a/sample/package.json
+++ b/sample/package.json
@@ -8,7 +8,8 @@
"refresh": "cordova plugin rm cordova-plugin-qonversion && cordova plugin add ../plugin",
"android": "cordova run android -- --gradleArg=-PcdvCompileSdkVersion=33",
"ios": "cordova run ios",
- "test": "echo \"Error: no test specified\" && exit 1"
+ "test": "echo \"Error: no test specified\" && exit 1",
+ "xcode": "open \"./platforms/ios/Qonversion Cordova.xcworkspace\""
},
"keywords": [
"ecosystem:cordova"
@@ -31,4 +32,4 @@
"cordova-plugin-qonversion": {}
}
}
-}
\ No newline at end of file
+}
diff --git a/sample/www/index.html b/sample/www/index.html
index c8748ca..7fc9897 100644
--- a/sample/www/index.html
+++ b/sample/www/index.html
@@ -47,11 +47,13 @@ Qonversion Cordova Plugin
+
-
-
+
+
+
diff --git a/sample/www/js/index.js b/sample/www/js/index.js
index 0882449..b1c6b22 100644
--- a/sample/www/js/index.js
+++ b/sample/www/js/index.js
@@ -26,7 +26,7 @@ const app = {
document.getElementById("initialize-sdk").addEventListener("click", this.initializeSdk);
document.getElementById("purchase").addEventListener("click", this.purchase);
- document.getElementById("purchase-product").addEventListener("click", this.purchaseProduct);
+ document.getElementById("update-purchase").addEventListener("click", this.updatePurchase);
document.getElementById("get-products").addEventListener("click", this.getProducts);
document.getElementById("get-remote-config").addEventListener("click", this.getRemoteConfig);
document.getElementById("get-offerings").addEventListener("click", this.getOfferings);
@@ -73,27 +73,33 @@ const app = {
async purchase() {
const productId = document.getElementById('product-id').value;
+ const offerId = document.getElementById('offer-id').value;
+ const products = await Qonversion.getSharedInstance().products();
+ const product = products.get(productId);
try {
- const entitlements = await Qonversion.getSharedInstance().purchase(productId);
+ const purchaseModel = product.toPurchaseModel(offerId);
+ const entitlements = await Qonversion.getSharedInstance().purchase(purchaseModel);
console.log('Qonversion purchase:', entitlements, productId);
} catch (e) {
console.log('Qonversion purchase failed', e);
}
},
- async purchaseProduct() {
- const productId = document.getElementById('purchase-product-id').value;
+ async updatePurchase() {
+ const productId = document.getElementById('update-product-id').value;
+ const oldProductId = document.getElementById('update-product-old-id').value;
const products = await Qonversion.getSharedInstance().products();
const product = products.get(productId);
try {
if (product) {
- const entitlements = await Qonversion.getSharedInstance().purchaseProduct(product);
- console.log('Qonversion purchaseProduct:', entitlements, product);
+ const purchaseUpdateModel = product.toPurchaseUpdateModel(oldProductId, Qonversion.PurchaseUpdatePolicy.CHARGE_FULL_PRICE);
+ const entitlements = await Qonversion.getSharedInstance().updatePurchase(purchaseUpdateModel);
+ console.log('Qonversion updatePurchase:', entitlements, product);
} else {
- console.log('Qonversion purchaseProduct:', 'product not found', productId);
+ console.log('Qonversion updatePurchase:', 'product not found', productId);
}
} catch (e) {
- console.log('Qonversion purchaseProduct failed', e);
+ console.log('Qonversion updatePurchase failed', e);
}
},
diff --git a/sample/yarn.lock b/sample/yarn.lock
index 975b197..b03d976 100644
--- a/sample/yarn.lock
+++ b/sample/yarn.lock
@@ -184,7 +184,7 @@ cordova-plugin-device@^2.1.0:
integrity sha512-FU0Lw1jZpuKOgG4v80LrfMAOIMCGfAVPumn7AwaX9S1iU/X3OPZUyoKUgP09q4bxL35IeNPkqNWVKYduAXZ1sg==
"cordova-plugin-qonversion@file:../plugin":
- version "4.2.0"
+ version "4.3.0"
resolved "file:../plugin"
cross-spawn@^7.0.1, cross-spawn@^7.0.3:
@@ -276,7 +276,17 @@ fs-extra@^10.1.0:
jsonfile "^6.0.1"
universalify "^2.0.0"
-fs-extra@^9.0.0, fs-extra@^9.1.0:
+fs-extra@^9.0.0:
+ version "9.1.0"
+ resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz"
+ integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
+ dependencies:
+ at-least-node "^1.0.0"
+ graceful-fs "^4.2.0"
+ jsonfile "^6.0.1"
+ universalify "^2.0.0"
+
+fs-extra@^9.1.0:
version "9.1.0"
resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz"
integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==
@@ -365,10 +375,10 @@ ios-sim@^8.0.2:
plist "^3.0.1"
simctl "^2"
-is-core-module@^2.11.0:
- version "2.12.1"
- resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz"
- integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==
+is-core-module@^2.13.0:
+ version "2.13.0"
+ resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz"
+ integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==
dependencies:
has "^1.0.3"
@@ -571,11 +581,11 @@ rechoir@^0.6.2:
resolve "^1.1.6"
resolve@^1.1.6:
- version "1.22.2"
- resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz"
- integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
+ version "1.22.4"
+ resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz"
+ integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==
dependencies:
- is-core-module "^2.11.0"
+ is-core-module "^2.13.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"