cordova-plugin-purchase
Advanced tools
Comparing version 10.2.0 to 10.3.0
@@ -395,4 +395,4 @@ # API Documentation | ||
- `product.lastRenewalDate` - Latest date a subscription was renewed (a javascript Date) | ||
- `product.billingPeriod` - Duration of the billing period for a subscription, in the units specified by the `billingPeriodUnit` property. | ||
- `product.billingPeriodUnit` - Units of the billing period for a subscription. Possible values: Minute, Hour, Day, Week, Month, Year. | ||
- `product.billingPeriod` - Duration of the billing period for a subscription, in the units specified by the `billingPeriodUnit` property. (_not available on iOS < 11.2_) | ||
- `product.billingPeriodUnit` - Units of the billing period for a subscription. Possible values: Minute, Hour, Day, Week, Month, Year. (_not available on iOS < 11.2_) | ||
- `product.trialPeriod` - Duration of the trial period for the subscription, in the units specified by the `trialPeriodUnit` property (windows only) | ||
@@ -707,2 +707,8 @@ - `product.trialPeriodUnit` - Units of the trial period for a subscription (windows only) | ||
the same group, `oldSku` will be set automatically for you (see `product.group`). | ||
- `prorationMode`, a string that describe the proration mode to apply when upgrading/downgrading a subscription (with `oldSku`) on Android. See https://developer.android.com/google/play/billing/subs#change | ||
**Possible values:** | ||
- `DEFERRED` - Replacement takes effect when the old plan expires, and the new price will be charged at the same time. | ||
- `IMMEDIATE_AND_CHARGE_PRORATED_PRICE` - Replacement takes effect immediately, and the billing cycle remains the same. | ||
- `IMMEDIATE_WITHOUT_PRORATION` - Replacement takes effect immediately, and the new price will be charged on next recurrence time. | ||
- `IMMEDIATE_WITH_TIME_PRORATION` - Replacement takes effect immediately, and the remaining time will be prorated and credited to the user. | ||
- `discount`, a object that describes the discount to apply with the purchase (iOS only): | ||
@@ -959,6 +965,8 @@ - `id`, discount identifier | ||
- `.cancelled(fn)` - Calls `fn` when the user cancelled the refresh request. | ||
- `.failed(fn)` - Calls `fn` when restoring purchases failed. | ||
- `.completed(fn)` - Calls `fn` when the queue of previous purchases have been processed. | ||
At this point, all previously owned products should be in the approved state. | ||
- `.finished(fn)` - Calls `fn` when all purchased in the approved state have been finished | ||
or expired. | ||
- `.finished(fn)` - Calls `fn` when the restore is finished, i.e. it has failed, been cancelled, | ||
or all purchased in the approved state have been finished or expired. | ||
@@ -965,0 +973,0 @@ In the case of the restore purchases call, you will want to hide any progress bar when the |
@@ -27,9 +27,7 @@ # iOS Configuration | ||
They auto-renew 5 times and then they stop, | ||
so after 25 minutes you will get the 21006 error. | ||
However even when repurchasing the same subscription it will NOT auto-renew | ||
again on the same test account since it has already auto-renewed 5 times. | ||
So if you want to test renewal and you have been messing with these | ||
subscriptions for a while you need to create a new itunes connect test user. | ||
so after 25 minutes your product will expire. | ||
If you have any issue repurchasing the same subscription, or it will NOT auto-renew again on the same test account, you should be able to fix this by creating a new itunes connect test user. | ||
### Hosted content | ||
@@ -36,0 +34,0 @@ |
@@ -11,1 +11,5 @@ # Troubleshooting | ||
See: https://github.com/j3k0/cordova-plugin-purchase/issues/76#issuecomment-407454342 | ||
#### Android - Google Playstore API V3 | ||
When you receive the information that you need to switch to the billing v3 API. In most cases this is because you have not yet updated your server side checks. It seems these still use the V2 API. | ||
This is usually due to the server validation you have created yourself. Alternatively, you can use https://billing.fovea.cc/. |
{ | ||
"name": "cordova-plugin-purchase", | ||
"version": "10.2.0", | ||
"version": "10.3.0", | ||
"description": "Cordova Purchase plugin for iOS, Android, Windows (AppStore, Play, UWP)", | ||
@@ -5,0 +5,0 @@ "cordova": { |
@@ -46,2 +46,20 @@ declare var store: IapStore.IStore; | ||
export type IAndroidProrationMode = | ||
'IMMEDIATE_WITH_TIME_PRORATION' | ||
| 'IMMEDIATE_AND_CHARGE_PRORATED_PRICE' | ||
| 'IMMEDIATE_WITHOUT_PRORATION' | ||
| 'DEFERRED'; | ||
export interface IAdditionalData { | ||
oldSku?: string | ||
oldPurchaseToken?: string; | ||
prorationMode?: IAndroidProrationMode; | ||
/** @deprecated | ||
* use oldSku instead. */ | ||
oldPurchasedSkus?: string[]; | ||
/** @deprecated | ||
* removed in Google Play Billing library v3 */ | ||
developerPayload?: string; | ||
} | ||
export interface IStore { | ||
@@ -118,3 +136,3 @@ FREE_SUBSCRIPTION: StoreProductType; | ||
off(callback: Function): void; | ||
order(id: string, additionalData?: null | { oldPurchasedSkus: string[] } | { developerPayload: string }): void; | ||
order(id: string, additionalData?: null | IAdditionalData): void; | ||
} | ||
@@ -121,0 +139,0 @@ |
@@ -27,2 +27,8 @@ (function() { | ||
/// the same group, `oldSku` will be set automatically for you (see `product.group`). | ||
/// - `prorationMode`, a string that describe the proration mode to apply when upgrading/downgrading a subscription (with `oldSku`) on Android. See https://developer.android.com/google/play/billing/subs#change | ||
/// **Possible values:** | ||
/// - `DEFERRED` - Replacement takes effect when the old plan expires, and the new price will be charged at the same time. | ||
/// - `IMMEDIATE_AND_CHARGE_PRORATED_PRICE` - Replacement takes effect immediately, and the billing cycle remains the same. | ||
/// - `IMMEDIATE_WITHOUT_PRORATION` - Replacement takes effect immediately, and the new price will be charged on next recurrence time. | ||
/// - `IMMEDIATE_WITH_TIME_PRORATION` - Replacement takes effect immediately, and the remaining time will be prorated and credited to the user. | ||
/// - `discount`, a object that describes the discount to apply with the purchase (iOS only): | ||
@@ -29,0 +35,0 @@ /// - `id`, discount identifier |
@@ -285,3 +285,5 @@ /*global storekit */ | ||
loaded = true; | ||
var ready = store.ready.bind(store, true); | ||
var ready = function() { | ||
store.ready(true); | ||
}; | ||
store.update(ready, ready, true); | ||
@@ -347,3 +349,3 @@ }, 1); | ||
product.set("state", store.INITIATED); | ||
storekit.refreshReceipts(); // We've asked for user password already anyway. | ||
// storekit.refreshReceipts(); // We've asked for user password already anyway. | ||
}); | ||
@@ -602,3 +604,6 @@ } | ||
}); | ||
store.trigger('refresh-failed'); | ||
if (errorCode === store.ERR_PAYMENT_CANCELLED) | ||
store.trigger('refresh-cancelled'); | ||
else | ||
store.trigger('refresh-failed'); | ||
} | ||
@@ -715,5 +720,7 @@ | ||
var now = +new Date(); | ||
// finds a product that is both owned and expired more than 1 minute ago | ||
var expired = store.products.find(function(product) { | ||
return product.owned && now > +product.expiryDate + 60000; | ||
}); | ||
// if one is found, refresh purchases using the validator (if setup) | ||
if (expired) { | ||
@@ -720,0 +727,0 @@ store.update(); |
@@ -409,7 +409,36 @@ (function() { | ||
// it's replaced). | ||
if (product.group && !a.oldSku) { | ||
store.getGroup(product.group).forEach(function(otherProduct) { | ||
if (isPurchased(otherProduct)) | ||
a.oldSku = otherProduct.id; | ||
}); | ||
if (product.group) { | ||
if (!a.oldPurchaseToken && !a.oldSku) { | ||
// If neither of the oldPurchaseToken and oldSku are specified, | ||
// look in the product group for an owned product. | ||
// Automatically set oldSku and oldPurchaseToken if one is found. | ||
store.getGroup(product.group).forEach(function(otherProduct) { | ||
if (isPurchased(otherProduct)) { | ||
a.oldSku = otherProduct.id; | ||
a.oldPurchaseToken = | ||
otherProduct.transaction ? | ||
otherProduct.transaction.purchaseToken : | ||
null; | ||
} | ||
}); | ||
} | ||
else if (a.oldSku && !a.oldPurchaseToken) { | ||
// If only oldSku is set, automatically set oldPurchaseToken. | ||
var otherProduct = store.get(a.oldSku); | ||
if (otherProduct && otherProduct.transaction) { | ||
a.oldPurchaseToken = otherProduct.transaction.purchaseToken; | ||
} | ||
} | ||
else if (a.oldPurchaseToken && !a.oldSku) { | ||
// If only oldPurchaseToken is set, automatically set oldSku. | ||
store.products.forEach(function(otherProduct) { | ||
var otherPurchaseToken = | ||
otherProduct.transaction ? | ||
otherProduct.transaction.purchaseToken : | ||
null; | ||
if (otherPurchaseToken == a.oldPurchaseToken) { | ||
a.oldSku = otherProduct.id; | ||
} | ||
}); | ||
} | ||
} | ||
@@ -416,0 +445,0 @@ }; |
@@ -131,4 +131,4 @@ (function() { | ||
/// - `product.lastRenewalDate` - Latest date a subscription was renewed (a javascript Date) | ||
/// - `product.billingPeriod` - Duration of the billing period for a subscription, in the units specified by the `billingPeriodUnit` property. | ||
/// - `product.billingPeriodUnit` - Units of the billing period for a subscription. Possible values: Minute, Hour, Day, Week, Month, Year. | ||
/// - `product.billingPeriod` - Duration of the billing period for a subscription, in the units specified by the `billingPeriodUnit` property. (_not available on iOS < 11.2_) | ||
/// - `product.billingPeriodUnit` - Units of the billing period for a subscription. Possible values: Minute, Hour, Day, Week, Month, Year. (_not available on iOS < 11.2_) | ||
/// - `product.trialPeriod` - Duration of the trial period for the subscription, in the units specified by the `trialPeriodUnit` property (windows only) | ||
@@ -232,3 +232,3 @@ /// - `product.trialPeriodUnit` - Units of the trial period for a subscription (windows only) | ||
if (dataTransaction) { | ||
that.transaction = Object.assign(that.transaction || {}, dataTransaction); | ||
that.transaction = Object.assign({}, that.transaction || {}, dataTransaction); | ||
store._extractTransactionFields(that); | ||
@@ -288,8 +288,2 @@ that.trigger("updated"); | ||
}); | ||
if (getData(data, "latest_receipt")) { | ||
// when the server is making use of the latest_receipt, | ||
// there is no need to retry | ||
store.log.debug("verify -> server did use the latest_receipt, no retries"); | ||
nRetry = 999999; | ||
} | ||
if (data.code === store.PURCHASE_EXPIRED) { | ||
@@ -300,24 +294,14 @@ err = new store.Error({ | ||
}); | ||
that.set("expired", true); | ||
store.error(err); | ||
store.utils.callExternal('verify.error', errorCb, err); | ||
store.utils.callExternal('verify.done', doneCb, that); | ||
that.trigger("expired"); | ||
that.set("state", store.VALID); | ||
store.utils.callExternal('verify.expired', expiredCb, that); | ||
} | ||
if (data.code === store.PURCHASE_EXPIRED) { | ||
if (nRetry < 2 && store._refreshForValidation) { | ||
nRetry += 1; | ||
store._refreshForValidation(function() { | ||
delay(that, tryValidation, 300); | ||
}); | ||
} | ||
else { | ||
that.set("expired", true); | ||
store.error(err); | ||
store.utils.callExternal('verify.error', errorCb, err); | ||
store.utils.callExternal('verify.done', doneCb, that); | ||
that.trigger("expired"); | ||
that.set("state", store.VALID); | ||
store.utils.callExternal('verify.expired', expiredCb, that); | ||
} | ||
} | ||
else if (nRetry < 4) { | ||
// It failed... let's try one more time. Maybe the appStoreReceipt wasn't updated yet. | ||
nRetry += 1; | ||
delay(this, tryValidation, 1000 * nRetry * nRetry); | ||
delay(this, tryValidation, 1500 * nRetry * nRetry); | ||
} | ||
@@ -324,0 +308,0 @@ else { |
@@ -29,6 +29,8 @@ (function() { | ||
/// | ||
/// - `.cancelled(fn)` - Calls `fn` when the user cancelled the refresh request. | ||
/// - `.failed(fn)` - Calls `fn` when restoring purchases failed. | ||
/// - `.completed(fn)` - Calls `fn` when the queue of previous purchases have been processed. | ||
/// At this point, all previously owned products should be in the approved state. | ||
/// - `.finished(fn)` - Calls `fn` when all purchased in the approved state have been finished | ||
/// or expired. | ||
/// - `.finished(fn)` - Calls `fn` when the restore is finished, i.e. it has failed, been cancelled, | ||
/// or all purchased in the approved state have been finished or expired. | ||
/// | ||
@@ -74,29 +76,21 @@ /// In the case of the restore purchases call, you will want to hide any progress bar when the | ||
// refresh-completed is called when all owned products have been | ||
// sent to the approved state. | ||
store.once("", "refresh-completed", function() { | ||
if (events["refresh-completed"]) return; | ||
events["refresh-completed"] = true; | ||
store.when().updated(checkFinished); | ||
checkFinished(); // make sure this is called at least once | ||
}); | ||
// User callbacks for each type of events | ||
var callbacks = { | ||
"refresh-failed": [], | ||
"refresh-cancelled": [], | ||
"refresh-completed": [], | ||
"refresh-finished": [], | ||
}; | ||
// trigger the refresh-finished event when no more products are in the | ||
// approved state. | ||
function checkFinished() { | ||
if (events["refresh-finished"]) return; | ||
function isApproved(p) { return p.state === store.APPROVED; } | ||
if (store.products.filter(isApproved).length === 0) { | ||
// done processing | ||
store.off(checkFinished); | ||
events["refresh-finished"] = true; | ||
setTimeout(function() { | ||
// if "completed" triggers "finished", | ||
// the setTimeout guarantees calling order | ||
store.trigger("refresh-finished"); | ||
}, 100); | ||
} | ||
} | ||
// Setup our own event handlers | ||
store.once("", "refresh-failed", failed); | ||
store.once("", "refresh-cancelled", cancelled); | ||
store.once("", "refresh-completed", completed); | ||
store.once("", "refresh-finished", finished); | ||
store.error(error); | ||
// Return the promise object | ||
return { | ||
cancelled: genPromise("refresh-cancelled"), | ||
failed: genPromise("refresh-failed"), | ||
completed: genPromise("refresh-completed"), | ||
@@ -106,2 +100,3 @@ finished: genPromise("refresh-finished"), | ||
// A promise function calls the callback or registers it | ||
function genPromise(eventName) { | ||
@@ -112,6 +107,85 @@ return function(cb) { | ||
else | ||
store.once("", eventName, cb); | ||
callbacks[eventName].push(cb); | ||
return this; | ||
}; | ||
} | ||
// Call all user callbacks for a given event | ||
function callback(eventName) { | ||
callbacks[eventName].forEach(function(cb) { cb(); }); | ||
callbacks[eventName] = []; | ||
} | ||
// Delete user callbacks for a given event | ||
// Trigger the refresh-finished event when no more products are in the | ||
// approved state. | ||
function checkFinished() { | ||
if (events["refresh-finished"]) return; | ||
function isApproved(p) { return p.state === store.APPROVED; } | ||
if (store.products.filter(isApproved).length === 0) { | ||
// done processing | ||
store.off(checkFinished); | ||
finish(); | ||
} | ||
} | ||
// Remove base events handlers | ||
function off() { | ||
store.off(cancelled); | ||
store.off(completed); | ||
store.off(failed); | ||
store.off(checkFinished); | ||
store.off(error); | ||
} | ||
// Fire a base event | ||
function fire(eventName) { | ||
if (events[eventName]) return false; | ||
events[eventName] = true; | ||
callback(eventName); | ||
return true; | ||
} | ||
// Fire the refresh-finished event | ||
function finish() { | ||
off(); | ||
if (events["refresh-finished"]) return; | ||
events["refresh-finished"] = true; | ||
// setTimeout guarantees calling order | ||
setTimeout(function() { | ||
store.trigger("refresh-finished"); | ||
}, 100); | ||
} | ||
// refresh-cancelled called when the user cancelled the password popup | ||
function cancelled() { | ||
fire("refresh-cancelled"); | ||
finish(); | ||
} | ||
// refresh-cancelled called when restore purchases couldn't complete | ||
// (can't connect to store or user not allowed to make purchases) | ||
function failed() { | ||
fire("refresh-failed"); | ||
finish(); | ||
} | ||
function error() { | ||
fire("refresh-failed"); | ||
finish(); | ||
} | ||
// refresh-completed is called when all owned products have been | ||
// sent to the approved state. | ||
function completed() { | ||
if (fire("refresh-completed")) { | ||
store.when().updated(checkFinished); | ||
checkFinished(); // make sure this is called at least once | ||
} | ||
} | ||
function finished() { | ||
callback("refresh-finished"); | ||
} | ||
} | ||
@@ -118,0 +192,0 @@ |
@@ -364,2 +364,2 @@ /// ### Philosophy | ||
store.version = '10.2.0'; | ||
store.version = '10.3.0'; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1020863
18303