cc.fovea.cordova.purchase
Version:
Cordova Purchase plugin for iOS, Android, Windows (AppStore, Play, UWP)
380 lines (364 loc) • 13 kB
JavaScript
/// ### Philosophy
///
/// The `store` API is mostly events based. As a user of this plugin,
/// you will have to register listeners to changes happening to the products
/// you register.
///
/// The core of the listening mechanism is the [`when()`](#when) method. It allows you to
/// be notified of changes to one or a set of products using a [`query`](#queries) mechanism:
/// ```js
/// store.when("product").updated(refreshScreen);
/// store.when("full version").owned(unlockApp);
/// store.when("subscription").approved(serverCheck);
/// store.when("downloadable content").downloaded(showContent);
/// etc.
/// ```
///
/// The `updated` event is fired whenever one of the fields of a product is
/// changed (its `owned` status for instance).
///
/// This event provides a generic way to track the statuses of your purchases,
/// to unlock features when needed and to refresh your views accordingly.
///
/// ### Registering products
///
/// The store needs to know the type and identifiers of your products before you
/// can use them in your code.
///
/// Use [`store.register()`](#register) before your first call to
/// [`store.refresh()`](#refresh).
///
/// Once registered, you can use [`store.get()`](#get) to retrieve
/// the [`product object`](#product) from the store.
///
/// ```js
/// store.register({
/// id: "cc.fovea.purchase.consumable1",
/// alias: "100 coins",
/// type: store.CONSUMABLE
/// });
/// ...
/// var p = store.get("100 coins");
/// // or
/// var p = store.get("cc.fovea.purchase.consumable1");
/// ```
///
/// The product `id` and `type` have to match products defined in your
/// Apple and Google developer consoles.
///
/// Learn how to do that in [HOWTO: Create New Products](https://github.com/j3k0/cordova-plugin-purchase/wiki/HOWTO#create-new-products).
///
/// ### Displaying products
///
/// Right after you registered your products, nothing much is known about them
/// except their `id`, `type` and an optional `alias`.
///
/// When you perform the initial [`refresh()`](#refresh) call, the store's server will
/// be contacted to load informations about the registered products: human
/// readable `title` and `description`, `price`, etc.
///
/// This isn't an optional step as some despotic store owners (like Apple) require you
/// to display information about a product as retrieved from their server: no
/// hard-coding of price and title allowed! This is also convenient for you
/// as you can change the price of your items knowing that it'll be reflected instantly
/// on your clients' devices.
///
/// However, the information may not be available when the first view that needs
/// them appears on screen. For you, the best option is to have your view monitor
/// changes made to the product.
///
/// #### monitor changes
///
/// Let's demonstrate this with an example:
///
/// ```js
/// // method called when the screen showing your purchase is made visible
/// function show() {
/// render();
/// store.when("cc.fovea.test1").updated(render);
/// }
///
/// function render() {
///
/// // Get the product from the pool.
/// var product = store.get("cc.fovea.test1");
///
/// if (!product) {
/// $el.html("");
/// }
/// else if (product.state === store.REGISTERED) {
/// $el.html("<div class=\"loading\" />");
/// }
/// else if (product.state === store.INVALID) {
/// $el.html("");
/// }
/// else {
/// // Good! Product loaded and valid.
/// $el.html(
/// "<div class=\"title\">" + product.title + "</div>"
/// + "<div class=\"description\">" + product.description + "</div>"
/// + "<div class=\"price\">" + product.price + "</div>"
/// );
///
/// // Is this product owned? Give him a special class.
/// if (product.owned)
/// $el.addClass("owned");
/// else
/// $el.removeClass("owned");
///
/// // Is an order for this product in progress? Can't be ordered right now?
/// if (product.canPurchase)
/// $el.addClass("can-purchase");
/// else
/// $el.removeClass("can-purchase");
/// }
/// }
///
/// // method called when the view is hidden
/// function hide() {
/// // stop monitoring the product
/// store.off(render);
/// }
/// ```
///
/// In this example, `render` redraw the purchase element whatever
/// happens to the product. When the view is hidden, we stop listening to changes
/// (`store.off(render)`).
///
/// ### <a name="purchasing"></a> Purchasing
///
/// #### initiate a purchase
///
/// Purchases are initiated using the [`store.order()`](#order) method.
///
/// The store will manage the internal purchase flow that'll end:
///
/// - with an `approved` [event](#events). The product enters the `APPROVED` state.
/// - with a `cancelled` [event](#events). The product gets back to the `VALID` state.
/// - with an `error` [event](#events). The product gets back to the `VALID` state.
///
/// See [product life-cycle](#life-cycle) for details about product states.
///
/// #### finish a purchase
///
/// Once the transaction is approved, the product still isn't owned: the store needs
/// confirmation that the purchase was delivered before closing the transaction.
///
/// To confirm delivery, you'll use the [`product.finish()`](#finish) method.
///
/// #### example usage
///
/// During initialization:
/// ```js
/// store.when("extra chapter").approved(function(product) {
/// // download the feature
/// app.downloadExtraChapter().then(function() {
/// product.finish();
/// });
/// });
/// ```
///
/// When the purchase button is clicked:
/// ```js
/// store.order("full version");
/// ```
///
/// #### un-finished purchases
///
/// If your app wasn't able to deliver the content, `product.finish()` won't be called.
///
/// Don't worry: the `approved` event will be re-triggered the next time you
/// call [`store.refresh()`](#refresh), which can very well be the next time
/// the application starts. Pending transactions are persistant.
///
/// #### simple case
///
/// In the most simple case, where:
///
/// - delivery of purchases is only local ;
/// - you don't want to implement receipt validation ;
///
/// you may just want to finish all purchases automatically. You can do it this way:
/// ```js
/// store.when("product").approved(function(p) {
/// p.finish();
/// });
/// ```
///
/// NOTE: the "product" query will match any purchases (see [here](#queries) to learn more details about queries).
///
/// ### Receipt validation
///
/// Some unthoughtful users will try to use fake "purchases" to access features
/// they should normally pay for. If that's a concern, you should implement
/// receipt validation, ideally server side validation.
///
/// When a purchase has been approved by the store, it's enriched with
/// [transaction](#transactions) information (`product.transaction` attribute).
///
/// To verfify a purchase you'll have to do three things:
///
/// - configure the [validator](#validator).
/// - call [`product.verify()`](#verify) from the `approved` event,
/// before finishing the transaction.
/// - finish the transaction when transaction is `verified`.
///
/// #### example using a validation URL
///
/// ```js
/// store.validator = "http://192.168.0.7:1980/check-purchase";
///
/// store.when("my stuff").approved(function(product) {
/// product.verify();
/// });
///
/// store.when("my stuff").verified(function(product) {
/// product.finish();
/// });
/// ```
///
/// For an example using a validation callback instead, see the documentation of [the validator method](#validator).
///
/// ### Subscriptions
///
/// For subscription, you MUST implement remote [receipt validation](#receipt-validation).
///
/// If the validator returns a `store.PURCHASE_EXPIRED` error code, the subscription will
/// automatically loose its `owned` status.
///
/// Typically, you'll enable and disable access to your content this way.
/// ```js
/// store.when("cc.fovea.subcription").updated(function(product) {
/// if (product.owned)
/// app.subscriberMode();
/// else
/// app.guestMode();
/// });
/// ```
// ### Security
//
// You will initiate a purchase with `store.order("product.id")`.
//
// 99% of the times, the purchase will be approved immediately by billing system.
//
// However, connection can be lost between you sending a purchase request
// and the server answering to you. In that case, the purchase shouldn't
// be lost (because the user paid for it), that's why the store will notify
// you of an approved purchase during the next application startup.
//
// The same can also happen if the user bought a product from another device, using his
// same account.
//
// For that reason, you should register all your features-unlocking listeners at
// startup, before the first call to `store.refresh()`
//
///
/// # <a name="store"></a>*store* object ##
///
/// `store` is the global object exported by the purchase plugin.
///
/// As with any other plugin, this object shouldn't be used before
/// the "deviceready" event is fired. Check cordova's documentation
/// for more details if needed.
///
/// Find below all public attributes and methods you can use.
///
var store = {};
/// ## <a name="verbosity"></a>*store.verbosity*
///
/// The `verbosity` property defines how much you want `store.js` to write on the console. Set to:
///
/// - `store.QUIET` or `0` to disable all logging (default)
/// - `store.ERROR` or `1` to show only error messages
/// - `store.WARNING` or `2` to show warnings and errors
/// - `store.INFO` or `3` to also show information messages
/// - `store.DEBUG` or `4` to enable internal debugging messages.
///
/// See the [logging levels](#logging-levels) constants.
store.verbosity = 0;
/// ## <a name="sandbox"></a>*store.sandbox*
///
/// The `sandbox` property defines if you want to invoke the platform purchase sandbox
///
/// - Windows will use the IAP simulator if true (see Windows docs)
/// - Android: NOT IN USE
/// - iOS: NOT IN USE
store.sandbox = false;
// #include "constants.js"
// #include "product.js"
// #include "error.js"
// #include "register.js"
// #include "get.js"
// #include "when.js"
// #include "once.js"
// #include "order.js"
// #include "ready.js"
// #include "off.js"
// #include "validator.js"
// #include "refresh.js"
///
/// ## <a name="manageSubscriptions"></a>*store.manageSubscriptions()*
///
/// Opens the Manage Subscription page (AppStore, Play, Microsoft, ...),
/// where the user can change his/her subscription settings or unsubscribe.
///
/// ##### example usage
///
/// ```js
/// store.manageSubscriptions();
/// ```
///
///
/// ## <a name="manageBilling"></a>*store.manageBilling()*
///
/// Opens the Manage Billing page (AppStore, Play, Microsoft, ...),
/// where the user can update his/her payment methods.
///
/// ##### example usage
///
/// ```js
/// store.manageBilling();
/// ```
///
///
/// ## <a name="redeem"></a>*store.redeem()*
///
/// Redeems a promotional offer from within the app.
///
/// * On iOS, calling `store.redeem()` will open the Code Redemption Sheet.
/// * See the [offer codes documentation](https://developer.apple.com/app-store/subscriptions/#offer-codes) for details.
/// * This call does nothing on Android and Microsoft UWP.
///
/// ##### example usage
///
/// ```js
/// store.redeem();
/// ```
// #include "log.js"
// #include "metadata.js"
///
/// #### <a name="getGroup"></a>`store.getGroup(groupId)` ##
///
/// Return all products member of a given subscription group.
///
store.getGroup = function(groupId) {
if (!groupId) return [];
return store.products.filter(function(product) {
return product.group === groupId;
});
};
/// # Random Tips
///
/// - Sometimes during development, the queue of pending transactions fills up on your devices. Before doing anything else you can set `store.autoFinishTransactions` to `true` to clean up the queue. Beware: **this is not meant for production**.
/// - The plugin will auto refresh the status of user's purchases every 24h. You can change this interval by setting `store.autoRefreshIntervalMillis` to another interval (before calling `store.init()`). (this isn't implemented on iOS since [it isn't necessary](https://github.com/j3k0/cordova-plugin-purchase/issues/777#issuecomment-481633968)). Set to `0` to disable auto-refreshing.
///
/// # internal APIs
/// USE AT YOUR OWN RISKS
// #include "products.js"
// #include "product-internal.js"
// #include "queries.js"
// #include "trigger.js"
// #include "error-callbacks.js"
// #include "utils.js"
// #include "polyfills.js"
store.version = '10.5.3';