cc.fovea.cordova.purchase
Version:
Cordova Purchase plugin for iOS, Android, Windows (AppStore, Play, UWP)
145 lines (91 loc) • 5.29 kB
Markdown
# Contributor Guide
*(generated from source files using `make doc-contrib)`*
# iOS Implementation
The implementation of the unified API is a small layer
built on top of the legacy "PhoneGap-InAppPurchase-iOS" plugin.
This was first decided as a temporary "get-things-done" solution.
However, I found this ended-up providing a nice separation of concerns:
- the `platforms/ios-bridge.js` file exposes an API called `storekit` that matches the
iOS way of dealing with in-app purchases.
- It is where the dialog with the Obj-C part happens.
- It turns that into a javascript friendly API, close to the StoreKit API.
- There are some specifities to it, so if eventually some users want
to go for a platform specific implementation on iOS, they can!
- the `platforms/ios-adapter.js` connects the iOS `storekit` API with the
unified `store` API.
- It makes sure products are loaded from apple servers
- It reacts to product's changes of state, so that a product get's purchased
when `REQUESTED`, or finished when `FINISHED` for instance.
## Reacting to product state changes
The iOS implementation monitors products changes of state to trigger
`storekit` operations.
Please refer to the [product life-cycle section](api.md#life-cycle) of the documentation
for better understanding of the job of this event handlers.
#### initialize storekit
At first refresh, initialize the storekit API. See [`storekitInit()`](#storekitInit) for details.
#### initiate a purchase
When a product enters the store.REQUESTED state, initiate a purchase with `storekit`.
#### finish a purchase
When a product enters the store.FINISHED state, `finish()` the storekit transaction.
#### persist ownership
`storekit` doesn't provide a way to know which products have been purchases.
That is why we have to handle that ourselves, by storing the `OWNED` status of a product.
Note that, until Apple provides a mean to get notified to refunds, there's no way back.
A non-consumable product, once `OWNED` always will be.
http://stackoverflow.com/questions/6429186/can-we-check-if-a-users-in-app-purchase-has-been-refunded-by-apple
#### persist downloaded status
`storekit` doesn't provide a way to know which products have been downloaded.
That is why we have to handle that ourselves, by storing the `DOWNLOADED` status of a product.
A non-consumable product, once `OWNED` can always be re-downloaded for free.
## Initialization
### <a name="storekitInit"></a> *storekitInit()*
This funciton will initialize the storekit API.
This initiates a chain reaction including [`storekitReady()`](#storekitReady) and [`storekitLoaded()`](#storekitLoaded)
that will make sure products are loaded from server, set as `VALID` or `INVALID`, and eventually restored
to their proper `OWNED` status.
It also registers the `storekit` callbacks to get notified of events from the StoreKit API:
- [`storekitPurchasing()`](#storekitPurchasing)
- [`storekitPurchased()`](#storekitPurchased)
- [`storekitError()`](#storekitError)
## *storekit* events handlers
### <a name="storekitReady"></a> *storekitReady()*
Called when `storekit` has been initialized successfully.
Loads all registered products, triggers `storekitLoaded()` when done.
### <a name="storekitLoaded"></a> *storekitLoaded()*
Update the `store`'s product definitions when they have been loaded.
1. Set the products state to `VALID` or `INVALID`
2. Trigger the "loaded" event
3. Set the products state to `OWNED` (if it is so)
4. Set the store status to "ready".
Note: the execution of "ready" is deferred to make sure state
changes have been processed.
### <a name="storekitPurchasing"></a> *storekitPurchasing()*
Called by `storekit` when a purchase is in progress.
It will set the product state to `INITIATED`.
### <a name="storekitPurchased"></a> *storekitPurchased()*
Called by `storekit` when a purchase have been approved.
It will set the product state to `APPROVED` and associates the product
with the order's transaction identifier.
### <a name="storekitDeferred"></a> *storekitDeferred()*
Called by `storekit` when a purchase is deferred.
It will set the product state to `INITIATED` and product.deferred to true.
### <a name="storekitError"></a> *storekitError()*
Called by `storekit` when an error happens in the storekit API.
Will convert storekit errors to a [`store.Error`](api.md/#errors).
## Persistance of the *OWNED* status
#### *isOwned(productId)*
return true iff the product with given ID has been purchased and finished
during this or a previous execution of the application.
#### *setOwned(productId, value)*
store the boolean OWNED status of a given product.
## Persistance of the *DOWNLOADED* status
#### *isDownloaded(productId)*
return true if the product with given ID has been purchased and finished downloading
during this or a previous execution of the application.
#### *setDownloaded(productId, value)*
store the boolean DOWNLOADED status of a given product.
## Retry failed requests
When setup and/or load failed, the plugin will retry over and over till it can connect
to the store.
However, to be nice with the battery, it'll double the retry timeout each time.
Special case, when the device goes online, it'll trigger all retry callback in the queue.