diff --git a/.jazzy.yaml b/.jazzy.yaml new file mode 100644 index 0000000..c63591e --- /dev/null +++ b/.jazzy.yaml @@ -0,0 +1,52 @@ +# `jazzy --help config` + +output: docs +clean: true +author: Iridescent +author_url: https://iridescent.dev +module: InAppPurchaseLib +title: InAppPurchaseLib documentation +copyright: "Copyright © 2020 [Iridescent](https://iridescent.dev)." +documentation: Documentation/*/*.md +abstract: Documentation/*.md +github_url: https://github.com/iridescent-dev/iap-swift-lib +hide_documentation_coverage: false +custom_categories: + - name: "Getting Started" + children: + - "Installation" + - "Micro Example" + - "License" + - name: "Usage" + children: + - "Initialization" + - "Displaying products" + - "Displaying subscriptions" + - "Refreshing" + - "Purchasing" + - "Handling purchases" + - "Restoring purchases" + - "Displaying products with purchases" + - "Errors" + - "Analytics" + - "Server integration" + - name: "API documentation" + children: + - InAppPurchase + - InAppPurchaseLib + - DefaultPurchaseDelegate + - IAPPurchaseDelegate + - IAPProduct + - IAPProductType + - SKProduct + - IAPPeriodFormat + - IAPPurchaseCallback + - IAPRefreshCallback + - IAPPurchaseResult + - IAPRefreshResult + - IAPPurchaseResultState + - IAPRefreshResultState + - IAPError + - IAPErrorCode + - IAPErrorProtocol +theme: fullwidth diff --git a/Documentation/API documentation.md b/Documentation/API documentation.md new file mode 100644 index 0000000..3614965 --- /dev/null +++ b/Documentation/API documentation.md @@ -0,0 +1,20 @@ +# Classes and Protocols + +The most important class is `InAppPurchase`. All the functions you need are defined in this class. + +If you have *consumable* and/or *non-renewing subscription* products in your application, you must have a class that adopts the `IAPPurchaseDelegate` protocol. + +# Products +* Input: the library requires an array of `IAPProduct` when it is initialized. + +* Output: the library will returns [SKProduct](https://developer.apple.com/documentation/storekit/skproduct) extended with helpful methods. See the [`SKProduct` extension](Extensions/SKProduct.html). + +# Callbacks +`refresh()`, `purchase()` and `restorePurchases()` are asynchronous functions. You must provide a callback that will allow you to perform actions depending on the result. + +* For `refresh()` and `restorePurchases()` functions, the result will be `IAPRefreshResult`. + +* For `purchase()` function, the result will be `IAPPurchaseResult`. + +# Errors +When calling `refresh()`, `purchase()` or `restorePurchases()`, the callback can return an `IAPError` if the state is `failed`. Look at `IAPErrorCode` to see the list of error codes you can receive. diff --git a/Documentation/Getting Started.md b/Documentation/Getting Started.md new file mode 100644 index 0000000..5f64fb2 --- /dev/null +++ b/Documentation/Getting Started.md @@ -0,0 +1,10 @@ +If you haven't already, I highly recommend your read the *Overview* and *Preparing* section of Apple's [In-App Purchase official documentation](https://developer.apple.com/in-app-purchase). + +## Requirements +* Configure your App and Xcode to support In-App Purchases. + * [AppStore Connect Setup](https://help.apple.com/app-store-connect/#/devb57be10e7) +* Create and configure your [Fovea.Billing](https://billing.fovea.cc/?ref=iap-swift-lib) project account: + * Set your bundle ID + * The iOS Shared Secret (or shared key) is to be retrieved from [AppStoreConnect](https://appstoreconnect.apple.com/) + * The iOS Subscription Status URL (only if you want subscriptions) + diff --git a/Documentation/Getting Started/Installation.md b/Documentation/Getting Started/Installation.md new file mode 100644 index 0000000..c14c162 --- /dev/null +++ b/Documentation/Getting Started/Installation.md @@ -0,0 +1,14 @@ +# Installation +

+ +

+ +* Select your project in Xcode +* Go to the section *Swift Package* +* Click on *(+) Add Package Dependency* +* Copy the Git URL: *https://github.com/iridescent-dev/iap-swift-lib.git* +* Click on *Next* > *Next* +* Make sure your project is selected in *Add to target* +* Click on *Finish* + +*Note:* You have to `import InAppPurchaseLib` wherever you use the library. diff --git a/Documentation/Getting Started/Micro Example.md b/Documentation/Getting Started/Micro Example.md new file mode 100644 index 0000000..2491fe3 --- /dev/null +++ b/Documentation/Getting Started/Micro Example.md @@ -0,0 +1,90 @@ +# Micro Example + + +```swift +/** AppDelegate.swift */ +import UIKit +import InAppPurchaseLib + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Initialize the library + InAppPurchase.initialize( + iapProducts: [ + IAPProduct(productIdentifier: "my_product", productType: .nonConsumable) + ], + validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678" + ) + return true + } + + func applicationWillTerminate(_ application: UIApplication) { + // Clean + InAppPurchase.stop() + } +} +``` + +```swift +/** ViewController.swift */ +import UIKit +import StoreKit +import InAppPurchaseLib + +class ViewController: UIViewController { + private var loaderView = LoaderView() + @IBOutlet weak var statusLabel: UILabel! + @IBOutlet weak var productTitleLabel: UILabel! + @IBOutlet weak var productDescriptionLabel: UILabel! + @IBOutlet weak var purchaseButton: UIButton! + @IBOutlet weak var restorePurchasesButton: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + // Add action for purchases and restore butons. + purchaseButton.addTarget(self, action: #selector(self.purchase), for: .touchUpInside) + restorePurchasesButton.addTarget(self, action: #selector(self.restorePurchases), for: .touchUpInside) + } + + override func viewWillAppear(_ animated: Bool) { + self.refreshView() + InAppPurchase.refresh(callback: { _ in + self.refreshView() + }) + } + + func refreshView() { + guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product") else { + self.productTitleLabel.text = "Product unavailable" + return + } + // Display product information. + productTitleLabel.text = product.localizedTitle + productDescriptionLabel.text = product.localizedDescription + purchaseButton.setTitle(product.localizedPrice, for: .normal) + + // Disable the button if the product has already been purchased. + if InAppPurchase.hasActivePurchase(for: "my_product") { + statusLabel.text = "OWNED" + purchaseButton.isPointerInteractionEnabled = false + } + } + + @IBAction func purchase(_ sender: Any) { + self.loaderView.show() + InAppPurchase.purchase( + productIdentifier: "my_product", + callback: { result in + self.loaderView.hide() + }) + } + + @IBAction func restorePurchases(_ sender: Any) { + self.loaderView.show() + InAppPurchase.restorePurchases(callback: { result in + self.loaderView.hide() + }) + } +} +``` diff --git a/InAppPurchaseLib.png b/Documentation/Images/InAppPurchaseLib.png similarity index 100% rename from InAppPurchaseLib.png rename to Documentation/Images/InAppPurchaseLib.png diff --git a/ScreenshotInstallation.png b/Documentation/Images/ScreenshotInstallation.png similarity index 100% rename from ScreenshotInstallation.png rename to Documentation/Images/ScreenshotInstallation.png diff --git a/Documentation/License.md b/Documentation/License.md new file mode 100644 index 0000000..ce44199 --- /dev/null +++ b/Documentation/License.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Iridescent + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Documentation/Usage.md b/Documentation/Usage.md new file mode 100644 index 0000000..e96c58e --- /dev/null +++ b/Documentation/Usage.md @@ -0,0 +1,8 @@ +The process of implementing in-app purchases involves several steps: +1. Displaying the list of purchasable products +2. Initiating a purchase +3. Delivering and finalizing a purchase +4. Checking the current ownership of non-consumables and subscriptions +5. Implementing the Restore Purchases button + +*Note:* You have to `import InAppPurchaseLib` wherever you use the library. diff --git a/Documentation/Usage/Analytics.md b/Documentation/Usage/Analytics.md new file mode 100644 index 0000000..946ebd1 --- /dev/null +++ b/Documentation/Usage/Analytics.md @@ -0,0 +1,42 @@ +# Analytics +Tracking the purchase flow is a common things in apps. Especially as it's core to your revenue model. + +We can track 5 events, which step in the purchase pipeline a user reached. +1. `purchase initiated` +2. `purchase cancelled` +3. `purchase failed` +4. `purchase deferred` +5. `purchase succeeded` + +Here's a quick example showing how to implement this correctly. + +``` swift +func makePurchase() { + Analytics.trackEvent("purchase initiated") + InAppPurchase.purchase( + productIdentifier: "my_product_id", + callback: { result in + switch result.state { + case .purchased: + // Reminder: We are not processing the purchase here, only updating your UI. + // That's why we do not send an event to analytics. + case .failed: + Analytics.trackEvent("purchase failed") + case .deferred: + Analytics.trackEvent("purchase deferred") + case .cancelled: + Analytics.trackEvent("purchase cancelled") + } + }) +} + +// IAPPurchaseDelegate implementation +func productPurchased(productIdentifier: String) { + Analytics.trackEvent("purchase succeeded") + InAppPurchase.finishTransactions(for: productIdentifier) +} +``` + +The important part to remember is that a purchase can occur outside your app (or be approved when the app is not running), that's why tracking `purchase succeeded` has to be part of the `productPurchased` delegate function. + +Refer to the [Consumables](handling-purchases.html#consumables) section to learn more about the `productPurchased` function. diff --git a/Documentation/Usage/Displaying products with purchases.md b/Documentation/Usage/Displaying products with purchases.md new file mode 100644 index 0000000..0ec900c --- /dev/null +++ b/Documentation/Usage/Displaying products with purchases.md @@ -0,0 +1,59 @@ +# Displaying products with purchases +In your store screen, where you present your products titles and prices with a purchase button, there are some cases to handle that we skipped. Owned products and deferred purchases. + +### Owned products +Non-consumables and active auto-renewing subscriptions cannot be purchased again. You should adjust your UI to reflect that state. Refer to `InAppPurchase.hasActivePurchase()` to and to the example later in this section. + +### Deferred purchases +Apple's **Ask to Buy** feature lets parents approve any purchases initiated by children, including in-app purchases. + +With **Ask to Buy** enabled, when a child requests to make a purchase, the app is notified that the purchase is awaiting the parent’s approval in the purchase callback: + +``` swift +InAppPurchase.purchase( + productIdentifier: productIdentifier, + callback: { result in + switch result.state { + case .deferred: + // Pending parent approval + } +}) +``` + +In the _deferred_ case, the child has been notified by StoreKit that the parents have to approve the purchase. He might then close the app and come back later. You don't have much to do, but to display in your UI that there is a purchase waiting for parental approval in your views. + +We will use the `hasDeferredTransaction` method: + +``` swift +InAppPurchase.hasDeferredTransaction(for productIdentifier: String) -> Bool +``` + +### Example +Here's an example that covers what has been discussed above. We will update our example `refreshView` function from before: + +``` swift +@objc func refreshView() { + guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else { + self.titleLabel.text = "Product unavailable" + return + } + self.titleLabel.text = product.localizedTitle + // ... + + // "Ask to Buy" deferred purchase waiting for parent's approval + if InAppPurchase.hasDeferredTransaction(for: "my_product_id") { + self.statusLabel.text = "Waiting for Approval..." + self.purchaseButton.isPointerInteractionEnabled = false + } + // "Owned" product + else if InAppPurchase.hasActivePurchase(for: "my_product_id") { + self.statusLabel.text = "OWNED" + self.purchaseButton.isPointerInteractionEnabled = false + } + else { + self.purchaseButton.isPointerInteractionEnabled = true + } +} +``` + +When a product is owned or has a deferred purchase, we make sure the purchase button is grayed out. We also use a status label to display some details. Of course, you are free to design your UI as you see fit. diff --git a/Documentation/Usage/Displaying products.md b/Documentation/Usage/Displaying products.md new file mode 100644 index 0000000..83c71b0 --- /dev/null +++ b/Documentation/Usage/Displaying products.md @@ -0,0 +1,36 @@ +# Displaying products +Let's start with the simplest case: you have a single product. + +You can retrieve all information about this product using the function `InAppPurchase.getProductBy(identifier: "my_product_id")`. This returns an [SKProduct](https://developer.apple.com/documentation/storekit/skproduct) extended with helpful methods. + +Those are the most important: + - `productIdentifier: String` - The string that identifies the product to the Apple AppStore. + - `localizedTitle: String` - The name of the product, in the language of the device, as retrieved from the AppStore. + - `localizedDescription: String` - A description of the product, in the language of the device, as retrieved from the AppStore. + - `localizedPrice: String` - The cost of the product in the local currency (_read-only property added by this library_). + +*Example*: + +You can add a function similar to this to your view. + +``` swift +@objc func refreshView() { + guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else { + self.titleLabel.text = "Product unavailable" + return + } + self.titleLabel.text = product.localizedTitle + self.descriptionLabel.text = product.localizedDescription + self.priceLabel.text = product.localizedPrice +} +``` + +This example assumes `self.titleLabel` is a UILabel, etc. + +Make sure to call this function when the view appears on screen, for instance by calling it from [`viewWillAppear`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621510-viewwillappear). + +``` swift +override func viewWillAppear(_ animated: Bool) { + self.refreshView() +} +``` diff --git a/Documentation/Usage/Displaying subscriptions.md b/Documentation/Usage/Displaying subscriptions.md new file mode 100644 index 0000000..0094c2e --- /dev/null +++ b/Documentation/Usage/Displaying subscriptions.md @@ -0,0 +1,36 @@ +# Displaying subscriptions +For subscription products, you also have some data about subscription periods and introductory offers. + + - `func hasIntroductoryPriceEligible() -> Bool` - The product has an introductory price the user is eligible to. + - `localizedSubscriptionPeriod: String?` - The period of the subscription. + - `localizedIntroductoryPrice: String?` - The cost of the introductory offer if available in the local currency. + - `localizedIntroductoryPeriod: String?` - The subscription period of the introductory offer. + - `localizedIntroductoryDuration: String?` - The duration of the introductory offer. + +**Example** + +``` swift +@objc func refreshView() { + guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else { + self.titleLabel.text = "Product unavailable" + return + } + self.titleLabel.text = product.localizedTitle + self.descriptionLabel.text = product.localizedDescription + + // Format price text. Example: "0,99€ / month for 3 months (then 3,99 € / month)" + var priceText = "\(product.localizedPrice) / \(product.localizedSubscriptionPeriod!)" + if product.hasIntroductoryPriceEligible() { + if product.introductoryPrice!.numberOfPeriods == 1 { + priceText = "\(product.localizedIntroductoryPrice!) for \(product.localizedIntroductoryDuration!)" + + " (then \(priceText))" + } else { + priceText = "\(product.localizedIntroductoryPrice!) / \(product.localizedIntroductoryPeriod!)" + + " for \(product.localizedIntroductoryDuration!) (then \(priceText))" + } + } + self.priceLabel.text = priceText +} +``` + +*Note:* You have to `import StoreKit` wherever you use `SKProduct`. diff --git a/Documentation/Usage/Errors.md b/Documentation/Usage/Errors.md new file mode 100644 index 0000000..a428e48 --- /dev/null +++ b/Documentation/Usage/Errors.md @@ -0,0 +1,20 @@ +# Errors + +When calling `refresh()`, `purchase()` or `restorePurchases()`, the callback can return an `IAPError` if the state is `failed`. +Here is the list of `IAPErrorCode` you can receive: + +* Errors returned by `refresh()`, `purchase()` or `restorePurchases()` + - `libraryNotInitialized` - You must call the `initialize` fuction before using the library. + - `bundleIdentifierInvalid` - The Bundle Identifier is invalid. + - `validatorUrlInvalid` - The Validator URL String is invalid. + - `refreshReceiptFailed` - Failed to refresh the App Store receipt. + - `validateReceiptFailed` - Failed to validate the App Store receipt with Fovea. + - `readReceiptFailed` - Failed to read the receipt validation. + +* Errors returned by `refresh()` + - `refreshProductsFailed` - Failed to refresh products from the App Store. + +* Errors returned by `purchase()` + - `productNotFound` - The product was not found on the App Store and cannot be purchased. + - `cannotMakePurchase` - The user is not allowed to authorize payments. + - `alreadyPurchasing` - A purchase is already in progress. diff --git a/Documentation/Usage/Handling purchases.md b/Documentation/Usage/Handling purchases.md new file mode 100644 index 0000000..06febe8 --- /dev/null +++ b/Documentation/Usage/Handling purchases.md @@ -0,0 +1,93 @@ +# Handling purchases +Finally, the magic happened: a user purchased one of your products! Let's see how we handle the different types of products. + +- [Non-Consumables](#non-consumables) +- [Auto-Renewable Subscriptions](#auto-renewable-subscriptions) +- [Consumables](#consumables) +- [Non-Renewing Subscriptions](#non-renewing-subscriptions) + + +## Non-Consumables +Wherever your app needs to know if a non-consumable product has been purchased, use `InAppPurchase.hasActivePurchase(for: +productIdentifier)`. This will return true if the user currently owns the product. + +**Note:** The last known state for the user's purchases is stored as [UserDefaults](https://developer.apple.com/documentation/foundation/userdefaults). As such, their status is always available to your app, even when offline. + +If you have a server that needs to know about the purchase. You should rely on Fovea's webhook instead of doing anything in here. We will see that later in the [Server integration](server-integration.html) section. + + +## Auto-Renewable Subscriptions +As with non-consumables, you will use `InAppPurchase.hasActivePurchase(for: productIdentifier)` to check if the user is an active subscriber to a given product. + +You might also like to call refresh regularly, for example when entering your main view. When appropriate, the library will refresh the receipt to detect subscription renewals or expiry. + +As we've seend in the [Refreshing](refreshing.html) section: + +``` swift +override func viewWillAppear(_ animated: Bool) { + self.refreshView() + InAppPurchase.refresh(callback: { _ in + self.refreshView() + }) +} +``` + +**Note:** Don't be reluctant to call `refresh()` often. Internally, the library ensures heavy operation are only performed if necessary: for example when a subscription just expired. So in 99% of cases this call will result in no-operations. + + +## Consumables +If the purchased products in a **consumable**, your app is responsible for delivering the purchase then acknowlege that you've done so. Delivering generally consists in increasing a counter for some sort of virtual currency. + +Your app can be notified of a purchase at any time. So the library asks you to provide an **IAPPurchaseDelegate** from initialization. + +In `InAppPurchase.initialize()`, we can pass an **IAPPurchaseDelegate** instance. This object implements the **productPurchased(productIdentifier:)** function, which is called whenever a purchase is approved. + +Here's a example implementation: + +``` swift +class AppDelegate: UIResponder, UIApplicationDelegate, IAPPurchaseDelegate { + ... + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + InAppPurchase.initialize( + iapProducts: [...], + iapPurchaseDelegate: self, // ADDED: iapPurchaseDelegate + validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678") + } + + // IAPPurchaseDelegate implementation + func productPurchased(productIdentifier: String) { + // TODO + } +} +``` + +It's also important to know that when a purchase is approved, money isn't yet to reach your bank account. You have to acknowledge delivery of the (virtual) item to finalize the transaction. That is why we have to call `InAppPurchase.finishTransactions(for: productIdentifier)` as soon as we delivered the product. + +**Example** + +Let's define a class that adopts the **IAPPurchaseDelegate** protocol, it can very well be your application delegate. + +``` swift +func productPurchased(productIdentifier: String) { + switch productIdenfier { + case "10_silver": + addSilver(10) + case "100_silver": + addSilver(100) + } + InAppPurchase.finishTransactions(for: productIdentifier) + Analytics.trackEvent("purchase succeeded", productIdentifier) +} +``` + +Here, we implement our own unlocking logic and call `InAppPurchase.finishTransactions()` afterward (assuming `addSilver` is synchronous). + +*Note:* `productPurchased` is called when a purchase has been confirmed by Fovea's receipt validator. If you have a server, he probably already has been notified of this purchase using the webhook. + +**Reminder**: Keep in mind that purchase notifications might occur even if you never called the `InAppPurchase.purchase()` function: purchases can be made from another device or the AppStore, they can be approved by parents when the app isn't running, purchase flows can be interupted, etc. The pattern above ensures your app is always ready to handle purchase events. + + +## Non-Renewing Subscriptions +For non-renewing subscriptions, delivering consists in increasing the amount of time a user can access a given feature. Apple doesn't manage the length and expiry of non-renewing subscriptions: you have to do this yourself, as for consumables. + +Basically, everything is identical to consumables. diff --git a/Documentation/Usage/Initialization.md b/Documentation/Usage/Initialization.md new file mode 100644 index 0000000..18f2e54 --- /dev/null +++ b/Documentation/Usage/Initialization.md @@ -0,0 +1,46 @@ +# Initialization +Before everything else the library must be initialized. This has to happen as soon as possible. A good way is to call the `InAppPurchase.initialize()` method when the application did finish launching. In the background, this will load your products and refresh the status of purchases and subscriptions. + +`InAppPurchase.initialize()` requires the following arguments: +* `iapProducts` - An array of `IAPProduct` +* `validatorUrlString` - The validator url retrieved from [Fovea](https://billing.fovea.cc/?ref=iap-swift-lib) + +Each `IAPProduct` contains the following fields: +* `productIdentifier` - The product unique identifier +* `productType` - The `IAPProductType` (*consumable*, *nonConsumable*, *nonRenewingSubscription* or *autoRenewableSubscription*) + +*Example:* + +A good place is generally in your application delegate's `didFinishLaunchingWithOptions` function, like below: + +``` swift +import InAppPurchaseLib + +class AppDelegate: UIResponder, UIApplicationDelegate, IAPPurchaseDelegate { + ... + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + InAppPurchase.initialize( + iapProducts: [ + IAPProduct(productIdentifier: "monthly_plan", productType: .autoRenewableSubscription), + IAPProduct(productIdentifier: "yearly_plan", productType: .autoRenewableSubscription), + IAPProduct(productIdentifier: "disable_ads", productType: .nonConsumable) + ], + validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678") + } + + func productPurchased(productIdentifier: String) { + // ... process purchase (we'll see that later) + } +} +``` + +You should also call the `stop` method when the application will terminate, for proper cleanup. +``` swift + func applicationWillTerminate(_ application: UIApplication) { + InAppPurchase.stop() + } +``` + +For more advanced use cases, in particular when you have implemented user login, you'll have to make some adjustments. We'll learn more about this in the [Server integration](server-integration.html) section. + +*Tip:* If initialization was successful, you should see a new receipt validation event in [Fovea's Dashboard](https://billing-dashboard.fovea.cc/events). diff --git a/Documentation/Usage/Purchasing.md b/Documentation/Usage/Purchasing.md new file mode 100644 index 0000000..aede98d --- /dev/null +++ b/Documentation/Usage/Purchasing.md @@ -0,0 +1,65 @@ +# Purchasing +The purchase process is generally a little bit more involving than most people would expect. Why is it not just: purchase → on success unlock the feature? + +Several reasons: +- In-app purchases can be initiated outside the app +- In-app purchases can be deferred, pending parental approval +- Apple wants to be sure you delivered the product before charging the user + +That is why the process looks like so: +- being ready to handle purchase events from app startup +- finalizing transactions when product delivery is complete +- sending purchase request, for which successful doesn't always mean complete + +### Initiating a purchase +To initiate a purchase, use the `InAppPurchase.purchase()` function. It takes the `productIdentifier` and a `callback` function, called when the purchase has been processed. + +**Important**: Do not process the purchase here, we'll handle that later! + +From this callback, you can for example unlock the UI by hiding your loading indicator and display a message to the user. + +*Example:* + +``` swift +self.loaderView.show() +InAppPurchase.purchase( + productIdentifier: "my_product_id", + callback: { _ in + self.loaderView.hide() +}) +``` + +This simple example locks the UI with a loader when the purchase is in progress. We'll see later how the purchase has to be processed by your applicaiton. + +The callback also gives more information about the outcome of the purchase, you might want to use it to update your UI as well. Note that some events are useful for analytics. So here's a more complete example. + +``` swift +self.loaderView.show() +InAppPurchase.purchase( + productIdentifier: "my_product_id", + callback: { result in + self.loaderView.hide() + + switch result.state { + case .purchased: + // Product successfully purchased + // Reminder: Do not process the purchase here, only update your UI. + // that's why we do not send data to analytics. + openThankYouScreen() + case .failed: + // Purchase failed + // - Human formated reason can be found in result.localizedDescription + // - More details in either result.skError or result.iapError + showError(result.localizedDescription) + case .deferred: + // The purchase is deferred, waiting for the parent's approval + openWaitingParentApprovalScreen() + case .cancelled: + // The user canceled the request, generally only useful for analytics. + } +}) +``` + +If the purchase fails, result will contain either `.skError`, a [`SKError`](https://developer.apple.com/documentation/storekit/skerror/code) from StoreKit, or `.iapError`, an [`IAPError`](errors.html). + +*Tip:* After a successful purchase, you should see a new transaction in [Fovea's dashboard](https://billing-dashboard.fovea.cc/transactions). diff --git a/Documentation/Usage/Refreshing.md b/Documentation/Usage/Refreshing.md new file mode 100644 index 0000000..ff76a77 --- /dev/null +++ b/Documentation/Usage/Refreshing.md @@ -0,0 +1,13 @@ +# Refreshing +Data might change or not be yet available when your "product" view is presented. In order to properly handle those cases, you should refresh your view after refreshing in-app products metadata. You want to be sure you're displaying up-to-date information. + +To achieve this, call `InAppPurchase.refresh()` when your view is presented. + +``` swift +override func viewWillAppear(_ animated: Bool) { + self.refreshView() + InAppPurchase.refresh(callback: { _ in + self.refreshView() + }) +} +``` diff --git a/Documentation/Usage/Restoring purchases.md b/Documentation/Usage/Restoring purchases.md new file mode 100644 index 0000000..2eab331 --- /dev/null +++ b/Documentation/Usage/Restoring purchases.md @@ -0,0 +1,25 @@ +# Restoring purchases +Except if you only sell consumable products, Apple requires that you provide a "Restore Purchases" button to your users. In general, it is found in your application settings. + +Call this method when this button is pressed. + +``` swift +@IBAction func restorePurchases(_ sender: Any) { + self.loaderView.show() + InAppPurchase.restorePurchases(callback: { result in + self.loaderView.hide() + switch result.state { + case .succeeded: + if result.addedPurchases > 0 { + print("Restore purchases successful.") + } else { + print("No purchase to restore.") + } + case .failed: + print("Restore purchases failed.") + } + }) +} +``` + +The `callback` method is called once the operation is complete. You can use it to unlock the UI, by hiding your loader for example, and display the adapted message to the user. diff --git a/Documentation/Usage/Server integration.md b/Documentation/Usage/Server integration.md new file mode 100644 index 0000000..ed35b28 --- /dev/null +++ b/Documentation/Usage/Server integration.md @@ -0,0 +1,21 @@ +# Server integration +In more advanced use cases, you have a server component. Users are logged in and you'll like to unlock the content for this user on your server. The safest approach is to setup a [Webhook on Fovea](https://billing.fovea.cc/documentation/webhook/?ref=iap-swift-lib). You'll receive notifications from Fovea that transaction have been processed and/or subscriptions updated. + +The information sent from Fovea has been verified from Apple's server, which makes it way more trustable than information sent from your app itself. + +To take advantage of this, you have to inform the library of your application username. This `applicationUsername` can be provided as a parameter of the `InAppPurchase.initialize` method and updated later by changing the associated property. + +*Example:* +``` swift +InAppPurchase.initialize( + iapProducts: [...], + validatorUrlString: "..."), + applicationUsername: UserSession.getUserId()) + +// later ... +InAppPurchase.applicationUsername = UserSession.getUserId() +``` + +If a user account is mandatory in your app, you will want to delay calls to `InAppPurchase.initialize()` to when your user's session is ready. + +Do not hesitate to [contact Fovea](mailto:support@fovea.cc) for help. diff --git a/README.md b/README.md index ee9697f..31b7d43 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,8 @@

- +

-> An easy-to-use library for In-App Purchases, using Fovea.Billing for receipts validation. - -- [Features](#features) -- [Getting Started](#getting-started) - - [Requirements](#requirements) - - [Installation](#installation) -- [Usage](#usage) - - [Initialization](#initialization) - - [Displaying products](#displaying-products) - - [Displaying subscriptions](#displaying-subscriptions) - - [Refreshing](#refreshing) - - [Purchasing](#purchasing) - - [Making a purchase](#making-a-purchase) - - [Processing purchases](#processing-purchases) - - [Restoring purchases](#restoring-purchases) - - [Purchased products](#purchased-products) - - [Purchases information](#purchases-information) - - [Errors](#errors) -- [Server integration](#server-integration) -- [Xcode Demo Project](#xcode-demo-project) -- [References](#references) -- [Troubleshooting](#troubleshooting) -- [License](#license) +> An easy-to-use Swift library for In-App Purchases, using Fovea.Billing for receipts validation. # Features @@ -39,21 +17,9 @@ * ✅ Server integration with a Webhook # Getting Started -If you haven't already, I highly recommend your read the *Overview* and *Preparing* section of Apple's [In-App Purchase official documentation](https://developer.apple.com/in-app-purchase) - -## Requirements -* Configure your App and Xcode to support In-App Purchases. - * [AppStore Connect Setup](https://help.apple.com/app-store-connect/#/devb57be10e7) -* Create and configure your [Fovea.Billing](https://billing.fovea.cc/?ref=iap-swift-lib) project account: - * Set your bundle ID - * The iOS Shared Secret (or shared key) is to be retrieved from [AppStoreConnect](https://appstoreconnect.apple.com/) - * The iOS Subscription Status URL (only if you want subscriptions) +If you haven't already, I highly recommend your read the *Overview* and *Preparing* section of Apple's [In-App Purchase official documentation](https://developer.apple.com/in-app-purchase). ## Installation -

- -

- * Select your project in Xcode * Go to the section *Swift Package* * Click on *(+) Add Package Dependency* @@ -64,492 +30,117 @@ If you haven't already, I highly recommend your read the *Overview* and *Prepari *Note:* You have to `import InAppPurchaseLib` wherever you use the library. +## Micro Example -# Usage - -The process of implementing in-app purchases involves several steps: -1. Displaying the list of purchasable products -2. Initiating a purchase -3. Delivering and finalizing a purchase -4. Checking the current ownership of non-consumables and subscriptions -5. Implementing the Restore Purchases button - -## Initialization -Before everything else the library must be initialized. This has to happen as soon as possible. A good way is to call the `InAppPurchase.initialize()` method when the application did finish launching. In the background, this will load your products and refresh the status of purchases and subscriptions. - -`InAppPurchase.initialize()` accepts the following arguments: -* `iapProducts` - An array of **IAPProduct** (REQUIRED) -* `validatorUrlString` - The validator url retrieved from [Fovea](https://billing.fovea.cc/?ref=iap-swift-lib) (REQUIRED) -* `applicationUsername` - The user name, if your app implements user login (optional) - -Each **IAPProduct** contains the following fields: -* `productIdentifier` - The product unique identifier -* `productType` - The **IAPProductType** (`consumable`, `nonConsumable`, `nonRenewingSubscription` or `autoRenewableSubscription`) - -*Example:* - -A good place is generally in your application delegate's `didFinishLaunchingWithOptions` function, like below: - -``` swift +```swift +/** AppDelegate.swift */ +import UIKit import InAppPurchaseLib -class AppDelegate: UIResponder, UIApplicationDelegate, IAPPurchaseDelegate { - ... +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Initialize the library InAppPurchase.initialize( iapProducts: [ - IAPProduct(productIdentifier: "monthly_plan", productType: .autoRenewableSubscription), - IAPProduct(productIdentifier: "yearly_plan", productType: .autoRenewableSubscription), - IAPProduct(productIdentifier: "disable_ads", productType: .nonConsumable) + IAPProduct(productIdentifier: "my_product", productType: .nonConsumable) ], - validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678") + validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678" + ) + return true } - func productPurchased(productIdentifier: String) { - // ... process purchase (we'll see that later) - } -} -``` - -You should also call the `stop` method when the application will terminate, for proper cleanup. -``` swift func applicationWillTerminate(_ application: UIApplication) { + // clean InAppPurchase.stop() } -``` - -For more advanced use cases, in particular when you have implemented user login, you'll have to make some adjustments. We'll learn more about this in the [Server integration](#server-integration) section. - -*Tip:* If initialization was successful, you should see a new receipt validation event in [Fovea's Dashboard](https://billing-dashboard.fovea.cc/events). - -## Displaying products -Let's start with the simplest case: you have a single product. - -You can retrieve all information about this product using the function `InAppPurchase.getProductBy(identifier: "my_product_id")`. This returns an [SKProduct](https://developer.apple.com/documentation/storekit/skproduct) extended with helpful methods. - -Those are the most important: - - `productIdentifier: String` - The string that identifies the product to the Apple AppStore. - - `localizedTitle: String` - The name of the product, in the language of the device, as retrieved from the AppStore. - - `localizedDescription: String` - A description of the product, in the language of the device, as retrieved from the AppStore. - - `localizedPrice: String` - The cost of the product in the local currency (_read-only property added by this library_). - -*Example*: - -You can add a function similar to this to your view. - -``` swift -@objc func refreshView() { - guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else { - self.titleLabel.text = "Product unavailable" - return - } - self.titleLabel.text = product.localizedTitle - self.descriptionLabel.text = product.localizedDescription - self.priceLabel.text = product.localizedPrice -} -``` - -This example assumes `self.titleLabel` is a UILabel, etc. - -Make sure to call this function when the view appears on screen, for instance by calling it from [`viewWillAppear`](https://developer.apple.com/documentation/uikit/uiviewcontroller/1621510-viewwillappear). - -``` swift -override func viewWillAppear(_ animated: Bool) { - self.refreshView() } ``` -## Displaying subscriptions -For subscription products, you also have some data about subscription periods and introductory offers. - - - `func hasIntroductoryPriceEligible() -> Bool` - The product has an introductory price the user is eligible to. - - `localizedSubscriptionPeriod: String?` - The period of the subscription. - - `localizedIntroductoryPrice: String?` - The cost of the introductory offer if available in the local currency. - - `localizedIntroductoryPeriod: String?` - The subscription period of the introductory offer. - - `localizedIntroductoryDuration: String?` - The duration of the introductory offer. - -**Example** - -``` swift -@objc func refreshView() { - guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else { - self.titleLabel.text = "Product unavailable" - return - } - self.titleLabel.text = product.localizedTitle - self.descriptionLabel.text = product.localizedDescription - - // Format price text. Example: "0,99€ / month for 3 months (then 3,99 € / month)" - var priceText = "\(product.localizedPrice) / \(product.localizedSubscriptionPeriod!)" - if product.hasIntroductoryPriceEligible() { - if product.introductoryPrice!.numberOfPeriods == 1 { - priceText = "\(product.localizedIntroductoryPrice!) for \(product.localizedIntroductoryDuration!)" + - " (then \(priceText))" - } else { - priceText = "\(product.localizedIntroductoryPrice!) / \(product.localizedIntroductoryPeriod!)" + - " for \(product.localizedIntroductoryDuration!) (then \(priceText))" - } - } - self.priceLabel.text = priceText -} -``` - -*Note:* You have to `import StoreKit` wherever you use `SKProduct`. - -## Refreshing -Data might change or not be yet available when your "product" view is presented. In order to properly handle those cases, you should refresh your view after refreshing in-app products metadata. You want to be sure you're displaying up-to-date information. - -To achieve this, call `InAppPurchase.refresh()` when your view is presented. - -``` swift -override func viewWillAppear(_ animated: Bool) { - self.refreshView() - InAppPurchase.refresh(callback: { _ in - self.refreshView() - }) -} -``` - -## Purchasing -The purchase process is generally a little bit more involving than most people would expect. Why is it not just: purchase → on success unlock the feature? - -Several reasons: -- In-app purchases can be initiated outside the app -- In-app purchases can be deferred, pending parental approval -- Apple wants to be sure you delivered the product before charging the user - -That is why the process looks like so: -- being ready to handle purchase events from app startup -- finalizing transactions when product delivery is complete -- sending purchase request, for which successful doesn't always mean complete - -### Initiating a purchase -To initiate a purchase, use the `InAppPurchase.purchase()` function. It takes the `productIdentifier` and a `callback` function, called when the purchase has been processed. - -**Important**: Do not process the purchase here, we'll handle that later! - -From this callback, you can for example unlock the UI by hiding your loading indicator and display a message to the user. - -*Example:* - -``` swift -self.loaderView.show() -InAppPurchase.purchase( - productIdentifier: "my_product_id", - callback: { _ in - self.loaderView.hide() -}) -``` - -This simple example locks the UI with a loader when the purchase is in progress. We'll see later how the purchase has to be processed by your applicaiton. - -The callback also gives more information about the outcome of the purchase, you might want to use it to update your UI as well. Note that some events are useful for analytics. So here's a more complete example. - -``` swift -self.loaderView.show() -InAppPurchase.purchase( - productIdentifier: "my_product_id", - callback: { result in - self.loaderView.hide() +```swift +/** ViewController.swift */ +import UIKit +import StoreKit +import InAppPurchaseLib - switch result.state { - case .purchased: - // Product successfully purchased - // Reminder: Do not process the purchase here, only update your UI. - // that's why we do not send data to analytics. - openThankYouScreen() - case .failed: - // Purchase failed - // - Human formated reason can be found in result.localizedDescription - // - More details in either result.skError or result.iapError - showError(result.localizedDescription) - case .deferred: - // The purchase is deferred, waiting for the parent's approval - openWaitingParentApprovalScreen() - case .cancelled: - // The user canceled the request, generally only useful for analytics. +class ViewController: UIViewController { + private var loaderView = LoaderView() + @IBOutlet weak var statusLabel: UILabel! + @IBOutlet weak var productTitleLabel: UILabel! + @IBOutlet weak var productDescriptionLabel: UILabel! + @IBOutlet weak var purchaseButton: UIButton! + @IBOutlet weak var restorePurchasesButton: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + // Add action for purchases and restore butons. + purchaseButton.addTarget(self, action: #selector(self.purchase), for: .touchUpInside) + restorePurchasesButton.addTarget(self, action: #selector(self.restorePurchases), for: .touchUpInside) } -}) -``` - -If the purchase fails, result will contain either `.skError`, a [`SKError`](https://developer.apple.com/documentation/storekit/skerror/code) from StoreKit, or `.iapError`, an [`IAPError`](#errors). - -*Tip:* After a successful purchase, you should see a new transaction in [Fovea's dashboard](https://billing-dashboard.fovea.cc/transactions). - -## Handling purchases -Finally, the magic happened: a user purchased one of your products! Let's see how we handle the different types of products. -### Non-Consumables -Wherever your app needs to know if a non-consumable product has been purchased, use `InAppPurchase.hasActivePurchase(for: -productIdentifier)`. This will return true if the user currently owns the product. - -**Note:** The last known state for the user's purchases is stored as [UserDefaults](https://developer.apple.com/documentation/foundation/userdefaults). As such, their status is always available to your app, even when offline. - -If you have a server that needs to know about the purchase. You should rely on Fovea's webhook instead of doing anything in here. We will see that later in the [Server integration](#server-integration) section. - -### Auto-Renewable Subscriptions -As with non-consumables, you will use `InAppPurchase.hasActivePurchase(for: productIdentifier)` to check if the user is an active subscriber to a given product. - -You might also like to call refresh regularly, for example when entering your main view. When appropriate, the library will refresh the receipt to detect subscription renewals or expiry. - -As we've seend in the [Refreshing](#refreshing) section: - -``` swift -override func viewWillAppear(_ animated: Bool) { - self.refreshView() - InAppPurchase.refresh(callback: { _ in + override func viewWillAppear(_ animated: Bool) { + self.refreshView() + InAppPurchase.refresh(callback: { _ in self.refreshView() - }) -} -``` - -**Note:** Don't be reluctant to call `refresh()` often. Internally, the library ensures heavy operation are only performed if necessary: for example when a subscription just expired. So in 99% of cases this call will result in no-operations. - -### Consumables -If the purchased products in a **consumable**, your app is responsible for delivering the purchase then acknowlege that you've done so. Delivering generally consists in increasing a counter for some sort of virtual currency. - -Your app can be notified of a purchase at any time. So the library asks you to provide an **IAPPurchaseDelegate** from initialization. - -In `InAppPurchase.initialize()`, we can pass an **IAPPurchaseDelegate** instance. This object implements the **productPurchased(productIdentifier:)** function, which is called whenever a purchase is approved. - -Here's a example implementation: - -``` swift -class AppDelegate: UIResponder, UIApplicationDelegate, IAPPurchaseDelegate { - ... - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - InAppPurchase.initialize( - iapProducts: [...], - iapPurchaseDelegate: self, // ADDED: iapPurchaseDelegate - validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678") + }) } - // IAPPurchaseDelegate implementation - func productPurchased(productIdentifier: String) { - // TODO + func refreshView() { + guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product") else { + self.productTitleLabel.text = "Product unavailable" + return + } + // Display product information. + productTitleLabel.text = product.localizedTitle + productDescriptionLabel.text = product.localizedDescription + purchaseButton.setTitle(product.localizedPrice, for: .normal) + + // Disable the button if the product has already been purchased. + if InAppPurchase.hasActivePurchase(for: "my_product") { + statusLabel.text = "OWNED" + purchaseButton.isPointerInteractionEnabled = false + } } -} -``` - -It's also important to know that when a purchase is approved, money isn't yet to reach your bank account. You have to acknowledge delivery of the (virtual) item to finalize the transaction. That is why we have to call `InAppPurchase.finishTransactions(for: productIdentifier)` as soon as we delivered the product. - -**Example** -Let's define a class that adopts the **IAPPurchaseDelegate** protocol, it can very well be your application delegate. - -``` swift -func productPurchased(productIdentifier: String) { - switch productIdenfier { - case "10_silver": - addSilver(10) - case "100_silver": - addSilver(100) + @IBAction func purchase(_ sender: Any) { + self.loaderView.show() + InAppPurchase.purchase( + productIdentifier: "my_product", + callback: { result in + self.loaderView.hide() + }) } - InAppPurchase.finishTransactions(for: productIdentifier) - Analytics.trackEvent("purchase succeeded", productIdentifier) -} -``` - -Here, we implement our own unlocking logic and call `InAppPurchase.finishTransactions()` afterward (assuming `addSilver` is synchronous). -*Note:* `productPurchased` is called when a purchase has been confirmed by Fovea's receipt validator. If you have a server, he probably already has been notified of this purchase using the webhook. - -**Reminder**: Keep in mind that purchase notifications might occur even if you never called the `InAppPurchase.purchase()` function: purchases can be made from another device or the AppStore, they can be approved by parents when the app isn't running, purchase flows can be interupted, etc. The pattern above ensures your app is always ready to handle purchase events. - -### Non-Renewing Subscriptions -For non-renewing subscriptions, delivering consists in increasing the amount of time a user can access a given feature. Apple doesn't manage the length and expiry of non-renewing subscriptions: you have to do this yourself, as for consumables. - -Basically, everything is identical to consumables. - -## Restoring purchases -Except if you only sell consumable products, Apple requires that you provide a "Restore Purchases" button to your users. In general, it is found in your application settings. - -Call this method when this button is pressed. - -``` swift -@IBAction func restorePurchases(_ sender: Any) { - self.loaderView.show() - InAppPurchase.restorePurchases(callback: { result in + @IBAction func restorePurchases(_ sender: Any) { + self.loaderView.show() + InAppPurchase.restorePurchases(callback: { result in self.loaderView.hide() - switch result.state { - case .succeeded: - if result.addedPurchases > 0 { - print("Restore purchases successful.") - } else { - print("No purchase to restore.") - } - case .failed: - print("Restore purchases failed.") - } - }) -} -``` - -The `callback` method is called once the operation is complete. You can use it to unlock the UI, by hiding your loader for example, and display the adapted message to the user. - - -## Displaying products with purchases -In your store screen, where you present your products titles and prices with a purchase button, there are some cases to handle that we skipped. Owned products and deferred purchases. - -### Owned products -Non-consumables and active auto-renewing subscriptions cannot be purchased again. You should adjust your UI to reflect that state. Refer to `InAppPurchase.hasActivePurchase()` to and to the example later in this section. - -### Deferred purchases -Apple's **Ask to Buy** feature lets parents approve any purchases initiated by children, including in-app purchases. - -With **Ask to Buy** enabled, when a child requests to make a purchase, the app is notified that the purchase is awaiting the parent’s approval in the purchase callback: - -``` swift -InAppPurchase.purchase( - productIdentifier: productIdentifier, - callback: { result in - switch result.state { - case .deferred: - // Pending parent approval - } -}) -``` - -In the _deferred_ case, the child has been notified by StoreKit that the parents have to approve the purchase. He might then close the app and come back later. You don't have much to do, but to display in your UI that there is a purchase waiting for parental approval in your views. - -We will use the `hasDeferredTransaction` method: - -``` swift -InAppPurchase.hasDeferredTransaction(for productIdentifier: String) -> Bool -``` - -### Example -Here's an example that covers what has been discussed above. We will update our example `refreshView` function from before: - -``` swift -@objc func refreshView() { - guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else { - self.titleLabel.text = "Product unavailable" - return - } - self.titleLabel.text = product.localizedTitle - // ... - - // "Ask to Buy" deferred purchase waiting for parent's approval - if InAppPurchase.hasDeferredTransaction(for: "my_product_id") { - self.statusLabel.text = "Waiting for Approval..." - self.purchaseButton.isPointerInteractionEnabled = false - } - // "Owned" product - else if InAppPurchase.hasActivePurchase(for: "my_product_id") { - self.statusLabel.text = "OWNED" - self.purchaseButton.isPointerInteractionEnabled = false - } - else { - self.purchaseButton.isPointerInteractionEnabled = true + }) } } ``` -When a product is owned or has a deferred purchase, we make sure the purchase button is grayed out. We also use a status label to display some details. Of course, you are free to design your UI as you see fit. +# Documentation +- [Getting Started](https://iridescent-dev.github.io/iap-swift-lib/Getting%20Started.html) +- [Usage](https://iridescent-dev.github.io/iap-swift-lib/Usage.html) +- [API documentation](https://iridescent-dev.github.io/iap-swift-lib/API%20documentation.html) -## Errors - -When calling `refresh()`, `purchase()` or `restorePurchases()`, the callback can return an `IAPError` if the state is `failed`. -Here is the list of `IAPErrorCode` you can receive: - -* Errors returned by `refresh()`, `purchase()` or `restorePurchases()` - - `libraryNotInitialized` - You must call the `initialize` fuction before using the library. - - `bundleIdentifierInvalid` - The Bundle Identifier is invalid. - - `validatorUrlInvalid` - The Validator URL String is invalid. - - `refreshReceiptFailed` - Failed to refresh the App Store receipt. - - `validateReceiptFailed` - Failed to validate the App Store receipt with Fovea. - - `readReceiptFailed` - Failed to read the receipt validation. - -* Errors returned by `refresh()` - - `refreshProductsFailed` - Failed to refresh products from the App Store. - -* Errors returned by `purchase()` - - `productNotFound` - The product was not found on the App Store and cannot be purchased. - - `cannotMakePurchase` - The user is not allowed to authorize payments. - - `alreadyPurchasing` - A purchase is already in progress. - -## Analytics -Tracking the purchase flow is a common things in apps. Especially as it's core to your revenue model. - -We can track 5 events, which step in the purchase pipeline a user reached. -1. `purchase initiated` -2. `purchase cancelled` -3. `purchase failed` -4. `purchase deferred` -5. `purchase succeeded` - -Here's a quick example showing how to implement this correctly. - -``` swift -func makePurchase() { - Analytics.trackEvent("purchase initiated") - InAppPurchase.purchase( - productIdentifier: "my_product_id", - callback: { result in - switch result.state { - case .purchased: - // Reminder: We are not processing the purchase here, only updating your UI. - // That's why we do not send an event to analytics. - case .failed: - Analytics.trackEvent("purchase failed") - case .deferred: - Analytics.trackEvent("purchase deferred") - case .cancelled: - Analytics.trackEvent("purchase cancelled") - } - }) -} - -// IAPPurchaseDelegate implementation -func productPurchased(productIdentifier: String) { - Analytics.trackEvent("purchase succeeded") - InAppPurchase.finishTransactions(for: productIdentifier) -} -``` - -The important part to remember is that a purchase can occur outside your app (or be approved when the app is not running), that's why tracking `purchase succeeded` has to be part of the `productPurchased` delegate function. - -Refer to the [Consumables](#consumables) section to learn more about the `productPurchased` function. - -## Server integration -In more advanced use cases, you have a server component. Users are logged in and you'll like to unlock the content for this user on your server. The safest approach is to setup a [Webhook on Fovea](https://billing.fovea.cc/documentation/webhook/?ref=iap-swift-lib). You'll receive notifications from Fovea that transaction have been processed and/or subscriptions updated. - -The information sent from Fovea has been verified from Apple's server, which makes it way more trustable than information sent from your app itself. - -To take advantage of this, you have to inform the library of your application username. This `applicationUsername` can be provided as a parameter of the `InAppPurchase.initialize` method and updated later by changing the associated property. - -*Example:* -``` swift -InAppPurchase.initialize( - iapProducts: [...], - validatorUrlString: "..."), - applicationUsername: UserSession.getUserId()) - -// later ... -InAppPurchase.applicationUsername = UserSession.getUserId() -``` - -If a user account is mandatory in your app, you will want to delay calls to `InAppPurchase.initialize()` to when your user's session is ready. - -Do not hesitate to [contact Fovea](mailto:support@fovea.cc) for help. +See also: +- [In-App Purchase official documentation](https://developer.apple.com/in-app-purchase) +- [StoreKit Documentation](https://developer.apple.com/documentation/storekit/in-app_purchase) # Xcode Demo Project Do not hesitate to check the demo project available on here: [iap-swift-lib-demo](https://github.com/iridescent-dev/iap-swift-lib-demo). -# References -- [API documentation](https://billing.fovea.cc/iap-swift-lib/api) -- [StoreKit Documentation](https://developer.apple.com/documentation/storekit/in-app_purchase) - # Coding -Generate the documentation, using [this fork](https://github.com/johankool/swift-doc/tree/access-level-option) of swift-doc (on `--minimum-access-level` is part of the main distrib). - +Generate the documentation, using [Jazzy](https://github.com/realm/jazzy) by running the following command: ``` -swift-doc generate sources --module-name InAppPurchase --format html --output docs --minimum-access-level public --base-url /iap-swift-lib/ +jazzy ``` # Troubleshooting Common issues are covered here: https://github.com/iridescent-dev/iap-swift-lib/wiki/Troubleshooting + # License InAppPurchaseLib is open-sourced library licensed under the MIT License. See [LICENSE](LICENSE) for details. diff --git a/Sources/InAppPurchaseLib/Common/IAPCallback.swift b/Sources/InAppPurchaseLib/Common/IAPCallback.swift index ac65678..0e3309b 100644 --- a/Sources/InAppPurchaseLib/Common/IAPCallback.swift +++ b/Sources/InAppPurchaseLib/Common/IAPCallback.swift @@ -10,6 +10,8 @@ import StoreKit public typealias IAPPurchaseCallback = (IAPPurchaseResult) -> Void + +/// The result returned in the `purchase()` callback. public struct IAPPurchaseResult { public internal(set) var state: IAPPurchaseResultState public internal(set) var iapError: IAPError? = nil @@ -22,15 +24,22 @@ public struct IAPPurchaseResult { } } +/// The list of the different states of the `IAPPurchaseResult`. public enum IAPPurchaseResultState { + /// The purchase was successful. case purchased + /// Puchase failed. case failed + /// The purchase was cancelled by the user. case cancelled + /// The purchase is deferred. case deferred } public typealias IAPRefreshCallback = (IAPRefreshResult) -> Void + +/// The result returned in the `refresh()` or `restorePurchases()` callback. public struct IAPRefreshResult { public internal(set) var state: IAPRefreshResultState public internal(set) var iapError: IAPError? = nil @@ -38,8 +47,12 @@ public struct IAPRefreshResult { public internal(set) var updatedPurchases: Int = 0 } +/// The list of the different states of the `IAPRefreshResult`. public enum IAPRefreshResultState { + /// Refresh was successful. case succeeded + /// Refresh failed. case failed + /// Refresh has been skipped because it is not necessary. case skipped } diff --git a/Sources/InAppPurchaseLib/Common/IAPError.swift b/Sources/InAppPurchaseLib/Common/IAPError.swift index 748f9ec..b659701 100644 --- a/Sources/InAppPurchaseLib/Common/IAPError.swift +++ b/Sources/InAppPurchaseLib/Common/IAPError.swift @@ -12,23 +12,49 @@ public protocol IAPErrorProtocol: LocalizedError { var code: IAPErrorCode { get } } +/// The list of error codes that can be returned by the library. public enum IAPErrorCode { + /* MARK: - Errors returned by `refresh()`, `purchase()` or `restorePurchases()` */ + /// You must call the `initialize` fuction before using the library. case libraryNotInitialized - case productNotFound - case cannotMakePurchase - case alreadyPurchasing + /// The Bundle Identifier is invalid. case bundleIdentifierInvalid + + /// The Validator URL String is invalid. case validatorUrlInvalid + + /// Failed to refresh the App Store receipt. case refreshReceiptFailed + + /// Failed to validate the App Store receipt with Fovea. case validateReceiptFailed + + /// Failed to read the receipt validation. case readReceiptFailed + /* MARK: - Errors returned by `refresh()` */ + /// Failed to refresh products from the App Store. case refreshProductsFailed + + /* MARK: - Errors returned by `purchase()` */ + /// The product was not found on the App Store and cannot be purchased. + case productNotFound + + /// The user is not allowed to authorize payments. + case cannotMakePurchase + + /// A purchase is already in progress. + case alreadyPurchasing } +/// When calling `refresh()`, `purchase()` or `restorePurchases()`, the callback can return an `IAPError` if the state is `failed`. public struct IAPError: IAPErrorProtocol { + /// The error code. + /// - See also: `IAPErrorCode`. public var code: IAPErrorCode + + /// The error description. public var localizedDescription: String { switch code { case .libraryNotInitialized: diff --git a/Sources/InAppPurchaseLib/InAppPurchase.swift b/Sources/InAppPurchaseLib/InAppPurchase.swift index 5eb946f..caa0efe 100644 --- a/Sources/InAppPurchaseLib/InAppPurchase.swift +++ b/Sources/InAppPurchaseLib/InAppPurchase.swift @@ -8,7 +8,7 @@ import Foundation import StoreKit - +/// public class InAppPurchase: NSObject, InAppPurchaseLib { // InAppPurchaseLib version number. internal static let versionNumber = "1.0.2" @@ -58,7 +58,7 @@ public class InAppPurchase: NSObject, InAppPurchaseLib { /// Refresh Product list and user Receipt. /// - Parameter callback: The function that will be called after processing. - /// - See also:`IAPRefreshCallback` and `IAPRefreshResult`. + /// - See also: `IAPRefreshResult` public static func refresh(callback: @escaping IAPRefreshCallback) { if !initialized { callback(IAPRefreshResult(state: .failed, iapError: IAPError(code: .libraryNotInitialized))) @@ -124,7 +124,7 @@ public class InAppPurchase: NSObject, InAppPurchaseLib { /* MARK: - Products information */ /// Gets all products retrieved from the App Store /// - Returns: An array of products. - /// - See also: `SKProduct`. + /// - See also: `SKProduct` public static func getProducts() -> Array { return IAPProductService.shared.getProducts() } @@ -132,7 +132,7 @@ public class InAppPurchase: NSObject, InAppPurchaseLib { /// Gets the product by its identifier from the list of products retrieved from the App Store. /// - Parameter identifier: The identifier of the product. /// - Returns: The product if it was retrieved from the App Store. - /// - See also: `SKProduct`. + /// - See also: `SKProduct` public static func getProductBy(identifier: String) -> SKProduct? { return IAPProductService.shared.getProductBy(identifier: identifier) } @@ -150,7 +150,7 @@ public class InAppPurchase: NSObject, InAppPurchaseLib { /// - productIdentifier: The identifier of the product to purchase. /// - quantity: The quantity to purchase (default value = 1). /// - callback: The function that will be called after processing. - /// - See also:`IAPPurchaseCallback` and `IAPPurchaseResult`. + /// - See also: `IAPPurchaseResult` public static func purchase(productIdentifier: String, quantity: Int, callback: @escaping IAPPurchaseCallback) { if !initialized { callback(IAPPurchaseResult(state: .failed, iapError: IAPError(code: .libraryNotInitialized))) @@ -166,7 +166,7 @@ public class InAppPurchase: NSObject, InAppPurchaseLib { /// Restore purchased products. /// - Parameter callback: The function that will be called after processing. - /// - See also:`IAPRefreshCallback` and `IAPRefreshResult`. + /// - See also: `IAPRefreshResult` public static func restorePurchases(callback: @escaping IAPRefreshCallback) { if !initialized { callback(IAPRefreshResult(state: .failed, iapError: IAPError(code: .libraryNotInitialized))) diff --git a/Sources/InAppPurchaseLib/InAppPurchaseLib.swift b/Sources/InAppPurchaseLib/InAppPurchaseLib.swift index 8e746ab..f1bdbf2 100644 --- a/Sources/InAppPurchaseLib/InAppPurchaseLib.swift +++ b/Sources/InAppPurchaseLib/InAppPurchaseLib.swift @@ -9,7 +9,7 @@ import Foundation import StoreKit -/// The protocol that `InAppPurchase`` adopts. +/// The protocol that `InAppPurchase` adopts. public protocol InAppPurchaseLib { /// The array of `IAPProduct`. static var iapProducts: Array { get } @@ -33,20 +33,20 @@ public protocol InAppPurchaseLib { /// Refresh Product list and user Receipt. /// - Parameter callback: The function that will be called after processing. - /// - See also:`IAPRefreshCallback` and `IAPRefreshResult`. + /// - See also:`IAPRefreshResult` static func refresh(callback: @escaping IAPRefreshCallback) -> Void /* MARK: - Products information */ /// Gets all products retrieved from the App Store /// - Returns: An array of products. - /// - See also: `SKProduct`. + /// - See also: `SKProduct` static func getProducts() -> Array /// Gets the product by its identifier from the list of products retrieved from the App Store. /// - Parameter identifier: The identifier of the product. /// - Returns: The product if it was retrieved from the App Store. - /// - See also: `SKProduct`. + /// - See also: `SKProduct` static func getProductBy(identifier: String) -> SKProduct? @@ -60,12 +60,12 @@ public protocol InAppPurchaseLib { /// - productIdentifier: The identifier of the product to purchase. /// - quantity: The quantity to purchase (default value = 1). /// - callback: The function that will be called after processing. - /// - See also:`IAPPurchaseCallback` and `IAPPurchaseResult`. + /// - See also:`IAPPurchaseResult` static func purchase(productIdentifier: String, quantity: Int, callback: @escaping IAPPurchaseCallback) -> Void /// Restore purchased products. /// - Parameter callback: The function that will be called after processing. - /// - See also:`IAPRefreshCallback` and `IAPRefreshResult`. + /// - See also:`IAPRefreshResult` static func restorePurchases(callback: @escaping IAPRefreshCallback) -> Void /// Finish all transactions for the product. @@ -116,8 +116,7 @@ public extension InAppPurchaseLib { } -/* MARK: - The protocol that you must adopt. */ -/// The protocol that you must adopt if you have `consumable` and/or `nonRenewingSubscription` products. +/// The protocol that you must adopt if you have *consumable* and/or *non-renewing subscription* products. public protocol IAPPurchaseDelegate { /// Called when a product is newly purchased, updated or restored. /// - Parameter productIdentifier: The identifier of the product. @@ -127,7 +126,7 @@ public protocol IAPPurchaseDelegate { } -/// The default implementation of `IAPPurchaseDelegate` if no other is provided. +/// The default implementation of `IAPPurchaseDelegate` if no other is provided. It is enough if you only have *non-consumable* and/or *auto-renewable subscription* products. public class DefaultPurchaseDelegate: IAPPurchaseDelegate { public init(){} diff --git a/Sources/InAppPurchaseLib/Product/IAPProduct.swift b/Sources/InAppPurchaseLib/Product/IAPProduct.swift index 74e919e..115a87e 100644 --- a/Sources/InAppPurchaseLib/Product/IAPProduct.swift +++ b/Sources/InAppPurchaseLib/Product/IAPProduct.swift @@ -7,7 +7,6 @@ import Foundation - public struct IAPProduct { /// The identifier of the product. diff --git a/docs/API documentation.html b/docs/API documentation.html new file mode 100644 index 0000000..70cd86c --- /dev/null +++ b/docs/API documentation.html @@ -0,0 +1,680 @@ + + + + API documentation Reference + + + + + + + + + + + + + + + + +
+

+ + InAppPurchaseLib documentation + + (77% documented) +

+ +

+

+ +
+

+ +

+ + + View on GitHub + +

+ +
+ + + +
+ +
+ +
+
+

API documentation

+

Classes and Protocols

+ +

The most important class is InAppPurchase. All the functions you need are defined in this class.

+ +

If you have consumable and/or non-renewing subscription products in your application, you must have a class that adopts the IAPPurchaseDelegate protocol.

+

Products

+ + +

Callbacks

+ +

refresh(), purchase() and restorePurchases() are asynchronous functions. You must provide a callback that will allow you to perform actions depending on the result.

+ + +

Errors

+ +

When calling refresh(), purchase() or restorePurchases(), the callback can return an IAPError if the state is failed. Look at IAPErrorCode to see the list of error codes you can receive.

+ +
+
+ +
+
+
+
    +
  • +
    + + + + InAppPurchase + +
    +
    +
    +
    +
    +
    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class InAppPurchase : NSObject, InAppPurchaseLib
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + InAppPurchaseLib + +
    +
    +
    +
    +
    +
    +

    The protocol that InAppPurchase adopts.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public protocol InAppPurchaseLib
    + +
    +
    +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    The default implementation of IAPPurchaseDelegate if no other is provided. It is enough if you only have non-consumable and/or auto-renewable subscription products.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public class DefaultPurchaseDelegate : IAPPurchaseDelegate
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + IAPPurchaseDelegate + +
    +
    +
    +
    +
    +
    +

    The protocol that you must adopt if you have consumable and/or non-renewing subscription products.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public protocol IAPPurchaseDelegate
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + IAPProduct + +
    +
    +
    +
    +
    +
    +

    Undocumented

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct IAPProduct
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + IAPProductType + +
    +
    +
    +
    +
    +
    +

    Undocumented

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum IAPProductType
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + SKProduct + +
    +
    +
    +
    +
    +
    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    extension SKProduct
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + IAPPeriodFormat + +
    +
    +
    +
    +
    +
    +

    Undocumented

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum IAPPeriodFormat
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + IAPPurchaseCallback + +
    +
    +
    +
    +
    +
    +

    Undocumented

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public typealias IAPPurchaseCallback = (IAPPurchaseResult) -> Void
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + IAPRefreshCallback + +
    +
    +
    +
    +
    +
    +

    Undocumented

    + +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public typealias IAPRefreshCallback = (IAPRefreshResult) -> Void
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + IAPPurchaseResult + +
    +
    +
    +
    +
    +
    +

    The result returned in the purchase() callback.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct IAPPurchaseResult
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + IAPRefreshResult + +
    +
    +
    +
    +
    +
    +

    The result returned in the refresh() or restorePurchases() callback.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct IAPRefreshResult
    + +
    +
    +
    +
    +
  • +
  • + +
    +
    +
    +
    +
    +

    The list of the different states of the IAPPurchaseResult.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum IAPPurchaseResultState
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + IAPRefreshResultState + +
    +
    +
    +
    +
    +
    +

    The list of the different states of the IAPRefreshResult.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum IAPRefreshResultState
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + IAPError + +
    +
    +
    +
    +
    +
    +

    When calling refresh(), purchase() or restorePurchases(), the callback can return an IAPError if the state is failed.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public struct IAPError : IAPErrorProtocol
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + IAPErrorCode + +
    +
    +
    +
    +
    +
    +

    The list of error codes that can be returned by the library.

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public enum IAPErrorCode
    + +
    +
    +
    +
    +
  • +
  • +
    + + + + IAPErrorProtocol + +
    +
    +
    +
    +
    +
    +

    Undocumented

    + + See more +
    +
    +

    Declaration

    +
    +

    Swift

    +
    public protocol IAPErrorProtocol : LocalizedError
    + +
    +
    +
    +
    +
  • +
+
+
+
+ +
+
+ + + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes/DefaultPurchaseDelegate.html b/docs/Classes/DefaultPurchaseDelegate.html similarity index 50% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes/DefaultPurchaseDelegate.html rename to docs/Classes/DefaultPurchaseDelegate.html index 3a8424b..5e4025c 100644 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes/DefaultPurchaseDelegate.html +++ b/docs/Classes/DefaultPurchaseDelegate.html @@ -4,116 +4,163 @@ DefaultPurchaseDelegate Class Reference - + + + + + + -
-
-

InAppPurchaseLib (52% documented)

-

View on GitHub

-
-
-
-
+

+ + InAppPurchaseLib documentation + + (77% documented)

-
+ +

+

+ +
+

+ +

+ + + View on GitHub + +

+ + + + + + + +
+
-
    +
    • @@ -202,14 +252,15 @@

      Parameters

-
- - + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes/InAppPurchase.html b/docs/Classes/InAppPurchase.html similarity index 87% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes/InAppPurchase.html rename to docs/Classes/InAppPurchase.html index b43f50e..269267c 100644 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes/InAppPurchase.html +++ b/docs/Classes/InAppPurchase.html @@ -4,116 +4,163 @@ InAppPurchase Class Reference - + + + + + + -
-
-

InAppPurchaseLib (52% documented)

-

View on GitHub

-
-
-
-
+

+ + InAppPurchaseLib documentation + + (77% documented)

-
+ +

+

+ +
+

+ +

+ + + View on GitHub + +

+ + + + +
-
-
    +
    • @@ -446,7 +495,7 @@

      Products information

      Gets all products retrieved from the App Store

      See

      - See also: SKProduct. + See also: SKProduct
      @@ -482,7 +531,7 @@

      Return Value

      Gets the product by its identifier from the list of products retrieved from the App Store.

      See

      - See also: SKProduct. + See also: SKProduct
      @@ -533,7 +582,7 @@

      Purchasing and Restoring

      -
        +
        • @@ -581,7 +630,7 @@

          Return Value

          Request a Payment from the App Store.

          See

          - See also:IAPPurchaseCallback and IAPPurchaseResult. + See also: IAPPurchaseResult
          @@ -590,7 +639,7 @@

          Return Value

          Declaration

          Swift

          -
          public static func purchase(productIdentifier: String, quantity: Int, callback: @escaping IAPPurchaseCallback)
          +
          public static func purchase(productIdentifier: String, quantity: Int, callback: @escaping IAPPurchaseCallback)
          @@ -656,7 +705,7 @@

          Parameters

          Restore purchased products.

          See

          - See also:IAPRefreshCallback and IAPRefreshResult. + See also: IAPRefreshResult
          @@ -665,7 +714,7 @@

          Parameters

          Declaration

          Swift

          -
          public static func restorePurchases(callback: @escaping IAPRefreshCallback)
          +
          public static func restorePurchases(callback: @escaping IAPRefreshCallback)
          @@ -799,7 +848,7 @@

          Purchases information

          -
            +
            • @@ -1014,14 +1063,15 @@

              Return Value

            - - - + + diff --git a/docs/jazzy/Enums/IAPErrorCode.html b/docs/Enums/IAPErrorCode.html similarity index 62% rename from docs/jazzy/Enums/IAPErrorCode.html rename to docs/Enums/IAPErrorCode.html index b78db89..16f2456 100644 --- a/docs/jazzy/Enums/IAPErrorCode.html +++ b/docs/Enums/IAPErrorCode.html @@ -4,116 +4,163 @@ IAPErrorCode Enumeration Reference - + + + + + + -
            -
            -

            InAppPurchaseLib (52% documented)

            -

            View on GitHub

            -
            -
            -
            -
            +

            + + InAppPurchaseLib documentation + + (77% documented)

            -
            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + + + + + + + +
            +
            -
              +
              + + +
              + +

              Errors returned by refresh(), purchase() or restorePurchases()

              +

              +
              +
              +
              • @@ -140,7 +199,7 @@

                IAPErrorCode

                -

                Undocumented

                +

                You must call the initialize fuction before using the library.

                @@ -157,9 +216,9 @@

                Declaration

              • @@ -167,14 +226,14 @@

                Declaration

                -

                Undocumented

                +

                The Bundle Identifier is invalid.

                Declaration

                Swift

                -
                case productNotFound
                +
                case bundleIdentifierInvalid
                @@ -184,9 +243,9 @@

                Declaration

              • @@ -194,14 +253,14 @@

                Declaration

                -

                Undocumented

                +

                The Validator URL String is invalid.

                Declaration

                Swift

                -
                case cannotMakePurchase
                +
                case validatorUrlInvalid
                @@ -211,9 +270,9 @@

                Declaration

              • @@ -221,14 +280,14 @@

                Declaration

                -

                Undocumented

                +

                Failed to refresh the App Store receipt.

                Declaration

                Swift

                -
                case alreadyPurchasing
                +
                case refreshReceiptFailed
                @@ -238,9 +297,9 @@

                Declaration

              • @@ -248,14 +307,14 @@

                Declaration

                -

                Undocumented

                +

                Failed to validate the App Store receipt with Fovea.

                Declaration

                Swift

                -
                case bundleIdentifierInvalid
                +
                case validateReceiptFailed
                @@ -265,9 +324,9 @@

                Declaration

              • @@ -275,26 +334,39 @@

                Declaration

                -

                Undocumented

                +

                Failed to read the receipt validation.

                Declaration

                Swift

                -
                case validatorUrlInvalid
                +
                case readReceiptFailed
              • +
              +
            +
            +
            + + +
            + +

            Errors returned by refresh()

            +

            +
            +
            +
            • @@ -302,26 +374,39 @@

              Declaration

              -

              Undocumented

              +

              Failed to refresh products from the App Store.

              Declaration

              Swift

              -
              case refreshReceiptFailed
              +
              case refreshProductsFailed
            • +
            +
            +
            +
            + + +
            + +

            Errors returned by purchase()

            +

            +
            +
            +
            • @@ -329,14 +414,14 @@

              Declaration

              -

              Undocumented

              +

              The product was not found on the App Store and cannot be purchased.

              Declaration

              Swift

              -
              case validateReceiptFailed
              +
              case productNotFound
              @@ -346,9 +431,9 @@

              Declaration

            • @@ -356,14 +441,14 @@

              Declaration

              -

              Undocumented

              +

              The user is not allowed to authorize payments.

              Declaration

              Swift

              -
              case readReceiptFailed
              +
              case cannotMakePurchase
              @@ -373,9 +458,9 @@

              Declaration

            • @@ -383,14 +468,14 @@

              Declaration

              -

              Undocumented

              +

              A purchase is already in progress.

              Declaration

              Swift

              -
              case refreshProductsFailed
              +
              case alreadyPurchasing
              @@ -399,14 +484,15 @@

              Declaration

            -
            - - + + diff --git a/docs/Enums/IAPPeriodFormat.html b/docs/Enums/IAPPeriodFormat.html new file mode 100644 index 0000000..d2e9a5f --- /dev/null +++ b/docs/Enums/IAPPeriodFormat.html @@ -0,0 +1,247 @@ + + + + IAPPeriodFormat Enumeration Reference + + + + + + + + + + + + + + + + +
            +

            + + InAppPurchaseLib documentation + + (77% documented) +

            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + +
            + + + +
            + +
            + +
            +
            +

            IAPPeriodFormat

            +
            +
            +
            public enum IAPPeriodFormat
            + +
            +
            +

            Undocumented

            + +
            +
            + +
            +
            +
            +
              +
            • +
              + + + + short + +
              +
              +
              +
              +
              +
              +

              Undocumented

              + +
              +
              +

              Declaration

              +
              +

              Swift

              +
              case short
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + long + +
              +
              +
              +
              +
              +
              +

              Undocumented

              + +
              +
              +

              Declaration

              +
              +

              Swift

              +
              case long
              + +
              +
              +
              +
              +
            • +
            +
            +
            +
            + +
            +
            + + + + diff --git a/docs/jazzy/Enums/IAPProductType.html b/docs/Enums/IAPProductType.html similarity index 55% rename from docs/jazzy/Enums/IAPProductType.html rename to docs/Enums/IAPProductType.html index 5f397d9..645973d 100644 --- a/docs/jazzy/Enums/IAPProductType.html +++ b/docs/Enums/IAPProductType.html @@ -4,116 +4,163 @@ IAPProductType Enumeration Reference - + + + + + + -
            -
            -

            InAppPurchaseLib (52% documented)

            -

            View on GitHub

            -
            -
            -
            -
            +

            + + InAppPurchaseLib documentation + + (77% documented)

            -
            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + + + + + + + +
            +
            -
              +
              • @@ -237,14 +287,15 @@

                Declaration

            -
            - - + + diff --git a/docs/jazzy/Enums/IAPPurchaseResultState.html b/docs/Enums/IAPPurchaseResultState.html similarity index 53% rename from docs/jazzy/Enums/IAPPurchaseResultState.html rename to docs/Enums/IAPPurchaseResultState.html index ade15de..42485c4 100644 --- a/docs/jazzy/Enums/IAPPurchaseResultState.html +++ b/docs/Enums/IAPPurchaseResultState.html @@ -4,116 +4,163 @@ IAPPurchaseResultState Enumeration Reference - + + + + + + -
            -
            -

            InAppPurchaseLib (52% documented)

            -

            View on GitHub

            -
            -
            -
            -
            +

            + + InAppPurchaseLib documentation + + (77% documented)

            -
            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + + + + + + + +
            +
            -
              +
              • @@ -140,7 +190,7 @@

                IAPPurchaseResultState

                -

                Undocumented

                +

                The purchase was successful.

                @@ -167,7 +217,7 @@

                Declaration

                -

                Undocumented

                +

                Puchase failed.

                @@ -194,7 +244,7 @@

                Declaration

                -

                Undocumented

                +

                The purchase was cancelled by the user.

                @@ -221,7 +271,7 @@

                Declaration

                -

                Undocumented

                +

                The purchase is deferred.

                @@ -237,14 +287,15 @@

                Declaration

            -
            - - + + diff --git a/docs/Enums/IAPRefreshResultState.html b/docs/Enums/IAPRefreshResultState.html new file mode 100644 index 0000000..f9151e4 --- /dev/null +++ b/docs/Enums/IAPRefreshResultState.html @@ -0,0 +1,274 @@ + + + + IAPRefreshResultState Enumeration Reference + + + + + + + + + + + + + + + + +
            +

            + + InAppPurchaseLib documentation + + (77% documented) +

            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + +
            + + + +
            + +
            + +
            +
            +

            IAPRefreshResultState

            +
            +
            +
            public enum IAPRefreshResultState
            + +
            +
            +

            The list of the different states of the IAPRefreshResult.

            + +
            +
            + +
            +
            +
            +
              +
            • +
              + + + + succeeded + +
              +
              +
              +
              +
              +
              +

              Refresh was successful.

              + +
              +
              +

              Declaration

              +
              +

              Swift

              +
              case succeeded
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + failed + +
              +
              +
              +
              +
              +
              +

              Refresh failed.

              + +
              +
              +

              Declaration

              +
              +

              Swift

              +
              case failed
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + skipped + +
              +
              +
              +
              +
              +
              +

              Refresh has been skipped because it is not necessary.

              + +
              +
              +

              Declaration

              +
              +

              Swift

              +
              case skipped
              + +
              +
              +
              +
              +
            • +
            +
            +
            +
            + +
            +
            + + + + diff --git a/docs/jazzy/Extensions/SKProduct.html b/docs/Extensions/SKProduct.html similarity index 68% rename from docs/jazzy/Extensions/SKProduct.html rename to docs/Extensions/SKProduct.html index 19d937b..8fbe59d 100644 --- a/docs/jazzy/Extensions/SKProduct.html +++ b/docs/Extensions/SKProduct.html @@ -4,116 +4,163 @@ SKProduct Extension Reference - + + + + + + -
            -
            -

            InAppPurchaseLib (52% documented)

            -

            View on GitHub

            -
            -
            -
            -
            +

            + + InAppPurchaseLib documentation + + (77% documented)

            -
            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + + + + + + + +
            +
            -
              +
              • @@ -317,14 +367,15 @@

                Declaration

            -
            - - + + diff --git a/docs/Getting Started.html b/docs/Getting Started.html new file mode 100644 index 0000000..717182d --- /dev/null +++ b/docs/Getting Started.html @@ -0,0 +1,221 @@ + + + + Getting Started Reference + + + + + + + + + + + + + + + + +
            +

            + + InAppPurchaseLib documentation + + (77% documented) +

            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + +
            + + + +
            + +
            + +
            +
            +

            Getting Started

            +

            If you haven’t already, I highly recommend your read the Overview and Preparing section of Apple’s In-App Purchase official documentation.

            +

            Requirements

            + +
              +
            • Configure your App and Xcode to support In-App Purchases. + +
            • +
            • Create and configure your Fovea.Billing project account: + +
                +
              • Set your bundle ID
              • +
              • The iOS Shared Secret (or shared key) is to be retrieved from AppStoreConnect
              • +
              • The iOS Subscription Status URL (only if you want subscriptions)
              • +
            • +
            + +
            +
            + +
            +
            +
            + +
            +
            +
            + +
            +
            + + + + diff --git a/docs/Protocols/IAPErrorProtocol.html b/docs/Protocols/IAPErrorProtocol.html new file mode 100644 index 0000000..8c3d780 --- /dev/null +++ b/docs/Protocols/IAPErrorProtocol.html @@ -0,0 +1,220 @@ + + + + IAPErrorProtocol Protocol Reference + + + + + + + + + + + + + + + + +
            +

            + + InAppPurchaseLib documentation + + (77% documented) +

            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + +
            + + + +
            + +
            + +
            +
            +

            IAPErrorProtocol

            +
            +
            +
            public protocol IAPErrorProtocol : LocalizedError
            + +
            +
            +

            Undocumented

            + +
            +
            + +
            +
            +
            +
              +
            • +
              + + + + code + +
              +
              +
              +
              +
              +
              +

              Undocumented

              + +
              +
              +

              Declaration

              +
              +

              Swift

              +
              var code: IAPErrorCode { get }
              + +
              +
              +
              +
              +
            • +
            +
            +
            +
            + +
            +
            + + + + diff --git a/docs/Protocols/IAPPurchaseDelegate.html b/docs/Protocols/IAPPurchaseDelegate.html new file mode 100644 index 0000000..34c6641 --- /dev/null +++ b/docs/Protocols/IAPPurchaseDelegate.html @@ -0,0 +1,244 @@ + + + + IAPPurchaseDelegate Protocol Reference + + + + + + + + + + + + + + + + +
            +

            + + InAppPurchaseLib documentation + + (77% documented) +

            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + +
            + + + +
            + +
            + +
            +
            +

            IAPPurchaseDelegate

            +
            +
            +
            public protocol IAPPurchaseDelegate
            + +
            +
            +

            The protocol that you must adopt if you have consumable and/or non-renewing subscription products.

            + +
            +
            + +
            +
            +
            +
              +
            • + +
              +
              +
              +
              +
              +

              Called when a product is newly purchased, updated or restored.

              +
              +

              Important

              +

              You have to acknowledge delivery of the (virtual) item to finalize the transaction. Then you have to call InAppPurchase.finishTransactions(for: productIdentifier)as soon as you have delivered the product.

              + +
              + +
              +
              +

              Declaration

              +
              +

              Swift

              +
              func productPurchased(productIdentifier: String)
              + +
              +
              +
              +

              Parameters

              + + + + + + + +
              + + productIdentifier + + +
              +

              The identifier of the product.

              +
              +
              +
              +
              +
              +
            • +
            +
            +
            +
            + +
            +
            + + + + diff --git a/docs/jazzy/Protocols/InAppPurchaseLib.html b/docs/Protocols/InAppPurchaseLib.html similarity index 86% rename from docs/jazzy/Protocols/InAppPurchaseLib.html rename to docs/Protocols/InAppPurchaseLib.html index 63ceafc..cdb81d0 100644 --- a/docs/jazzy/Protocols/InAppPurchaseLib.html +++ b/docs/Protocols/InAppPurchaseLib.html @@ -4,116 +4,163 @@ InAppPurchaseLib Protocol Reference - + + + + + + -
            -
            -

            InAppPurchaseLib (52% documented)

            -

            View on GitHub

            -
            -
            -
            -
            +

            + + InAppPurchaseLib documentation + + (77% documented)

            -
            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + + + + + + + +
            +
            -
            -
              +
              • @@ -431,7 +481,7 @@

                Products information

                Gets all products retrieved from the App Store

                See

                - See also: SKProduct. + See also: SKProduct
                @@ -467,7 +517,7 @@

                Return Value

                Gets the product by its identifier from the list of products retrieved from the App Store.

                See

                - See also: SKProduct. + See also: SKProduct
                @@ -518,7 +568,7 @@

                Purchasing and Restoring

                -
            - - + + diff --git a/docs/Structs/IAPError.html b/docs/Structs/IAPError.html new file mode 100644 index 0000000..3ce0582 --- /dev/null +++ b/docs/Structs/IAPError.html @@ -0,0 +1,252 @@ + + + + IAPError Structure Reference + + + + + + + + + + + + + + + + +
            +

            + + InAppPurchaseLib documentation + + (77% documented) +

            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + +
            + + + +
            + +
            + +
            +
            +

            IAPError

            +
            +
            +
            public struct IAPError : IAPErrorProtocol
            + +
            +
            +

            When calling refresh(), purchase() or restorePurchases(), the callback can return an IAPError if the state is failed.

            + +
            +
            + +
            +
            +
            +
              +
            • +
              + + + + code + +
              +
              +
              +
              +
              +
              +

              The error code.

              +
              +

              See

              + See also: IAPErrorCode. + +
              + +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public var code: IAPErrorCode
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + localizedDescription + +
              +
              +
              +
              +
              +
              +

              The error description.

              + +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public var localizedDescription: String { get }
              + +
              +
              +
              +
              +
            • +
            +
            +
            +
            + +
            +
            + + + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPProduct.html b/docs/Structs/IAPProduct.html similarity index 58% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPProduct.html rename to docs/Structs/IAPProduct.html index 889974f..f52efcb 100644 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPProduct.html +++ b/docs/Structs/IAPProduct.html @@ -4,116 +4,163 @@ IAPProduct Structure Reference - + + + + + + -
            -
            -

            InAppPurchaseLib (52% documented)

            -

            View on GitHub

            -
            -
            -
            -
            +

            + + InAppPurchaseLib documentation + + (77% documented)

            -
            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + + + + + + + +
            +
            -
              +
              • @@ -251,14 +301,15 @@

                Parameters

            -
            - - + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPPurchaseResult.html b/docs/Structs/IAPPurchaseResult.html similarity index 58% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPPurchaseResult.html rename to docs/Structs/IAPPurchaseResult.html index 6bc3b5d..d17b2a6 100644 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPPurchaseResult.html +++ b/docs/Structs/IAPPurchaseResult.html @@ -4,116 +4,163 @@ IAPPurchaseResult Structure Reference - + + + + + + -
            -
            -

            InAppPurchaseLib (52% documented)

            -

            View on GitHub

            -
            -
            -
            -
            +

            + + InAppPurchaseLib documentation + + (77% documented)

            -
            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + + + + + + + +
            +
            -
              +
              • @@ -237,14 +287,15 @@

                Declaration

            -
            - - + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPRefreshResult.html b/docs/Structs/IAPRefreshResult.html similarity index 57% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPRefreshResult.html rename to docs/Structs/IAPRefreshResult.html index 8d70385..670d0f2 100644 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPRefreshResult.html +++ b/docs/Structs/IAPRefreshResult.html @@ -4,116 +4,163 @@ IAPRefreshResult Structure Reference - + + + + + + -
            -
            -

            InAppPurchaseLib (52% documented)

            -

            View on GitHub

            -
            -
            -
            -
            +

            + + InAppPurchaseLib documentation + + (77% documented)

            -
            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + + + + + + + +
            +
            -
              +
              • @@ -237,14 +287,15 @@

                Declaration

            -
            - - + + diff --git a/docs/Usage.html b/docs/Usage.html new file mode 100644 index 0000000..535a067 --- /dev/null +++ b/docs/Usage.html @@ -0,0 +1,296 @@ + + + + Usage Reference + + + + + + + + + + + + + + + + +
            +

            + + InAppPurchaseLib documentation + + (77% documented) +

            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + +
            + + + +
            + +
            + +
            +
            +

            Usage

            +

            The process of implementing in-app purchases involves several steps:

            + +
              +
            1. Displaying the list of purchasable products
            2. +
            3. Initiating a purchase
            4. +
            5. Delivering and finalizing a purchase
            6. +
            7. Checking the current ownership of non-consumables and subscriptions
            8. +
            9. Implementing the Restore Purchases button
            10. +
            + +

            Note: You have to import InAppPurchaseLib wherever you use the library.

            + +
            +
            + +
            +
            +
            + +
            +
            +
            + +
            +
            + + + + diff --git a/docs/analytics.html b/docs/analytics.html new file mode 100644 index 0000000..697340d --- /dev/null +++ b/docs/analytics.html @@ -0,0 +1,221 @@ + + + + Analytics Reference + + + + + + + + + + + + + + + +
            +

            + + InAppPurchaseLib documentation + + (77% documented) +

            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + +
            + + + +
            + +
            + +
            +
            + +

            Analytics

            + +

            Tracking the purchase flow is a common things in apps. Especially as it’s core to your revenue model.

            + +

            We can track 5 events, which step in the purchase pipeline a user reached.

            + +
              +
            1. purchase initiated
            2. +
            3. purchase cancelled
            4. +
            5. purchase failed
            6. +
            7. purchase deferred
            8. +
            9. purchase succeeded
            10. +
            + +

            Here’s a quick example showing how to implement this correctly.

            +
            func makePurchase() {
            +  Analytics.trackEvent("purchase initiated")
            +  InAppPurchase.purchase(
            +    productIdentifier: "my_product_id",
            +    callback: { result in
            +      switch result.state {
            +      case .purchased:
            +        // Reminder: We are not processing the purchase here, only updating your UI.
            +        //           That's why we do not send an event to analytics.
            +      case .failed:
            +        Analytics.trackEvent("purchase failed")
            +      case .deferred:
            +        Analytics.trackEvent("purchase deferred")
            +      case .cancelled:
            +        Analytics.trackEvent("purchase cancelled")
            +    }
            +  })
            +}
            +
            +// IAPPurchaseDelegate implementation
            +func productPurchased(productIdentifier: String) {
            +  Analytics.trackEvent("purchase succeeded")
            +  InAppPurchase.finishTransactions(for: productIdentifier)
            +}
            +
            + +

            The important part to remember is that a purchase can occur outside your app (or be approved when the app is not running), that’s why tracking purchase succeeded has to be part of the productPurchased delegate function.

            + +

            Refer to the Consumables section to learn more about the productPurchased function.

            + +
            +
            + + +
            +
            + + + + diff --git a/docs/jazzy/badge.svg b/docs/badge.svg similarity index 93% rename from docs/jazzy/badge.svg rename to docs/badge.svg index 81f3c9b..f6985a8 100644 --- a/docs/jazzy/badge.svg +++ b/docs/badge.svg @@ -8,7 +8,7 @@ - + @@ -19,10 +19,10 @@ documentation - 52% + 77% - 52% + 77% diff --git a/docs/jazzy/css/highlight.css b/docs/css/highlight.css similarity index 100% rename from docs/jazzy/css/highlight.css rename to docs/css/highlight.css diff --git a/docs/css/jazzy.css b/docs/css/jazzy.css new file mode 100644 index 0000000..ff59f5f --- /dev/null +++ b/docs/css/jazzy.css @@ -0,0 +1,395 @@ +*, *:before, *:after { + box-sizing: inherit; } + +body { + margin: 0; + background: #fff; + color: #333; + font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; + letter-spacing: .2px; + -webkit-font-smoothing: antialiased; + box-sizing: border-box; } + +h1 { + font-size: 2rem; + font-weight: 700; + margin: 1.275em 0 0.6em; } + +h2 { + font-size: 1.75rem; + font-weight: 700; + margin: 1.275em 0 0.3em; } + +h3 { + font-size: 1.5rem; + font-weight: 700; + margin: 1em 0 0.3em; } + +h4 { + font-size: 1.25rem; + font-weight: 700; + margin: 1.275em 0 0.85em; } + +h5 { + font-size: 1rem; + font-weight: 700; + margin: 1.275em 0 0.85em; } + +h6 { + font-size: 1rem; + font-weight: 700; + margin: 1.275em 0 0.85em; + color: #777; } + +p { + margin: 0 0 1em; } + +ul, ol { + padding: 0 0 0 2em; + margin: 0 0 0.85em; } + +blockquote { + margin: 0 0 0.85em; + padding: 0 15px; + color: #858585; + border-left: 4px solid #e5e5e5; } + +img { + max-width: 100%; } + +a { + color: #4183c4; + text-decoration: none; } + a:hover, a:focus { + outline: 0; + text-decoration: underline; } + a.discouraged { + text-decoration: line-through; } + a.discouraged:hover, a.discouraged:focus { + text-decoration: underline line-through; } + +table { + background: #fff; + width: 100%; + border-collapse: collapse; + border-spacing: 0; + overflow: auto; + margin: 0 0 0.85em; } + +tr:nth-child(2n) { + background-color: #fbfbfb; } + +th, td { + padding: 6px 13px; + border: 1px solid #ddd; } + +pre { + margin: 0 0 1.275em; + padding: .85em 1em; + overflow: auto; + background: #f7f7f7; + font-size: .85em; + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } + +code { + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } + +.item-container p > code, .item-container li > code, .top-matter p > code, .top-matter li > code { + background: #f7f7f7; + padding: .2em; } + .item-container p > code:before, .item-container p > code:after, .item-container li > code:before, .item-container li > code:after, .top-matter p > code:before, .top-matter p > code:after, .top-matter li > code:before, .top-matter li > code:after { + letter-spacing: -.2em; + content: "\00a0"; } + +pre code { + padding: 0; + white-space: pre; } + +.content-wrapper { + display: flex; + flex-direction: column; } + @media (min-width: 768px) { + .content-wrapper { + flex-direction: row; } } +.header { + display: flex; + padding: 8px; + font-size: 0.875em; + background: #444; + color: #999; } + +.header-col { + margin: 0; + padding: 0 8px; } + +.header-col--primary { + flex: 1; } + +.header-link { + color: #fff; } + +.header-icon { + padding-right: 6px; + vertical-align: -4px; + height: 16px; } + +.breadcrumbs { + font-size: 0.875em; + padding: 8px 16px; + margin: 0; + background: #fbfbfb; + border-bottom: 1px solid #ddd; } + +.carat { + height: 10px; + margin: 0 5px; } + +.navigation { + order: 2; } + @media (min-width: 768px) { + .navigation { + order: 1; + width: 25%; + max-width: 300px; + padding-bottom: 64px; + overflow: hidden; + word-wrap: normal; + background: #fbfbfb; + border-right: 1px solid #ddd; } } +.nav-groups { + list-style-type: none; + padding-left: 0; } + +.nav-group-name { + border-bottom: 1px solid #ddd; + padding: 8px 0 8px 16px; } + +.nav-group-name-link { + color: #333; } + +.nav-group-tasks { + margin: 8px 0; + padding: 0 0 0 8px; } + +.nav-group-task { + font-size: 1em; + list-style-type: none; + white-space: nowrap; } + +.nav-group-task-link { + color: #808080; } + +.main-content { + order: 1; } + @media (min-width: 768px) { + .main-content { + order: 2; + flex: 1; + padding-bottom: 60px; } } +.section { + padding: 0 32px; + border-bottom: 1px solid #ddd; } + +.section-content { + max-width: 834px; + margin: 0 auto; + padding: 16px 0; } + +.section-name { + color: #666; + display: block; } + .section-name p { + margin-bottom: inherit; } + +.declaration .highlight { + overflow-x: initial; + padding: 8px 0; + margin: 0; + background-color: transparent; + border: none; } + +.task-group-section { + border-top: 1px solid #ddd; } + +.task-group { + padding-top: 0px; } + +.task-name-container a[name]:before { + content: ""; + display: block; } + +.section-name-container { + position: relative; } + .section-name-container .section-name-link { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + margin-bottom: 0; } + .section-name-container .section-name { + position: relative; + pointer-events: none; + z-index: 1; } + .section-name-container .section-name a { + pointer-events: auto; } + +.item-container { + padding: 0; } + +.item { + padding-top: 8px; + width: 100%; + list-style-type: none; } + .item a[name]:before { + content: ""; + display: block; } + .item .token, .item .direct-link { + display: inline-block; + text-indent: -20px; + padding-left: 3px; + margin-left: 20px; + font-size: 1rem; } + .item .declaration-note { + font-size: .85em; + color: #808080; + font-style: italic; } + +.pointer-container { + border-bottom: 1px solid #ddd; + left: -23px; + padding-bottom: 13px; + position: relative; + width: 110%; } + +.pointer { + left: 21px; + top: 7px; + display: block; + position: absolute; + width: 12px; + height: 12px; + border-left: 1px solid #ddd; + border-top: 1px solid #ddd; + background: #fff; + transform: rotate(45deg); } + +.height-container { + display: none; + position: relative; + width: 100%; + overflow: hidden; } + .height-container .section { + background: #fff; + border: 1px solid #ddd; + border-top-width: 0; + padding-top: 10px; + padding-bottom: 5px; + padding: 8px 16px; } + +.aside, .language { + padding: 6px 12px; + margin: 12px 0; + border-left: 5px solid #dddddd; + overflow-y: hidden; } + .aside .aside-title, .language .aside-title { + font-size: 9px; + letter-spacing: 2px; + text-transform: uppercase; + padding-bottom: 0; + margin: 0; + color: #aaa; + -webkit-user-select: none; } + .aside p:last-child, .language p:last-child { + margin-bottom: 0; } + +.language { + border-left: 5px solid #cde9f4; } + .language .aside-title { + color: #4183c4; } + +.aside-warning, .aside-deprecated, .aside-unavailable { + border-left: 5px solid #ff6666; } + .aside-warning .aside-title, .aside-deprecated .aside-title, .aside-unavailable .aside-title { + color: #ff0000; } + +.graybox { + border-collapse: collapse; + width: 100%; } + .graybox p { + margin: 0; + word-break: break-word; + min-width: 50px; } + .graybox td { + border: 1px solid #ddd; + padding: 5px 25px 5px 10px; + vertical-align: middle; } + .graybox tr td:first-of-type { + text-align: right; + padding: 7px; + vertical-align: top; + word-break: normal; + width: 40px; } + +.slightly-smaller { + font-size: 0.9em; } + +.footer { + padding: 8px 16px; + background: #444; + color: #ddd; + font-size: 0.8em; } + .footer p { + margin: 8px 0; } + .footer a { + color: #fff; } + +html.dash .header, html.dash .breadcrumbs, html.dash .navigation { + display: none; } + +html.dash .height-container { + display: block; } + +form[role=search] input { + font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 24px; + padding: 0 10px; + margin: 0; + border: none; + border-radius: 1em; } + .loading form[role=search] input { + background: white url(../img/spinner.gif) center right 4px no-repeat; } + +form[role=search] .tt-menu { + margin: 0; + min-width: 300px; + background: #fbfbfb; + color: #333; + border: 1px solid #ddd; } + +form[role=search] .tt-highlight { + font-weight: bold; } + +form[role=search] .tt-suggestion { + font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; + padding: 0 8px; } + form[role=search] .tt-suggestion span { + display: table-cell; + white-space: nowrap; } + form[role=search] .tt-suggestion .doc-parent-name { + width: 100%; + text-align: right; + font-weight: normal; + font-size: 0.9em; + padding-left: 16px; } + +form[role=search] .tt-suggestion:hover, +form[role=search] .tt-suggestion.tt-cursor { + cursor: pointer; + background-color: #4183c4; + color: #fff; } + +form[role=search] .tt-suggestion:hover .doc-parent-name, +form[role=search] .tt-suggestion.tt-cursor .doc-parent-name { + color: #fff; } diff --git a/docs/displaying-products-with-purchases.html b/docs/displaying-products-with-purchases.html new file mode 100644 index 0000000..d77fc40 --- /dev/null +++ b/docs/displaying-products-with-purchases.html @@ -0,0 +1,231 @@ + + + + Displaying products with purchases Reference + + + + + + + + + + + + + + + +
            +

            + + InAppPurchaseLib documentation + + (77% documented) +

            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + +
            + + + +
            + +
            + +
            +
            + +

            Displaying products with purchases

            + +

            In your store screen, where you present your products titles and prices with a purchase button, there are some cases to handle that we skipped. Owned products and deferred purchases.

            +

            Owned products

            + +

            Non-consumables and active auto-renewing subscriptions cannot be purchased again. You should adjust your UI to reflect that state. Refer to InAppPurchase.hasActivePurchase() to and to the example later in this section.

            +

            Deferred purchases

            + +

            Apple’s Ask to Buy feature lets parents approve any purchases initiated by children, including in-app purchases.

            + +

            With Ask to Buy enabled, when a child requests to make a purchase, the app is notified that the purchase is awaiting the parent’s approval in the purchase callback:

            +
            InAppPurchase.purchase(
            +  productIdentifier: productIdentifier,
            +  callback: { result in
            +    switch result.state {
            +    case .deferred:
            +      // Pending parent approval
            +  }
            +})
            +
            + +

            In the deferred case, the child has been notified by StoreKit that the parents have to approve the purchase. He might then close the app and come back later. You don’t have much to do, but to display in your UI that there is a purchase waiting for parental approval in your views.

            + +

            We will use the hasDeferredTransaction method:

            +
            InAppPurchase.hasDeferredTransaction(for productIdentifier: String) -> Bool
            +
            +

            Example

            + +

            Here’s an example that covers what has been discussed above. We will update our example refreshView function from before:

            +
            @objc func refreshView() {
            +  guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else {
            +    self.titleLabel.text = "Product unavailable"
            +    return
            +  }
            +  self.titleLabel.text = product.localizedTitle
            +  // ...
            +
            +  // "Ask to Buy" deferred purchase waiting for parent's approval
            +  if InAppPurchase.hasDeferredTransaction(for: "my_product_id") {
            +    self.statusLabel.text = "Waiting for Approval..."
            +    self.purchaseButton.isPointerInteractionEnabled = false
            +  }
            +  // "Owned" product
            +  else if InAppPurchase.hasActivePurchase(for: "my_product_id") {
            +    self.statusLabel.text = "OWNED"
            +    self.purchaseButton.isPointerInteractionEnabled = false
            +  }
            +  else {
            +    self.purchaseButton.isPointerInteractionEnabled = true
            +  }
            +}
            +
            + +

            When a product is owned or has a deferred purchase, we make sure the purchase button is grayed out. We also use a status label to display some details. Of course, you are free to design your UI as you see fit.

            + +
            +
            + + +
            +
            + + + + diff --git a/docs/displaying-products.html b/docs/displaying-products.html new file mode 100644 index 0000000..cc50b1f --- /dev/null +++ b/docs/displaying-products.html @@ -0,0 +1,213 @@ + + + + Displaying products Reference + + + + + + + + + + + + + + + +
            +

            + + InAppPurchaseLib documentation + + (77% documented) +

            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + +
            + + + +
            + +
            + +
            +
            + +

            Displaying products

            + +

            Let’s start with the simplest case: you have a single product.

            + +

            You can retrieve all information about this product using the function InAppPurchase.getProductBy(identifier: "my_product_id"). This returns an SKProduct extended with helpful methods.

            + +

            Those are the most important:

            + +
              +
            • productIdentifier: String - The string that identifies the product to the Apple AppStore.
            • +
            • localizedTitle: String - The name of the product, in the language of the device, as retrieved from the AppStore.
            • +
            • localizedDescription: String - A description of the product, in the language of the device, as retrieved from the AppStore.
            • +
            • localizedPrice: String - The cost of the product in the local currency (read-only property added by this library).
            • +
            + +

            Example:

            + +

            You can add a function similar to this to your view.

            +
            @objc func refreshView() {
            +  guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else {
            +    self.titleLabel.text = "Product unavailable"
            +    return
            +  }
            +  self.titleLabel.text = product.localizedTitle
            +  self.descriptionLabel.text = product.localizedDescription
            +  self.priceLabel.text = product.localizedPrice
            +}
            +
            + +

            This example assumes self.titleLabel is a UILabel, etc.

            + +

            Make sure to call this function when the view appears on screen, for instance by calling it from viewWillAppear.

            +
            override func viewWillAppear(_ animated: Bool) {
            +  self.refreshView()
            +}
            +
            + +
            +
            + + +
            +
            + + + + diff --git a/docs/displaying-subscriptions.html b/docs/displaying-subscriptions.html new file mode 100644 index 0000000..640c8ff --- /dev/null +++ b/docs/displaying-subscriptions.html @@ -0,0 +1,214 @@ + + + + Displaying subscriptions Reference + + + + + + + + + + + + + + + +
            +

            + + InAppPurchaseLib documentation + + (77% documented) +

            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + +
            + + + +
            + +
            + +
            +
            + +

            Displaying subscriptions

            + +

            For subscription products, you also have some data about subscription periods and introductory offers.

            + +
              +
            • func hasIntroductoryPriceEligible() -> Bool - The product has an introductory price the user is eligible to.
            • +
            • localizedSubscriptionPeriod: String? - The period of the subscription.
            • +
            • localizedIntroductoryPrice: String? - The cost of the introductory offer if available in the local currency.
            • +
            • localizedIntroductoryPeriod: String? - The subscription period of the introductory offer.
            • +
            • localizedIntroductoryDuration: String? - The duration of the introductory offer.
            • +
            + +

            Example

            +
            @objc func refreshView() {
            +  guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else {
            +    self.titleLabel.text = "Product unavailable"
            +    return
            +  }
            +  self.titleLabel.text = product.localizedTitle
            +  self.descriptionLabel.text = product.localizedDescription
            +
            +  // Format price text. Example: "0,99€ / month for 3 months (then 3,99 € / month)"
            +  var priceText = "\(product.localizedPrice) / \(product.localizedSubscriptionPeriod!)"
            +  if product.hasIntroductoryPriceEligible() {
            +      if product.introductoryPrice!.numberOfPeriods == 1 {
            +          priceText = "\(product.localizedIntroductoryPrice!) for \(product.localizedIntroductoryDuration!)" +
            +          " (then \(priceText))"
            +      } else {
            +          priceText = "\(product.localizedIntroductoryPrice!) / \(product.localizedIntroductoryPeriod!)" +
            +          " for \(product.localizedIntroductoryDuration!) (then \(priceText))"
            +      }
            +  }
            +  self.priceLabel.text = priceText
            +}
            +
            + +

            Note: You have to import StoreKit wherever you use SKProduct.

            + +
            +
            + + +
            +
            + + + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Info.plist b/docs/docsets/InAppPurchaseLib.docset/Contents/Info.plist similarity index 100% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Info.plist rename to docs/docsets/InAppPurchaseLib.docset/Contents/Info.plist diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/API documentation.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/API documentation.html new file mode 100644 index 0000000..70cd86c --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/API documentation.html @@ -0,0 +1,680 @@ + + + + API documentation Reference + + + + + + + + + + + + + + + + +
            +

            + + InAppPurchaseLib documentation + + (77% documented) +

            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + +
            + + + +
            + +
            + +
            +
            +

            API documentation

            +

            Classes and Protocols

            + +

            The most important class is InAppPurchase. All the functions you need are defined in this class.

            + +

            If you have consumable and/or non-renewing subscription products in your application, you must have a class that adopts the IAPPurchaseDelegate protocol.

            +

            Products

            + + +

            Callbacks

            + +

            refresh(), purchase() and restorePurchases() are asynchronous functions. You must provide a callback that will allow you to perform actions depending on the result.

            + + +

            Errors

            + +

            When calling refresh(), purchase() or restorePurchases(), the callback can return an IAPError if the state is failed. Look at IAPErrorCode to see the list of error codes you can receive.

            + +
            +
            + +
            +
            +
            +
              +
            • +
              + + + + InAppPurchase + +
              +
              +
              +
              +
              +
              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public class InAppPurchase : NSObject, InAppPurchaseLib
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + InAppPurchaseLib + +
              +
              +
              +
              +
              +
              +

              The protocol that InAppPurchase adopts.

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public protocol InAppPurchaseLib
              + +
              +
              +
              +
              +
            • +
            • + +
              +
              +
              +
              +
              +

              The default implementation of IAPPurchaseDelegate if no other is provided. It is enough if you only have non-consumable and/or auto-renewable subscription products.

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public class DefaultPurchaseDelegate : IAPPurchaseDelegate
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + IAPPurchaseDelegate + +
              +
              +
              +
              +
              +
              +

              The protocol that you must adopt if you have consumable and/or non-renewing subscription products.

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public protocol IAPPurchaseDelegate
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + IAPProduct + +
              +
              +
              +
              +
              +
              +

              Undocumented

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public struct IAPProduct
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + IAPProductType + +
              +
              +
              +
              +
              +
              +

              Undocumented

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public enum IAPProductType
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + SKProduct + +
              +
              +
              +
              +
              +
              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              extension SKProduct
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + IAPPeriodFormat + +
              +
              +
              +
              +
              +
              +

              Undocumented

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public enum IAPPeriodFormat
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + IAPPurchaseCallback + +
              +
              +
              +
              +
              +
              +

              Undocumented

              + +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public typealias IAPPurchaseCallback = (IAPPurchaseResult) -> Void
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + IAPRefreshCallback + +
              +
              +
              +
              +
              +
              +

              Undocumented

              + +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public typealias IAPRefreshCallback = (IAPRefreshResult) -> Void
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + IAPPurchaseResult + +
              +
              +
              +
              +
              +
              +

              The result returned in the purchase() callback.

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public struct IAPPurchaseResult
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + IAPRefreshResult + +
              +
              +
              +
              +
              +
              +

              The result returned in the refresh() or restorePurchases() callback.

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public struct IAPRefreshResult
              + +
              +
              +
              +
              +
            • +
            • + +
              +
              +
              +
              +
              +

              The list of the different states of the IAPPurchaseResult.

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public enum IAPPurchaseResultState
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + IAPRefreshResultState + +
              +
              +
              +
              +
              +
              +

              The list of the different states of the IAPRefreshResult.

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public enum IAPRefreshResultState
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + IAPError + +
              +
              +
              +
              +
              +
              +

              When calling refresh(), purchase() or restorePurchases(), the callback can return an IAPError if the state is failed.

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public struct IAPError : IAPErrorProtocol
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + IAPErrorCode + +
              +
              +
              +
              +
              +
              +

              The list of error codes that can be returned by the library.

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public enum IAPErrorCode
              + +
              +
              +
              +
              +
            • +
            • +
              + + + + IAPErrorProtocol + +
              +
              +
              +
              +
              +
              +

              Undocumented

              + + See more +
              +
              +

              Declaration

              +
              +

              Swift

              +
              public protocol IAPErrorProtocol : LocalizedError
              + +
              +
              +
              +
              +
            • +
            +
            +
            +
            + +
            +
            + + + + diff --git a/docs/jazzy/Classes/DefaultPurchaseDelegate.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes/DefaultPurchaseDelegate.html similarity index 50% rename from docs/jazzy/Classes/DefaultPurchaseDelegate.html rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes/DefaultPurchaseDelegate.html index 3a8424b..5e4025c 100644 --- a/docs/jazzy/Classes/DefaultPurchaseDelegate.html +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes/DefaultPurchaseDelegate.html @@ -4,116 +4,163 @@ DefaultPurchaseDelegate Class Reference - + + + + + + -
            -
            -

            InAppPurchaseLib (52% documented)

            -

            View on GitHub

            -
            -
            -
            -
            +

            + + InAppPurchaseLib documentation + + (77% documented)

            -
            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + + + + + + + +
            +
            -
              +
              • @@ -202,14 +252,15 @@

                Parameters

            -
            - - + + diff --git a/docs/jazzy/Classes/InAppPurchase.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes/InAppPurchase.html similarity index 87% rename from docs/jazzy/Classes/InAppPurchase.html rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes/InAppPurchase.html index b43f50e..269267c 100644 --- a/docs/jazzy/Classes/InAppPurchase.html +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes/InAppPurchase.html @@ -4,116 +4,163 @@ InAppPurchase Class Reference - + + + + + + -
            -
            -

            InAppPurchaseLib (52% documented)

            -

            View on GitHub

            -
            -
            -
            -
            +

            + + InAppPurchaseLib documentation + + (77% documented)

            -
            + +

            +

            + +
            +

            + +

            + + + View on GitHub + +

            + + + + +
            -
            -
              +
              • @@ -446,7 +495,7 @@

                Products information

                Gets all products retrieved from the App Store

                See

                - See also: SKProduct. + See also: SKProduct
                @@ -482,7 +531,7 @@

                Return Value

                Gets the product by its identifier from the list of products retrieved from the App Store.

                See

                - See also: SKProduct. + See also: SKProduct
                @@ -533,7 +582,7 @@

                Purchasing and Restoring

                -
                  +
                  • @@ -581,7 +630,7 @@

                    Return Value

                    Request a Payment from the App Store.

                    See

                    - See also:IAPPurchaseCallback and IAPPurchaseResult. + See also: IAPPurchaseResult
                    @@ -590,7 +639,7 @@

                    Return Value

                    Declaration

                    Swift

                    -
                    public static func purchase(productIdentifier: String, quantity: Int, callback: @escaping IAPPurchaseCallback)
                    +
                    public static func purchase(productIdentifier: String, quantity: Int, callback: @escaping IAPPurchaseCallback)
                    @@ -656,7 +705,7 @@

                    Parameters

                    Restore purchased products.

                    See

                    - See also:IAPRefreshCallback and IAPRefreshResult. + See also: IAPRefreshResult
                    @@ -665,7 +714,7 @@

                    Parameters

                    Declaration

                    Swift

                    -
                    public static func restorePurchases(callback: @escaping IAPRefreshCallback)
                    +
                    public static func restorePurchases(callback: @escaping IAPRefreshCallback)
                    @@ -799,7 +848,7 @@

                    Purchases information

                    -
                      +
                      • @@ -1014,14 +1063,15 @@

                        Return Value

                      - - - + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPErrorCode.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPErrorCode.html similarity index 62% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPErrorCode.html rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPErrorCode.html index b78db89..16f2456 100644 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPErrorCode.html +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPErrorCode.html @@ -4,116 +4,163 @@ IAPErrorCode Enumeration Reference - + + + + + + -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      -
                      +

                      + + InAppPurchaseLib documentation + + (77% documented)

                      -
                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + + + + + + + +
                      +
                      -
                        +
                        + + +
                        + +

                        Errors returned by refresh(), purchase() or restorePurchases()

                        +

                        +
                        +
                        +
                        • @@ -140,7 +199,7 @@

                          IAPErrorCode

                          -

                          Undocumented

                          +

                          You must call the initialize fuction before using the library.

                          @@ -157,9 +216,9 @@

                          Declaration

                        • @@ -167,14 +226,14 @@

                          Declaration

                          -

                          Undocumented

                          +

                          The Bundle Identifier is invalid.

                          Declaration

                          Swift

                          -
                          case productNotFound
                          +
                          case bundleIdentifierInvalid
                          @@ -184,9 +243,9 @@

                          Declaration

                        • @@ -194,14 +253,14 @@

                          Declaration

                          -

                          Undocumented

                          +

                          The Validator URL String is invalid.

                          Declaration

                          Swift

                          -
                          case cannotMakePurchase
                          +
                          case validatorUrlInvalid
                          @@ -211,9 +270,9 @@

                          Declaration

                        • @@ -221,14 +280,14 @@

                          Declaration

                          -

                          Undocumented

                          +

                          Failed to refresh the App Store receipt.

                          Declaration

                          Swift

                          -
                          case alreadyPurchasing
                          +
                          case refreshReceiptFailed
                          @@ -238,9 +297,9 @@

                          Declaration

                        • @@ -248,14 +307,14 @@

                          Declaration

                          -

                          Undocumented

                          +

                          Failed to validate the App Store receipt with Fovea.

                          Declaration

                          Swift

                          -
                          case bundleIdentifierInvalid
                          +
                          case validateReceiptFailed
                          @@ -265,9 +324,9 @@

                          Declaration

                        • @@ -275,26 +334,39 @@

                          Declaration

                          -

                          Undocumented

                          +

                          Failed to read the receipt validation.

                          Declaration

                          Swift

                          -
                          case validatorUrlInvalid
                          +
                          case readReceiptFailed
                        • +
                        +
                      +
                      +
                      + + +
                      + +

                      Errors returned by refresh()

                      +

                      +
                      +
                      +
                      • @@ -302,26 +374,39 @@

                        Declaration

                        -

                        Undocumented

                        +

                        Failed to refresh products from the App Store.

                        Declaration

                        Swift

                        -
                        case refreshReceiptFailed
                        +
                        case refreshProductsFailed
                      • +
                      +
                      +
                      +
                      + + +
                      + +

                      Errors returned by purchase()

                      +

                      +
                      +
                      +
                      • @@ -329,14 +414,14 @@

                        Declaration

                        -

                        Undocumented

                        +

                        The product was not found on the App Store and cannot be purchased.

                        Declaration

                        Swift

                        -
                        case validateReceiptFailed
                        +
                        case productNotFound
                        @@ -346,9 +431,9 @@

                        Declaration

                      • @@ -356,14 +441,14 @@

                        Declaration

                        -

                        Undocumented

                        +

                        The user is not allowed to authorize payments.

                        Declaration

                        Swift

                        -
                        case readReceiptFailed
                        +
                        case cannotMakePurchase
                        @@ -373,9 +458,9 @@

                        Declaration

                      • @@ -383,14 +468,14 @@

                        Declaration

                        -

                        Undocumented

                        +

                        A purchase is already in progress.

                        Declaration

                        Swift

                        -
                        case refreshProductsFailed
                        +
                        case alreadyPurchasing
                        @@ -399,14 +484,15 @@

                        Declaration

                      -
                      - - + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPPeriodFormat.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPPeriodFormat.html new file mode 100644 index 0000000..d2e9a5f --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPPeriodFormat.html @@ -0,0 +1,247 @@ + + + + IAPPeriodFormat Enumeration Reference + + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      +

                      IAPPeriodFormat

                      +
                      +
                      +
                      public enum IAPPeriodFormat
                      + +
                      +
                      +

                      Undocumented

                      + +
                      +
                      + +
                      +
                      +
                      +
                        +
                      • +
                        + + + + short + +
                        +
                        +
                        +
                        +
                        +
                        +

                        Undocumented

                        + +
                        +
                        +

                        Declaration

                        +
                        +

                        Swift

                        +
                        case short
                        + +
                        +
                        +
                        +
                        +
                      • +
                      • +
                        + + + + long + +
                        +
                        +
                        +
                        +
                        +
                        +

                        Undocumented

                        + +
                        +
                        +

                        Declaration

                        +
                        +

                        Swift

                        +
                        case long
                        + +
                        +
                        +
                        +
                        +
                      • +
                      +
                      +
                      +
                      + +
                      +
                      + + + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPProductType.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPProductType.html similarity index 55% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPProductType.html rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPProductType.html index 5f397d9..645973d 100644 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPProductType.html +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPProductType.html @@ -4,116 +4,163 @@ IAPProductType Enumeration Reference - + + + + + + -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      -
                      +

                      + + InAppPurchaseLib documentation + + (77% documented)

                      -
                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + + + + + + + +
                      +
                      -
                        +
                        • @@ -237,14 +287,15 @@

                          Declaration

                      -
                      - - + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPPurchaseResultState.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPPurchaseResultState.html similarity index 53% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPPurchaseResultState.html rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPPurchaseResultState.html index ade15de..42485c4 100644 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPPurchaseResultState.html +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPPurchaseResultState.html @@ -4,116 +4,163 @@ IAPPurchaseResultState Enumeration Reference - + + + + + + -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      -
                      +

                      + + InAppPurchaseLib documentation + + (77% documented)

                      -
                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + + + + + + + +
                      +
                      -
                        +
                        • @@ -140,7 +190,7 @@

                          IAPPurchaseResultState

                          -

                          Undocumented

                          +

                          The purchase was successful.

                          @@ -167,7 +217,7 @@

                          Declaration

                          -

                          Undocumented

                          +

                          Puchase failed.

                          @@ -194,7 +244,7 @@

                          Declaration

                          -

                          Undocumented

                          +

                          The purchase was cancelled by the user.

                          @@ -221,7 +271,7 @@

                          Declaration

                          -

                          Undocumented

                          +

                          The purchase is deferred.

                          @@ -237,14 +287,15 @@

                          Declaration

                      -
                      - - + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPRefreshResultState.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPRefreshResultState.html new file mode 100644 index 0000000..f9151e4 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPRefreshResultState.html @@ -0,0 +1,274 @@ + + + + IAPRefreshResultState Enumeration Reference + + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      +

                      IAPRefreshResultState

                      +
                      +
                      +
                      public enum IAPRefreshResultState
                      + +
                      +
                      +

                      The list of the different states of the IAPRefreshResult.

                      + +
                      +
                      + +
                      +
                      +
                      +
                        +
                      • +
                        + + + + succeeded + +
                        +
                        +
                        +
                        +
                        +
                        +

                        Refresh was successful.

                        + +
                        +
                        +

                        Declaration

                        +
                        +

                        Swift

                        +
                        case succeeded
                        + +
                        +
                        +
                        +
                        +
                      • +
                      • +
                        + + + + failed + +
                        +
                        +
                        +
                        +
                        +
                        +

                        Refresh failed.

                        + +
                        +
                        +

                        Declaration

                        +
                        +

                        Swift

                        +
                        case failed
                        + +
                        +
                        +
                        +
                        +
                      • +
                      • +
                        + + + + skipped + +
                        +
                        +
                        +
                        +
                        +
                        +

                        Refresh has been skipped because it is not necessary.

                        + +
                        +
                        +

                        Declaration

                        +
                        +

                        Swift

                        +
                        case skipped
                        + +
                        +
                        +
                        +
                        +
                      • +
                      +
                      +
                      +
                      + +
                      +
                      + + + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Extensions/SKProduct.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Extensions/SKProduct.html similarity index 68% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Extensions/SKProduct.html rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Extensions/SKProduct.html index 19d937b..8fbe59d 100644 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Extensions/SKProduct.html +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Extensions/SKProduct.html @@ -4,116 +4,163 @@ SKProduct Extension Reference - + + + + + + -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      -
                      +

                      + + InAppPurchaseLib documentation + + (77% documented)

                      -
                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + + + + + + + +
                      +
                      -
                        +
                        • @@ -317,14 +367,15 @@

                          Declaration

                      -
                      - - + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Getting Started.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Getting Started.html new file mode 100644 index 0000000..717182d --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Getting Started.html @@ -0,0 +1,221 @@ + + + + Getting Started Reference + + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      +

                      Getting Started

                      +

                      If you haven’t already, I highly recommend your read the Overview and Preparing section of Apple’s In-App Purchase official documentation.

                      +

                      Requirements

                      + +
                        +
                      • Configure your App and Xcode to support In-App Purchases. + +
                      • +
                      • Create and configure your Fovea.Billing project account: + +
                          +
                        • Set your bundle ID
                        • +
                        • The iOS Shared Secret (or shared key) is to be retrieved from AppStoreConnect
                        • +
                        • The iOS Subscription Status URL (only if you want subscriptions)
                        • +
                      • +
                      + +
                      +
                      + +
                      +
                      +
                      + +
                      +
                      +
                      + +
                      +
                      + + + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/IAPErrorProtocol.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/IAPErrorProtocol.html new file mode 100644 index 0000000..8c3d780 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/IAPErrorProtocol.html @@ -0,0 +1,220 @@ + + + + IAPErrorProtocol Protocol Reference + + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      +

                      IAPErrorProtocol

                      +
                      +
                      +
                      public protocol IAPErrorProtocol : LocalizedError
                      + +
                      +
                      +

                      Undocumented

                      + +
                      +
                      + +
                      +
                      +
                      +
                        +
                      • +
                        + + + + code + +
                        +
                        +
                        +
                        +
                        +
                        +

                        Undocumented

                        + +
                        +
                        +

                        Declaration

                        +
                        +

                        Swift

                        +
                        var code: IAPErrorCode { get }
                        + +
                        +
                        +
                        +
                        +
                      • +
                      +
                      +
                      +
                      + +
                      +
                      + + + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/IAPPurchaseDelegate.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/IAPPurchaseDelegate.html new file mode 100644 index 0000000..34c6641 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/IAPPurchaseDelegate.html @@ -0,0 +1,244 @@ + + + + IAPPurchaseDelegate Protocol Reference + + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      +

                      IAPPurchaseDelegate

                      +
                      +
                      +
                      public protocol IAPPurchaseDelegate
                      + +
                      +
                      +

                      The protocol that you must adopt if you have consumable and/or non-renewing subscription products.

                      + +
                      +
                      + +
                      +
                      +
                      +
                        +
                      • + +
                        +
                        +
                        +
                        +
                        +

                        Called when a product is newly purchased, updated or restored.

                        +
                        +

                        Important

                        +

                        You have to acknowledge delivery of the (virtual) item to finalize the transaction. Then you have to call InAppPurchase.finishTransactions(for: productIdentifier)as soon as you have delivered the product.

                        + +
                        + +
                        +
                        +

                        Declaration

                        +
                        +

                        Swift

                        +
                        func productPurchased(productIdentifier: String)
                        + +
                        +
                        +
                        +

                        Parameters

                        + + + + + + + +
                        + + productIdentifier + + +
                        +

                        The identifier of the product.

                        +
                        +
                        +
                        +
                        +
                        +
                      • +
                      +
                      +
                      +
                      + +
                      +
                      + + + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/InAppPurchaseLib.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/InAppPurchaseLib.html similarity index 86% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/InAppPurchaseLib.html rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/InAppPurchaseLib.html index 63ceafc..cdb81d0 100644 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/InAppPurchaseLib.html +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/InAppPurchaseLib.html @@ -4,116 +4,163 @@ InAppPurchaseLib Protocol Reference - + + + + + + -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      -
                      +

                      + + InAppPurchaseLib documentation + + (77% documented)

                      -
                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + + + + + + + +
                      +
                      -
                      -
                        +
                        • @@ -431,7 +481,7 @@

                          Products information

                          Gets all products retrieved from the App Store

                          See

                          - See also: SKProduct. + See also: SKProduct
                          @@ -467,7 +517,7 @@

                          Return Value

                          Gets the product by its identifier from the list of products retrieved from the App Store.

                          See

                          - See also: SKProduct. + See also: SKProduct
                          @@ -518,7 +568,7 @@

                          Purchasing and Restoring

                          -
                      - - + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPError.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPError.html new file mode 100644 index 0000000..3ce0582 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPError.html @@ -0,0 +1,252 @@ + + + + IAPError Structure Reference + + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      +

                      IAPError

                      +
                      +
                      +
                      public struct IAPError : IAPErrorProtocol
                      + +
                      +
                      +

                      When calling refresh(), purchase() or restorePurchases(), the callback can return an IAPError if the state is failed.

                      + +
                      +
                      + +
                      +
                      +
                      +
                        +
                      • +
                        + + + + code + +
                        +
                        +
                        +
                        +
                        +
                        +

                        The error code.

                        +
                        +

                        See

                        + See also: IAPErrorCode. + +
                        + +
                        +
                        +

                        Declaration

                        +
                        +

                        Swift

                        +
                        public var code: IAPErrorCode
                        + +
                        +
                        +
                        +
                        +
                      • +
                      • +
                        + + + + localizedDescription + +
                        +
                        +
                        +
                        +
                        +
                        +

                        The error description.

                        + +
                        +
                        +

                        Declaration

                        +
                        +

                        Swift

                        +
                        public var localizedDescription: String { get }
                        + +
                        +
                        +
                        +
                        +
                      • +
                      +
                      +
                      +
                      + +
                      +
                      + + + + diff --git a/docs/jazzy/Structs/IAPProduct.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPProduct.html similarity index 58% rename from docs/jazzy/Structs/IAPProduct.html rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPProduct.html index 889974f..f52efcb 100644 --- a/docs/jazzy/Structs/IAPProduct.html +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPProduct.html @@ -4,116 +4,163 @@ IAPProduct Structure Reference - + + + + + + -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      -
                      +

                      + + InAppPurchaseLib documentation + + (77% documented)

                      -
                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + + + + + + + +
                      +
                      -
                        +
                        • @@ -251,14 +301,15 @@

                          Parameters

                      -
                      - - + + diff --git a/docs/jazzy/Structs/IAPPurchaseResult.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPPurchaseResult.html similarity index 58% rename from docs/jazzy/Structs/IAPPurchaseResult.html rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPPurchaseResult.html index 6bc3b5d..d17b2a6 100644 --- a/docs/jazzy/Structs/IAPPurchaseResult.html +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPPurchaseResult.html @@ -4,116 +4,163 @@ IAPPurchaseResult Structure Reference - + + + + + + -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      -
                      +

                      + + InAppPurchaseLib documentation + + (77% documented)

                      -
                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + + + + + + + +
                      +
                      -
                        +
                        • @@ -237,14 +287,15 @@

                          Declaration

                      -
                      - - + + diff --git a/docs/jazzy/Structs/IAPRefreshResult.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPRefreshResult.html similarity index 57% rename from docs/jazzy/Structs/IAPRefreshResult.html rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPRefreshResult.html index 8d70385..670d0f2 100644 --- a/docs/jazzy/Structs/IAPRefreshResult.html +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPRefreshResult.html @@ -4,116 +4,163 @@ IAPRefreshResult Structure Reference - + + + + + + -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      -
                      +

                      + + InAppPurchaseLib documentation + + (77% documented)

                      -
                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + + + + + + + +
                      +
                      -
                        +
                        • @@ -237,14 +287,15 @@

                          Declaration

                      -
                      - - + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Usage.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Usage.html new file mode 100644 index 0000000..535a067 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Usage.html @@ -0,0 +1,296 @@ + + + + Usage Reference + + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      +

                      Usage

                      +

                      The process of implementing in-app purchases involves several steps:

                      + +
                        +
                      1. Displaying the list of purchasable products
                      2. +
                      3. Initiating a purchase
                      4. +
                      5. Delivering and finalizing a purchase
                      6. +
                      7. Checking the current ownership of non-consumables and subscriptions
                      8. +
                      9. Implementing the Restore Purchases button
                      10. +
                      + +

                      Note: You have to import InAppPurchaseLib wherever you use the library.

                      + +
                      +
                      + +
                      +
                      +
                      + +
                      +
                      +
                      + +
                      +
                      + + + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/analytics.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/analytics.html new file mode 100644 index 0000000..697340d --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/analytics.html @@ -0,0 +1,221 @@ + + + + Analytics Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Analytics

                      + +

                      Tracking the purchase flow is a common things in apps. Especially as it’s core to your revenue model.

                      + +

                      We can track 5 events, which step in the purchase pipeline a user reached.

                      + +
                        +
                      1. purchase initiated
                      2. +
                      3. purchase cancelled
                      4. +
                      5. purchase failed
                      6. +
                      7. purchase deferred
                      8. +
                      9. purchase succeeded
                      10. +
                      + +

                      Here’s a quick example showing how to implement this correctly.

                      +
                      func makePurchase() {
                      +  Analytics.trackEvent("purchase initiated")
                      +  InAppPurchase.purchase(
                      +    productIdentifier: "my_product_id",
                      +    callback: { result in
                      +      switch result.state {
                      +      case .purchased:
                      +        // Reminder: We are not processing the purchase here, only updating your UI.
                      +        //           That's why we do not send an event to analytics.
                      +      case .failed:
                      +        Analytics.trackEvent("purchase failed")
                      +      case .deferred:
                      +        Analytics.trackEvent("purchase deferred")
                      +      case .cancelled:
                      +        Analytics.trackEvent("purchase cancelled")
                      +    }
                      +  })
                      +}
                      +
                      +// IAPPurchaseDelegate implementation
                      +func productPurchased(productIdentifier: String) {
                      +  Analytics.trackEvent("purchase succeeded")
                      +  InAppPurchase.finishTransactions(for: productIdentifier)
                      +}
                      +
                      + +

                      The important part to remember is that a purchase can occur outside your app (or be approved when the app is not running), that’s why tracking purchase succeeded has to be part of the productPurchased delegate function.

                      + +

                      Refer to the Consumables section to learn more about the productPurchased function.

                      + +
                      +
                      + + +
                      +
                      + + + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/css/highlight.css b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/css/highlight.css similarity index 100% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/css/highlight.css rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/css/highlight.css diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/css/jazzy.css b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/css/jazzy.css new file mode 100644 index 0000000..ff59f5f --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/css/jazzy.css @@ -0,0 +1,395 @@ +*, *:before, *:after { + box-sizing: inherit; } + +body { + margin: 0; + background: #fff; + color: #333; + font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; + letter-spacing: .2px; + -webkit-font-smoothing: antialiased; + box-sizing: border-box; } + +h1 { + font-size: 2rem; + font-weight: 700; + margin: 1.275em 0 0.6em; } + +h2 { + font-size: 1.75rem; + font-weight: 700; + margin: 1.275em 0 0.3em; } + +h3 { + font-size: 1.5rem; + font-weight: 700; + margin: 1em 0 0.3em; } + +h4 { + font-size: 1.25rem; + font-weight: 700; + margin: 1.275em 0 0.85em; } + +h5 { + font-size: 1rem; + font-weight: 700; + margin: 1.275em 0 0.85em; } + +h6 { + font-size: 1rem; + font-weight: 700; + margin: 1.275em 0 0.85em; + color: #777; } + +p { + margin: 0 0 1em; } + +ul, ol { + padding: 0 0 0 2em; + margin: 0 0 0.85em; } + +blockquote { + margin: 0 0 0.85em; + padding: 0 15px; + color: #858585; + border-left: 4px solid #e5e5e5; } + +img { + max-width: 100%; } + +a { + color: #4183c4; + text-decoration: none; } + a:hover, a:focus { + outline: 0; + text-decoration: underline; } + a.discouraged { + text-decoration: line-through; } + a.discouraged:hover, a.discouraged:focus { + text-decoration: underline line-through; } + +table { + background: #fff; + width: 100%; + border-collapse: collapse; + border-spacing: 0; + overflow: auto; + margin: 0 0 0.85em; } + +tr:nth-child(2n) { + background-color: #fbfbfb; } + +th, td { + padding: 6px 13px; + border: 1px solid #ddd; } + +pre { + margin: 0 0 1.275em; + padding: .85em 1em; + overflow: auto; + background: #f7f7f7; + font-size: .85em; + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } + +code { + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; } + +.item-container p > code, .item-container li > code, .top-matter p > code, .top-matter li > code { + background: #f7f7f7; + padding: .2em; } + .item-container p > code:before, .item-container p > code:after, .item-container li > code:before, .item-container li > code:after, .top-matter p > code:before, .top-matter p > code:after, .top-matter li > code:before, .top-matter li > code:after { + letter-spacing: -.2em; + content: "\00a0"; } + +pre code { + padding: 0; + white-space: pre; } + +.content-wrapper { + display: flex; + flex-direction: column; } + @media (min-width: 768px) { + .content-wrapper { + flex-direction: row; } } +.header { + display: flex; + padding: 8px; + font-size: 0.875em; + background: #444; + color: #999; } + +.header-col { + margin: 0; + padding: 0 8px; } + +.header-col--primary { + flex: 1; } + +.header-link { + color: #fff; } + +.header-icon { + padding-right: 6px; + vertical-align: -4px; + height: 16px; } + +.breadcrumbs { + font-size: 0.875em; + padding: 8px 16px; + margin: 0; + background: #fbfbfb; + border-bottom: 1px solid #ddd; } + +.carat { + height: 10px; + margin: 0 5px; } + +.navigation { + order: 2; } + @media (min-width: 768px) { + .navigation { + order: 1; + width: 25%; + max-width: 300px; + padding-bottom: 64px; + overflow: hidden; + word-wrap: normal; + background: #fbfbfb; + border-right: 1px solid #ddd; } } +.nav-groups { + list-style-type: none; + padding-left: 0; } + +.nav-group-name { + border-bottom: 1px solid #ddd; + padding: 8px 0 8px 16px; } + +.nav-group-name-link { + color: #333; } + +.nav-group-tasks { + margin: 8px 0; + padding: 0 0 0 8px; } + +.nav-group-task { + font-size: 1em; + list-style-type: none; + white-space: nowrap; } + +.nav-group-task-link { + color: #808080; } + +.main-content { + order: 1; } + @media (min-width: 768px) { + .main-content { + order: 2; + flex: 1; + padding-bottom: 60px; } } +.section { + padding: 0 32px; + border-bottom: 1px solid #ddd; } + +.section-content { + max-width: 834px; + margin: 0 auto; + padding: 16px 0; } + +.section-name { + color: #666; + display: block; } + .section-name p { + margin-bottom: inherit; } + +.declaration .highlight { + overflow-x: initial; + padding: 8px 0; + margin: 0; + background-color: transparent; + border: none; } + +.task-group-section { + border-top: 1px solid #ddd; } + +.task-group { + padding-top: 0px; } + +.task-name-container a[name]:before { + content: ""; + display: block; } + +.section-name-container { + position: relative; } + .section-name-container .section-name-link { + position: absolute; + top: 0; + left: 0; + bottom: 0; + right: 0; + margin-bottom: 0; } + .section-name-container .section-name { + position: relative; + pointer-events: none; + z-index: 1; } + .section-name-container .section-name a { + pointer-events: auto; } + +.item-container { + padding: 0; } + +.item { + padding-top: 8px; + width: 100%; + list-style-type: none; } + .item a[name]:before { + content: ""; + display: block; } + .item .token, .item .direct-link { + display: inline-block; + text-indent: -20px; + padding-left: 3px; + margin-left: 20px; + font-size: 1rem; } + .item .declaration-note { + font-size: .85em; + color: #808080; + font-style: italic; } + +.pointer-container { + border-bottom: 1px solid #ddd; + left: -23px; + padding-bottom: 13px; + position: relative; + width: 110%; } + +.pointer { + left: 21px; + top: 7px; + display: block; + position: absolute; + width: 12px; + height: 12px; + border-left: 1px solid #ddd; + border-top: 1px solid #ddd; + background: #fff; + transform: rotate(45deg); } + +.height-container { + display: none; + position: relative; + width: 100%; + overflow: hidden; } + .height-container .section { + background: #fff; + border: 1px solid #ddd; + border-top-width: 0; + padding-top: 10px; + padding-bottom: 5px; + padding: 8px 16px; } + +.aside, .language { + padding: 6px 12px; + margin: 12px 0; + border-left: 5px solid #dddddd; + overflow-y: hidden; } + .aside .aside-title, .language .aside-title { + font-size: 9px; + letter-spacing: 2px; + text-transform: uppercase; + padding-bottom: 0; + margin: 0; + color: #aaa; + -webkit-user-select: none; } + .aside p:last-child, .language p:last-child { + margin-bottom: 0; } + +.language { + border-left: 5px solid #cde9f4; } + .language .aside-title { + color: #4183c4; } + +.aside-warning, .aside-deprecated, .aside-unavailable { + border-left: 5px solid #ff6666; } + .aside-warning .aside-title, .aside-deprecated .aside-title, .aside-unavailable .aside-title { + color: #ff0000; } + +.graybox { + border-collapse: collapse; + width: 100%; } + .graybox p { + margin: 0; + word-break: break-word; + min-width: 50px; } + .graybox td { + border: 1px solid #ddd; + padding: 5px 25px 5px 10px; + vertical-align: middle; } + .graybox tr td:first-of-type { + text-align: right; + padding: 7px; + vertical-align: top; + word-break: normal; + width: 40px; } + +.slightly-smaller { + font-size: 0.9em; } + +.footer { + padding: 8px 16px; + background: #444; + color: #ddd; + font-size: 0.8em; } + .footer p { + margin: 8px 0; } + .footer a { + color: #fff; } + +html.dash .header, html.dash .breadcrumbs, html.dash .navigation { + display: none; } + +html.dash .height-container { + display: block; } + +form[role=search] input { + font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; + font-size: 14px; + line-height: 24px; + padding: 0 10px; + margin: 0; + border: none; + border-radius: 1em; } + .loading form[role=search] input { + background: white url(../img/spinner.gif) center right 4px no-repeat; } + +form[role=search] .tt-menu { + margin: 0; + min-width: 300px; + background: #fbfbfb; + color: #333; + border: 1px solid #ddd; } + +form[role=search] .tt-highlight { + font-weight: bold; } + +form[role=search] .tt-suggestion { + font: 16px/1.7 "Helvetica Neue", Helvetica, Arial, sans-serif; + padding: 0 8px; } + form[role=search] .tt-suggestion span { + display: table-cell; + white-space: nowrap; } + form[role=search] .tt-suggestion .doc-parent-name { + width: 100%; + text-align: right; + font-weight: normal; + font-size: 0.9em; + padding-left: 16px; } + +form[role=search] .tt-suggestion:hover, +form[role=search] .tt-suggestion.tt-cursor { + cursor: pointer; + background-color: #4183c4; + color: #fff; } + +form[role=search] .tt-suggestion:hover .doc-parent-name, +form[role=search] .tt-suggestion.tt-cursor .doc-parent-name { + color: #fff; } diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/displaying-products-with-purchases.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/displaying-products-with-purchases.html new file mode 100644 index 0000000..d77fc40 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/displaying-products-with-purchases.html @@ -0,0 +1,231 @@ + + + + Displaying products with purchases Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Displaying products with purchases

                      + +

                      In your store screen, where you present your products titles and prices with a purchase button, there are some cases to handle that we skipped. Owned products and deferred purchases.

                      +

                      Owned products

                      + +

                      Non-consumables and active auto-renewing subscriptions cannot be purchased again. You should adjust your UI to reflect that state. Refer to InAppPurchase.hasActivePurchase() to and to the example later in this section.

                      +

                      Deferred purchases

                      + +

                      Apple’s Ask to Buy feature lets parents approve any purchases initiated by children, including in-app purchases.

                      + +

                      With Ask to Buy enabled, when a child requests to make a purchase, the app is notified that the purchase is awaiting the parent’s approval in the purchase callback:

                      +
                      InAppPurchase.purchase(
                      +  productIdentifier: productIdentifier,
                      +  callback: { result in
                      +    switch result.state {
                      +    case .deferred:
                      +      // Pending parent approval
                      +  }
                      +})
                      +
                      + +

                      In the deferred case, the child has been notified by StoreKit that the parents have to approve the purchase. He might then close the app and come back later. You don’t have much to do, but to display in your UI that there is a purchase waiting for parental approval in your views.

                      + +

                      We will use the hasDeferredTransaction method:

                      +
                      InAppPurchase.hasDeferredTransaction(for productIdentifier: String) -> Bool
                      +
                      +

                      Example

                      + +

                      Here’s an example that covers what has been discussed above. We will update our example refreshView function from before:

                      +
                      @objc func refreshView() {
                      +  guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else {
                      +    self.titleLabel.text = "Product unavailable"
                      +    return
                      +  }
                      +  self.titleLabel.text = product.localizedTitle
                      +  // ...
                      +
                      +  // "Ask to Buy" deferred purchase waiting for parent's approval
                      +  if InAppPurchase.hasDeferredTransaction(for: "my_product_id") {
                      +    self.statusLabel.text = "Waiting for Approval..."
                      +    self.purchaseButton.isPointerInteractionEnabled = false
                      +  }
                      +  // "Owned" product
                      +  else if InAppPurchase.hasActivePurchase(for: "my_product_id") {
                      +    self.statusLabel.text = "OWNED"
                      +    self.purchaseButton.isPointerInteractionEnabled = false
                      +  }
                      +  else {
                      +    self.purchaseButton.isPointerInteractionEnabled = true
                      +  }
                      +}
                      +
                      + +

                      When a product is owned or has a deferred purchase, we make sure the purchase button is grayed out. We also use a status label to display some details. Of course, you are free to design your UI as you see fit.

                      + +
                      +
                      + + +
                      +
                      + + + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/displaying-products.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/displaying-products.html new file mode 100644 index 0000000..cc50b1f --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/displaying-products.html @@ -0,0 +1,213 @@ + + + + Displaying products Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Displaying products

                      + +

                      Let’s start with the simplest case: you have a single product.

                      + +

                      You can retrieve all information about this product using the function InAppPurchase.getProductBy(identifier: "my_product_id"). This returns an SKProduct extended with helpful methods.

                      + +

                      Those are the most important:

                      + +
                        +
                      • productIdentifier: String - The string that identifies the product to the Apple AppStore.
                      • +
                      • localizedTitle: String - The name of the product, in the language of the device, as retrieved from the AppStore.
                      • +
                      • localizedDescription: String - A description of the product, in the language of the device, as retrieved from the AppStore.
                      • +
                      • localizedPrice: String - The cost of the product in the local currency (read-only property added by this library).
                      • +
                      + +

                      Example:

                      + +

                      You can add a function similar to this to your view.

                      +
                      @objc func refreshView() {
                      +  guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else {
                      +    self.titleLabel.text = "Product unavailable"
                      +    return
                      +  }
                      +  self.titleLabel.text = product.localizedTitle
                      +  self.descriptionLabel.text = product.localizedDescription
                      +  self.priceLabel.text = product.localizedPrice
                      +}
                      +
                      + +

                      This example assumes self.titleLabel is a UILabel, etc.

                      + +

                      Make sure to call this function when the view appears on screen, for instance by calling it from viewWillAppear.

                      +
                      override func viewWillAppear(_ animated: Bool) {
                      +  self.refreshView()
                      +}
                      +
                      + +
                      +
                      + + +
                      +
                      + + + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/displaying-subscriptions.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/displaying-subscriptions.html new file mode 100644 index 0000000..640c8ff --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/displaying-subscriptions.html @@ -0,0 +1,214 @@ + + + + Displaying subscriptions Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Displaying subscriptions

                      + +

                      For subscription products, you also have some data about subscription periods and introductory offers.

                      + +
                        +
                      • func hasIntroductoryPriceEligible() -> Bool - The product has an introductory price the user is eligible to.
                      • +
                      • localizedSubscriptionPeriod: String? - The period of the subscription.
                      • +
                      • localizedIntroductoryPrice: String? - The cost of the introductory offer if available in the local currency.
                      • +
                      • localizedIntroductoryPeriod: String? - The subscription period of the introductory offer.
                      • +
                      • localizedIntroductoryDuration: String? - The duration of the introductory offer.
                      • +
                      + +

                      Example

                      +
                      @objc func refreshView() {
                      +  guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else {
                      +    self.titleLabel.text = "Product unavailable"
                      +    return
                      +  }
                      +  self.titleLabel.text = product.localizedTitle
                      +  self.descriptionLabel.text = product.localizedDescription
                      +
                      +  // Format price text. Example: "0,99€ / month for 3 months (then 3,99 € / month)"
                      +  var priceText = "\(product.localizedPrice) / \(product.localizedSubscriptionPeriod!)"
                      +  if product.hasIntroductoryPriceEligible() {
                      +      if product.introductoryPrice!.numberOfPeriods == 1 {
                      +          priceText = "\(product.localizedIntroductoryPrice!) for \(product.localizedIntroductoryDuration!)" +
                      +          " (then \(priceText))"
                      +      } else {
                      +          priceText = "\(product.localizedIntroductoryPrice!) / \(product.localizedIntroductoryPeriod!)" +
                      +          " for \(product.localizedIntroductoryDuration!) (then \(priceText))"
                      +      }
                      +  }
                      +  self.priceLabel.text = priceText
                      +}
                      +
                      + +

                      Note: You have to import StoreKit wherever you use SKProduct.

                      + +
                      +
                      + + +
                      +
                      + + + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/errors.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/errors.html new file mode 100644 index 0000000..33fa397 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/errors.html @@ -0,0 +1,206 @@ + + + + Errors Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Errors

                      + +

                      When calling refresh(), purchase() or restorePurchases(), the callback can return an IAPError if the state is failed. +Here is the list of IAPErrorCode you can receive:

                      + +
                        +
                      • Errors returned by refresh(), purchase() or restorePurchases()

                        + +
                          +
                        • libraryNotInitialized - You must call the initialize fuction before using the library.
                        • +
                        • bundleIdentifierInvalid - The Bundle Identifier is invalid.
                        • +
                        • validatorUrlInvalid - The Validator URL String is invalid.
                        • +
                        • refreshReceiptFailed - Failed to refresh the App Store receipt.
                        • +
                        • validateReceiptFailed - Failed to validate the App Store receipt with Fovea.
                        • +
                        • readReceiptFailed - Failed to read the receipt validation.
                        • +
                      • +
                      • Errors returned by refresh()

                        + +
                          +
                        • refreshProductsFailed - Failed to refresh products from the App Store.
                        • +
                      • +
                      • Errors returned by purchase()

                        + +
                          +
                        • productNotFound - The product was not found on the App Store and cannot be purchased.
                        • +
                        • cannotMakePurchase - The user is not allowed to authorize payments.
                        • +
                        • alreadyPurchasing - A purchase is already in progress.
                        • +
                      • +
                      + +
                      +
                      + + +
                      +
                      + + + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/handling-purchases.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/handling-purchases.html new file mode 100644 index 0000000..00379e9 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/handling-purchases.html @@ -0,0 +1,271 @@ + + + + Handling purchases Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Handling purchases

                      + +

                      Finally, the magic happened: a user purchased one of your products! Let’s see how we handle the different types of products.

                      + + + +

                      +

                      Non-Consumables

                      + +

                      Wherever your app needs to know if a non-consumable product has been purchased, use InAppPurchase.hasActivePurchase(for: +productIdentifier). This will return true if the user currently owns the product.

                      + +

                      Note: The last known state for the user’s purchases is stored as UserDefaults. As such, their status is always available to your app, even when offline.

                      + +

                      If you have a server that needs to know about the purchase. You should rely on Fovea’s webhook instead of doing anything in here. We will see that later in the Server integration section.

                      + +

                      +

                      Auto-Renewable Subscriptions

                      + +

                      As with non-consumables, you will use InAppPurchase.hasActivePurchase(for: productIdentifier) to check if the user is an active subscriber to a given product.

                      + +

                      You might also like to call refresh regularly, for example when entering your main view. When appropriate, the library will refresh the receipt to detect subscription renewals or expiry.

                      + +

                      As we’ve seend in the Refreshing section:

                      +
                      override func viewWillAppear(_ animated: Bool) {
                      +  self.refreshView()
                      +  InAppPurchase.refresh(callback: { _ in
                      +      self.refreshView()
                      +  })
                      +}
                      +
                      + +

                      Note: Don’t be reluctant to call refresh() often. Internally, the library ensures heavy operation are only performed if necessary: for example when a subscription just expired. So in 99% of cases this call will result in no-operations.

                      + +

                      +

                      Consumables

                      + +

                      If the purchased products in a consumable, your app is responsible for delivering the purchase then acknowlege that you’ve done so. Delivering generally consists in increasing a counter for some sort of virtual currency.

                      + +

                      Your app can be notified of a purchase at any time. So the library asks you to provide an IAPPurchaseDelegate from initialization.

                      + +

                      In InAppPurchase.initialize(), we can pass an IAPPurchaseDelegate instance. This object implements the productPurchased(productIdentifier:) function, which is called whenever a purchase is approved.

                      + +

                      Here’s a example implementation:

                      +
                      class AppDelegate: UIResponder, UIApplicationDelegate, IAPPurchaseDelegate {
                      +  ...
                      +  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      +    InAppPurchase.initialize(
                      +      iapProducts: [...],
                      +      iapPurchaseDelegate: self, // ADDED: iapPurchaseDelegate
                      +      validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678")
                      +  }
                      +
                      +  // IAPPurchaseDelegate implementation
                      +  func productPurchased(productIdentifier: String) {
                      +    // TODO
                      +  }
                      +}
                      +
                      + +

                      It’s also important to know that when a purchase is approved, money isn’t yet to reach your bank account. You have to acknowledge delivery of the (virtual) item to finalize the transaction. That is why we have to call InAppPurchase.finishTransactions(for: productIdentifier) as soon as we delivered the product.

                      + +

                      Example

                      + +

                      Let’s define a class that adopts the IAPPurchaseDelegate protocol, it can very well be your application delegate.

                      +
                      func productPurchased(productIdentifier: String) {
                      +  switch productIdenfier {
                      +  case "10_silver":
                      +    addSilver(10)
                      +  case "100_silver":
                      +    addSilver(100)
                      +  }
                      +  InAppPurchase.finishTransactions(for: productIdentifier)
                      +  Analytics.trackEvent("purchase succeeded", productIdentifier)
                      +}
                      +
                      + +

                      Here, we implement our own unlocking logic and call InAppPurchase.finishTransactions() afterward (assuming addSilver is synchronous).

                      + +

                      Note: productPurchased is called when a purchase has been confirmed by Fovea’s receipt validator. If you have a server, he probably already has been notified of this purchase using the webhook.

                      + +

                      Reminder: Keep in mind that purchase notifications might occur even if you never called the InAppPurchase.purchase() function: purchases can be made from another device or the AppStore, they can be approved by parents when the app isn’t running, purchase flows can be interupted, etc. The pattern above ensures your app is always ready to handle purchase events.

                      + +

                      +

                      Non-Renewing Subscriptions

                      + +

                      For non-renewing subscriptions, delivering consists in increasing the amount of time a user can access a given feature. Apple doesn’t manage the length and expiry of non-renewing subscriptions: you have to do this yourself, as for consumables.

                      + +

                      Basically, everything is identical to consumables.

                      + +
                      +
                      + + +
                      +
                      + + + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/carat.png b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/carat.png similarity index 100% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/carat.png rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/carat.png diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/dash.png b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/dash.png similarity index 100% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/dash.png rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/dash.png diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/gh.png b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/gh.png similarity index 100% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/gh.png rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/gh.png diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/spinner.gif b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/spinner.gif new file mode 100644 index 0000000..e3038d0 Binary files /dev/null and b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/img/spinner.gif differ diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/index.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/index.html new file mode 100644 index 0000000..268c210 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/index.html @@ -0,0 +1,325 @@ + + + + InAppPurchaseLib Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      + +

                      + +
                      +

                      An easy-to-use Swift library for In-App Purchases, using Fovea.Billing for receipts validation.

                      +
                      +

                      Features

                      + +
                        +
                      • ✅ Purchase a product
                      • +
                      • ✅ Restore purchased products
                      • +
                      • ✅ Verify transactions with the App Store on Fovea.Billing server
                      • +
                      • ✅ Handle and notify payment transaction states
                      • +
                      • ✅ Retreive products information from the App Store
                      • +
                      • ✅ Support all product types (consumable, non-consumable, auto-renewable subscription, non-renewing subscription)
                      • +
                      • ✅ Status of purchases available when offline
                      • +
                      • ✅ Server integration with a Webhook
                      • +
                      +

                      Getting Started

                      + +

                      If you haven’t already, I highly recommend your read the Overview and Preparing section of Apple’s In-App Purchase official documentation.

                      +

                      Installation

                      + +
                        +
                      • Select your project in Xcode
                      • +
                      • Go to the section Swift Package
                      • +
                      • Click on (+) Add Package Dependency
                      • +
                      • Copy the Git URL: https://github.com/iridescent-dev/iap-swift-lib.git
                      • +
                      • Click on Next > Next
                      • +
                      • Make sure your project is selected in Add to target
                      • +
                      • Click on Finish
                      • +
                      + +

                      Note: You have to import InAppPurchaseLib wherever you use the library.

                      +

                      Micro Example

                      +
                      /** AppDelegate.swift */
                      +import UIKit
                      +import InAppPurchaseLib
                      +
                      +@UIApplicationMain
                      +class AppDelegate: UIResponder, UIApplicationDelegate {
                      +  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      +    // Initialize the library
                      +    InAppPurchase.initialize(
                      +      iapProducts: [
                      +        IAPProduct(productIdentifier: "my_product", productType: .nonConsumable)
                      +      ],
                      +      validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678"
                      +    )
                      +    return true
                      +  }
                      +
                      +  func applicationWillTerminate(_ application: UIApplication) {
                      +    // clean
                      +    InAppPurchase.stop()
                      +  }
                      +}
                      +
                      +
                      /** ViewController.swift */
                      +import UIKit
                      +import StoreKit
                      +import InAppPurchaseLib
                      +
                      +class ViewController: UIViewController {
                      +  private var loaderView = LoaderView()
                      +  @IBOutlet weak var statusLabel: UILabel!
                      +  @IBOutlet weak var productTitleLabel: UILabel!
                      +  @IBOutlet weak var productDescriptionLabel: UILabel!
                      +  @IBOutlet weak var purchaseButton: UIButton!
                      +  @IBOutlet weak var restorePurchasesButton: UIButton!
                      +
                      +  override func viewDidLoad() {
                      +    super.viewDidLoad()
                      +    // Add action for purchases and restore butons.
                      +    purchaseButton.addTarget(self, action: #selector(self.purchase), for: .touchUpInside)
                      +    restorePurchasesButton.addTarget(self, action: #selector(self.restorePurchases), for: .touchUpInside)
                      +  }
                      +
                      +  override func viewWillAppear(_ animated: Bool) {
                      +    self.refreshView()
                      +    InAppPurchase.refresh(callback: { _ in
                      +      self.refreshView()
                      +    })
                      +  }
                      +
                      +  func refreshView() {
                      +    guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product") else {
                      +      self.productTitleLabel.text = "Product unavailable"
                      +      return
                      +    }
                      +    // Display product information.
                      +    productTitleLabel.text = product.localizedTitle
                      +    productDescriptionLabel.text = product.localizedDescription
                      +    purchaseButton.setTitle(product.localizedPrice, for: .normal)
                      +
                      +    // Disable the button if the product has already been purchased.
                      +    if InAppPurchase.hasActivePurchase(for: "my_product") {
                      +      statusLabel.text = "OWNED"
                      +      purchaseButton.isPointerInteractionEnabled = false
                      +    }
                      +  }
                      +
                      +  @IBAction func purchase(_ sender: Any) {
                      +    self.loaderView.show()
                      +    InAppPurchase.purchase(
                      +      productIdentifier: "my_product",
                      +      callback: { result in
                      +        self.loaderView.hide()
                      +      })
                      +  }
                      +
                      +  @IBAction func restorePurchases(_ sender: Any) {
                      +    self.loaderView.show()
                      +    InAppPurchase.restorePurchases(callback: { result in
                      +      self.loaderView.hide()
                      +    })
                      +  }
                      +}
                      +
                      +

                      Documentation

                      + + + +

                      See also:

                      + + +

                      Xcode Demo Project

                      + +

                      Do not hesitate to check the demo project available on here: iap-swift-lib-demo.

                      +

                      Coding

                      + +

                      Generate the documentation, using Jazzy by running the following command:

                      +
                      jazzy
                      +
                      +

                      Troubleshooting

                      + +

                      Common issues are covered here: https://github.com/iridescent-dev/iap-swift-lib/wiki/Troubleshooting

                      +

                      License

                      + +

                      InAppPurchaseLib is open-sourced library licensed under the MIT License. See LICENSE for details.

                      + +
                      +
                      + + +
                      +
                      + + + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/initialization.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/initialization.html new file mode 100644 index 0000000..a87c6e0 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/initialization.html @@ -0,0 +1,227 @@ + + + + Initialization Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Initialization

                      + +

                      Before everything else the library must be initialized. This has to happen as soon as possible. A good way is to call the InAppPurchase.initialize() method when the application did finish launching. In the background, this will load your products and refresh the status of purchases and subscriptions.

                      + +

                      InAppPurchase.initialize() requires the following arguments:

                      + +
                        +
                      • iapProducts - An array of IAPProduct
                      • +
                      • validatorUrlString - The validator url retrieved from Fovea
                      • +
                      + +

                      Each IAPProduct contains the following fields:

                      + +
                        +
                      • productIdentifier - The product unique identifier
                      • +
                      • productType - The IAPProductType (consumable, nonConsumable, nonRenewingSubscription or autoRenewableSubscription)
                      • +
                      + +

                      Example:

                      + +

                      A good place is generally in your application delegate’s didFinishLaunchingWithOptions function, like below:

                      +
                      import InAppPurchaseLib
                      +
                      +class AppDelegate: UIResponder, UIApplicationDelegate, IAPPurchaseDelegate {
                      +  ...
                      +  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      +    InAppPurchase.initialize(
                      +      iapProducts: [
                      +        IAPProduct(productIdentifier: "monthly_plan", productType: .autoRenewableSubscription),
                      +        IAPProduct(productIdentifier: "yearly_plan",  productType: .autoRenewableSubscription),
                      +        IAPProduct(productIdentifier: "disable_ads",  productType: .nonConsumable)
                      +      ],
                      +      validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678")
                      +  }
                      +
                      +  func productPurchased(productIdentifier: String) {
                      +    // ... process purchase (we'll see that later)
                      +  }
                      +}
                      +
                      + +

                      You should also call the stop method when the application will terminate, for proper cleanup.

                      +
                        func applicationWillTerminate(_ application: UIApplication) {
                      +    InAppPurchase.stop()
                      +  }
                      +
                      + +

                      For more advanced use cases, in particular when you have implemented user login, you’ll have to make some adjustments. We’ll learn more about this in the Server integration section.

                      + +

                      Tip: If initialization was successful, you should see a new receipt validation event in Fovea’s Dashboard.

                      + +
                      +
                      + + +
                      +
                      + + + + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/installation.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/installation.html new file mode 100644 index 0000000..637dbb0 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/installation.html @@ -0,0 +1,194 @@ + + + + Installation Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Installation

                      + +

                      + +

                      + +
                        +
                      • Select your project in Xcode
                      • +
                      • Go to the section Swift Package
                      • +
                      • Click on (+) Add Package Dependency
                      • +
                      • Copy the Git URL: https://github.com/iridescent-dev/iap-swift-lib.git
                      • +
                      • Click on Next > Next
                      • +
                      • Make sure your project is selected in Add to target
                      • +
                      • Click on Finish
                      • +
                      + +

                      Note: You have to import InAppPurchaseLib wherever you use the library.

                      + +
                      +
                      + + +
                      +
                      + + + + diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/jazzy.js b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/jazzy.js similarity index 100% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/jazzy.js rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/jazzy.js diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/jazzy.search.js b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/jazzy.search.js new file mode 100644 index 0000000..e3d1ab9 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/jazzy.search.js @@ -0,0 +1,70 @@ +$(function(){ + var $typeahead = $('[data-typeahead]'); + var $form = $typeahead.parents('form'); + var searchURL = $form.attr('action'); + + function displayTemplate(result) { + return result.name; + } + + function suggestionTemplate(result) { + var t = '
                      '; + t += '' + result.name + ''; + if (result.parent_name) { + t += '' + result.parent_name + ''; + } + t += '
                      '; + return t; + } + + $typeahead.one('focus', function() { + $form.addClass('loading'); + + $.getJSON(searchURL).then(function(searchData) { + const searchIndex = lunr(function() { + this.ref('url'); + this.field('name'); + this.field('abstract'); + for (const [url, doc] of Object.entries(searchData)) { + this.add({url: url, name: doc.name, abstract: doc.abstract}); + } + }); + + $typeahead.typeahead( + { + highlight: true, + minLength: 3, + autoselect: true + }, + { + limit: 10, + display: displayTemplate, + templates: { suggestion: suggestionTemplate }, + source: function(query, sync) { + const lcSearch = query.toLowerCase(); + const results = searchIndex.query(function(q) { + q.term(lcSearch, { boost: 100 }); + q.term(lcSearch, { + boost: 10, + wildcard: lunr.Query.wildcard.TRAILING + }); + }).map(function(result) { + var doc = searchData[result.ref]; + doc.url = result.ref; + return doc; + }); + sync(results); + } + } + ); + $form.removeClass('loading'); + $typeahead.trigger('focus'); + }); + }); + + var baseURL = searchURL.slice(0, -"search.json".length); + + $typeahead.on('typeahead:select', function(e, result) { + window.location = baseURL + result.url; + }); +}); diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/jquery.min.js b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/jquery.min.js similarity index 100% rename from docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/jquery.min.js rename to docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/jquery.min.js diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/lunr.min.js b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/lunr.min.js new file mode 100644 index 0000000..f45a81e --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/js/lunr.min.js @@ -0,0 +1 @@ +!function(){var t,l,c,e,r,h,d,f,p,y,m,g,x,v,w,Q,k,S,E,L,b,P,T,O,I,i,n,s,z=function(e){var t=new z.Builder;return t.pipeline.add(z.trimmer,z.stopWordFilter,z.stemmer),t.searchPipeline.add(z.stemmer),e.call(t,t),t.build()};z.version="2.3.5",z.utils={},z.utils.warn=(t=this,function(e){t.console&&console.warn&&console.warn(e)}),z.utils.asString=function(e){return null==e?"":e.toString()},z.utils.clone=function(e){if(null==e)return e;for(var t=Object.create(null),r=Object.keys(e),i=0;i=this.length)return z.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},z.QueryLexer.prototype.width=function(){return this.pos-this.start},z.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},z.QueryLexer.prototype.backup=function(){this.pos-=1},z.QueryLexer.prototype.acceptDigitRun=function(){for(var e,t;47<(t=(e=this.next()).charCodeAt(0))&&t<58;);e!=z.QueryLexer.EOS&&this.backup()},z.QueryLexer.prototype.more=function(){return this.pos', + menu: '
                      ' + }; + } + function buildSelectors(classes) { + var selectors = {}; + _.each(classes, function(v, k) { + selectors[k] = "." + v; + }); + return selectors; + } + function buildCss() { + var css = { + wrapper: { + position: "relative", + display: "inline-block" + }, + hint: { + position: "absolute", + top: "0", + left: "0", + borderColor: "transparent", + boxShadow: "none", + opacity: "1" + }, + input: { + position: "relative", + verticalAlign: "top", + backgroundColor: "transparent" + }, + inputWithNoHint: { + position: "relative", + verticalAlign: "top" + }, + menu: { + position: "absolute", + top: "100%", + left: "0", + zIndex: "100", + display: "none" + }, + ltr: { + left: "0", + right: "auto" + }, + rtl: { + left: "auto", + right: " 0" + } + }; + if (_.isMsie()) { + _.mixin(css.input, { + backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)" + }); + } + return css; + } + }(); + var EventBus = function() { + "use strict"; + var namespace, deprecationMap; + namespace = "typeahead:"; + deprecationMap = { + render: "rendered", + cursorchange: "cursorchanged", + select: "selected", + autocomplete: "autocompleted" + }; + function EventBus(o) { + if (!o || !o.el) { + $.error("EventBus initialized without el"); + } + this.$el = $(o.el); + } + _.mixin(EventBus.prototype, { + _trigger: function(type, args) { + var $e = $.Event(namespace + type); + this.$el.trigger.call(this.$el, $e, args || []); + return $e; + }, + before: function(type) { + var args, $e; + args = [].slice.call(arguments, 1); + $e = this._trigger("before" + type, args); + return $e.isDefaultPrevented(); + }, + trigger: function(type) { + var deprecatedType; + this._trigger(type, [].slice.call(arguments, 1)); + if (deprecatedType = deprecationMap[type]) { + this._trigger(deprecatedType, [].slice.call(arguments, 1)); + } + } + }); + return EventBus; + }(); + var EventEmitter = function() { + "use strict"; + var splitter = /\s+/, nextTick = getNextTick(); + return { + onSync: onSync, + onAsync: onAsync, + off: off, + trigger: trigger + }; + function on(method, types, cb, context) { + var type; + if (!cb) { + return this; + } + types = types.split(splitter); + cb = context ? bindContext(cb, context) : cb; + this._callbacks = this._callbacks || {}; + while (type = types.shift()) { + this._callbacks[type] = this._callbacks[type] || { + sync: [], + async: [] + }; + this._callbacks[type][method].push(cb); + } + return this; + } + function onAsync(types, cb, context) { + return on.call(this, "async", types, cb, context); + } + function onSync(types, cb, context) { + return on.call(this, "sync", types, cb, context); + } + function off(types) { + var type; + if (!this._callbacks) { + return this; + } + types = types.split(splitter); + while (type = types.shift()) { + delete this._callbacks[type]; + } + return this; + } + function trigger(types) { + var type, callbacks, args, syncFlush, asyncFlush; + if (!this._callbacks) { + return this; + } + types = types.split(splitter); + args = [].slice.call(arguments, 1); + while ((type = types.shift()) && (callbacks = this._callbacks[type])) { + syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args)); + asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args)); + syncFlush() && nextTick(asyncFlush); + } + return this; + } + function getFlush(callbacks, context, args) { + return flush; + function flush() { + var cancelled; + for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) { + cancelled = callbacks[i].apply(context, args) === false; + } + return !cancelled; + } + } + function getNextTick() { + var nextTickFn; + if (window.setImmediate) { + nextTickFn = function nextTickSetImmediate(fn) { + setImmediate(function() { + fn(); + }); + }; + } else { + nextTickFn = function nextTickSetTimeout(fn) { + setTimeout(function() { + fn(); + }, 0); + }; + } + return nextTickFn; + } + function bindContext(fn, context) { + return fn.bind ? fn.bind(context) : function() { + fn.apply(context, [].slice.call(arguments, 0)); + }; + } + }(); + var highlight = function(doc) { + "use strict"; + var defaults = { + node: null, + pattern: null, + tagName: "strong", + className: null, + wordsOnly: false, + caseSensitive: false, + diacriticInsensitive: false + }; + var accented = { + A: "[AaªÀ-Åà-åĀ-ąǍǎȀ-ȃȦȧᴬᵃḀḁẚẠ-ảₐ℀℁℻⒜Ⓐⓐ㍱-㍴㎀-㎄㎈㎉㎩-㎯㏂㏊㏟㏿Aa]", + B: "[BbᴮᵇḂ-ḇℬ⒝Ⓑⓑ㍴㎅-㎇㏃㏈㏔㏝Bb]", + C: "[CcÇçĆ-čᶜ℀ℂ℃℅℆ℭⅭⅽ⒞Ⓒⓒ㍶㎈㎉㎝㎠㎤㏄-㏇Cc]", + D: "[DdĎďDŽ-džDZ-dzᴰᵈḊ-ḓⅅⅆⅮⅾ⒟Ⓓⓓ㋏㍲㍷-㍹㎗㎭-㎯㏅㏈Dd]", + E: "[EeÈ-Ëè-ëĒ-ěȄ-ȇȨȩᴱᵉḘ-ḛẸ-ẽₑ℡ℯℰⅇ⒠Ⓔⓔ㉐㋍㋎Ee]", + F: "[FfᶠḞḟ℉ℱ℻⒡Ⓕⓕ㎊-㎌㎙ff-fflFf]", + G: "[GgĜ-ģǦǧǴǵᴳᵍḠḡℊ⒢Ⓖⓖ㋌㋍㎇㎍-㎏㎓㎬㏆㏉㏒㏿Gg]", + H: "[HhĤĥȞȟʰᴴḢ-ḫẖℋ-ℎ⒣Ⓗⓗ㋌㍱㎐-㎔㏊㏋㏗Hh]", + I: "[IiÌ-Ïì-ïĨ-İIJijǏǐȈ-ȋᴵᵢḬḭỈ-ịⁱℐℑℹⅈⅠ-ⅣⅥ-ⅨⅪⅫⅰ-ⅳⅵ-ⅸⅺⅻ⒤Ⓘⓘ㍺㏌㏕fiffiIi]", + J: "[JjIJ-ĵLJ-njǰʲᴶⅉ⒥ⒿⓙⱼJj]", + K: "[KkĶķǨǩᴷᵏḰ-ḵK⒦Ⓚⓚ㎄㎅㎉㎏㎑㎘㎞㎢㎦㎪㎸㎾㏀㏆㏍-㏏Kk]", + L: "[LlĹ-ŀLJ-ljˡᴸḶḷḺ-ḽℒℓ℡Ⅼⅼ⒧Ⓛⓛ㋏㎈㎉㏐-㏓㏕㏖㏿flfflLl]", + M: "[MmᴹᵐḾ-ṃ℠™ℳⅯⅿ⒨Ⓜⓜ㍷-㍹㎃㎆㎎㎒㎖㎙-㎨㎫㎳㎷㎹㎽㎿㏁㏂㏎㏐㏔-㏖㏘㏙㏞㏟Mm]", + N: "[NnÑñŃ-ʼnNJ-njǸǹᴺṄ-ṋⁿℕ№⒩Ⓝⓝ㎁㎋㎚㎱㎵㎻㏌㏑Nn]", + O: "[OoºÒ-Öò-öŌ-őƠơǑǒǪǫȌ-ȏȮȯᴼᵒỌ-ỏₒ℅№ℴ⒪Ⓞⓞ㍵㏇㏒㏖Oo]", + P: "[PpᴾᵖṔ-ṗℙ⒫Ⓟⓟ㉐㍱㍶㎀㎊㎩-㎬㎰㎴㎺㏋㏗-㏚Pp]", + Q: "[Qqℚ⒬Ⓠⓠ㏃Qq]", + R: "[RrŔ-řȐ-ȓʳᴿᵣṘ-ṛṞṟ₨ℛ-ℝ⒭Ⓡⓡ㋍㍴㎭-㎯㏚㏛Rr]", + S: "[SsŚ-šſȘșˢṠ-ṣ₨℁℠⒮Ⓢⓢ㎧㎨㎮-㎳㏛㏜stSs]", + T: "[TtŢ-ťȚțᵀᵗṪ-ṱẗ℡™⒯Ⓣⓣ㉐㋏㎔㏏ſtstTt]", + U: "[UuÙ-Üù-üŨ-ųƯưǓǔȔ-ȗᵁᵘᵤṲ-ṷỤ-ủ℆⒰Ⓤⓤ㍳㍺Uu]", + V: "[VvᵛᵥṼ-ṿⅣ-Ⅷⅳ-ⅷ⒱Ⓥⓥⱽ㋎㍵㎴-㎹㏜㏞Vv]", + W: "[WwŴŵʷᵂẀ-ẉẘ⒲Ⓦⓦ㎺-㎿㏝Ww]", + X: "[XxˣẊ-ẍₓ℻Ⅸ-Ⅻⅸ-ⅻ⒳Ⓧⓧ㏓Xx]", + Y: "[YyÝýÿŶ-ŸȲȳʸẎẏẙỲ-ỹ⒴Ⓨⓨ㏉Yy]", + Z: "[ZzŹ-žDZ-dzᶻẐ-ẕℤℨ⒵Ⓩⓩ㎐-㎔Zz]" + }; + return function hightlight(o) { + var regex; + o = _.mixin({}, defaults, o); + if (!o.node || !o.pattern) { + return; + } + o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ]; + regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly, o.diacriticInsensitive); + traverse(o.node, hightlightTextNode); + function hightlightTextNode(textNode) { + var match, patternNode, wrapperNode; + if (match = regex.exec(textNode.data)) { + wrapperNode = doc.createElement(o.tagName); + o.className && (wrapperNode.className = o.className); + patternNode = textNode.splitText(match.index); + patternNode.splitText(match[0].length); + wrapperNode.appendChild(patternNode.cloneNode(true)); + textNode.parentNode.replaceChild(wrapperNode, patternNode); + } + return !!match; + } + function traverse(el, hightlightTextNode) { + var childNode, TEXT_NODE_TYPE = 3; + for (var i = 0; i < el.childNodes.length; i++) { + childNode = el.childNodes[i]; + if (childNode.nodeType === TEXT_NODE_TYPE) { + i += hightlightTextNode(childNode) ? 1 : 0; + } else { + traverse(childNode, hightlightTextNode); + } + } + } + }; + function accent_replacer(chr) { + return accented[chr.toUpperCase()] || chr; + } + function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensitive) { + var escapedPatterns = [], regexStr; + for (var i = 0, len = patterns.length; i < len; i++) { + var escapedWord = _.escapeRegExChars(patterns[i]); + if (diacriticInsensitive) { + escapedWord = escapedWord.replace(/\S/g, accent_replacer); + } + escapedPatterns.push(escapedWord); + } + regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")"; + return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i"); + } + }(window.document); + var Input = function() { + "use strict"; + var specialKeyCodeMap; + specialKeyCodeMap = { + 9: "tab", + 27: "esc", + 37: "left", + 39: "right", + 13: "enter", + 38: "up", + 40: "down" + }; + function Input(o, www) { + o = o || {}; + if (!o.input) { + $.error("input is missing"); + } + www.mixin(this); + this.$hint = $(o.hint); + this.$input = $(o.input); + this.$input.attr({ + "aria-activedescendant": "", + "aria-owns": this.$input.attr("id") + "_listbox", + role: "combobox", + "aria-readonly": "true", + "aria-autocomplete": "list" + }); + $(www.menu).attr("id", this.$input.attr("id") + "_listbox"); + this.query = this.$input.val(); + this.queryWhenFocused = this.hasFocus() ? this.query : null; + this.$overflowHelper = buildOverflowHelper(this.$input); + this._checkLanguageDirection(); + if (this.$hint.length === 0) { + this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop; + } + this.onSync("cursorchange", this._updateDescendent); + } + Input.normalizeQuery = function(str) { + return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " "); + }; + _.mixin(Input.prototype, EventEmitter, { + _onBlur: function onBlur() { + this.resetInputValue(); + this.trigger("blurred"); + }, + _onFocus: function onFocus() { + this.queryWhenFocused = this.query; + this.trigger("focused"); + }, + _onKeydown: function onKeydown($e) { + var keyName = specialKeyCodeMap[$e.which || $e.keyCode]; + this._managePreventDefault(keyName, $e); + if (keyName && this._shouldTrigger(keyName, $e)) { + this.trigger(keyName + "Keyed", $e); + } + }, + _onInput: function onInput() { + this._setQuery(this.getInputValue()); + this.clearHintIfInvalid(); + this._checkLanguageDirection(); + }, + _managePreventDefault: function managePreventDefault(keyName, $e) { + var preventDefault; + switch (keyName) { + case "up": + case "down": + preventDefault = !withModifier($e); + break; + + default: + preventDefault = false; + } + preventDefault && $e.preventDefault(); + }, + _shouldTrigger: function shouldTrigger(keyName, $e) { + var trigger; + switch (keyName) { + case "tab": + trigger = !withModifier($e); + break; + + default: + trigger = true; + } + return trigger; + }, + _checkLanguageDirection: function checkLanguageDirection() { + var dir = (this.$input.css("direction") || "ltr").toLowerCase(); + if (this.dir !== dir) { + this.dir = dir; + this.$hint.attr("dir", dir); + this.trigger("langDirChanged", dir); + } + }, + _setQuery: function setQuery(val, silent) { + var areEquivalent, hasDifferentWhitespace; + areEquivalent = areQueriesEquivalent(val, this.query); + hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false; + this.query = val; + if (!silent && !areEquivalent) { + this.trigger("queryChanged", this.query); + } else if (!silent && hasDifferentWhitespace) { + this.trigger("whitespaceChanged", this.query); + } + }, + _updateDescendent: function updateDescendent(event, id) { + this.$input.attr("aria-activedescendant", id); + }, + bind: function() { + var that = this, onBlur, onFocus, onKeydown, onInput; + onBlur = _.bind(this._onBlur, this); + onFocus = _.bind(this._onFocus, this); + onKeydown = _.bind(this._onKeydown, this); + onInput = _.bind(this._onInput, this); + this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown); + if (!_.isMsie() || _.isMsie() > 9) { + this.$input.on("input.tt", onInput); + } else { + this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) { + if (specialKeyCodeMap[$e.which || $e.keyCode]) { + return; + } + _.defer(_.bind(that._onInput, that, $e)); + }); + } + return this; + }, + focus: function focus() { + this.$input.focus(); + }, + blur: function blur() { + this.$input.blur(); + }, + getLangDir: function getLangDir() { + return this.dir; + }, + getQuery: function getQuery() { + return this.query || ""; + }, + setQuery: function setQuery(val, silent) { + this.setInputValue(val); + this._setQuery(val, silent); + }, + hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() { + return this.query !== this.queryWhenFocused; + }, + getInputValue: function getInputValue() { + return this.$input.val(); + }, + setInputValue: function setInputValue(value) { + this.$input.val(value); + this.clearHintIfInvalid(); + this._checkLanguageDirection(); + }, + resetInputValue: function resetInputValue() { + this.setInputValue(this.query); + }, + getHint: function getHint() { + return this.$hint.val(); + }, + setHint: function setHint(value) { + this.$hint.val(value); + }, + clearHint: function clearHint() { + this.setHint(""); + }, + clearHintIfInvalid: function clearHintIfInvalid() { + var val, hint, valIsPrefixOfHint, isValid; + val = this.getInputValue(); + hint = this.getHint(); + valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0; + isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow(); + !isValid && this.clearHint(); + }, + hasFocus: function hasFocus() { + return this.$input.is(":focus"); + }, + hasOverflow: function hasOverflow() { + var constraint = this.$input.width() - 2; + this.$overflowHelper.text(this.getInputValue()); + return this.$overflowHelper.width() >= constraint; + }, + isCursorAtEnd: function() { + var valueLength, selectionStart, range; + valueLength = this.$input.val().length; + selectionStart = this.$input[0].selectionStart; + if (_.isNumber(selectionStart)) { + return selectionStart === valueLength; + } else if (document.selection) { + range = document.selection.createRange(); + range.moveStart("character", -valueLength); + return valueLength === range.text.length; + } + return true; + }, + destroy: function destroy() { + this.$hint.off(".tt"); + this.$input.off(".tt"); + this.$overflowHelper.remove(); + this.$hint = this.$input = this.$overflowHelper = $("
                      "); + } + }); + return Input; + function buildOverflowHelper($input) { + return $('').css({ + position: "absolute", + visibility: "hidden", + whiteSpace: "pre", + fontFamily: $input.css("font-family"), + fontSize: $input.css("font-size"), + fontStyle: $input.css("font-style"), + fontVariant: $input.css("font-variant"), + fontWeight: $input.css("font-weight"), + wordSpacing: $input.css("word-spacing"), + letterSpacing: $input.css("letter-spacing"), + textIndent: $input.css("text-indent"), + textRendering: $input.css("text-rendering"), + textTransform: $input.css("text-transform") + }).insertAfter($input); + } + function areQueriesEquivalent(a, b) { + return Input.normalizeQuery(a) === Input.normalizeQuery(b); + } + function withModifier($e) { + return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey; + } + }(); + var Dataset = function() { + "use strict"; + var keys, nameGenerator; + keys = { + dataset: "tt-selectable-dataset", + val: "tt-selectable-display", + obj: "tt-selectable-object" + }; + nameGenerator = _.getIdGenerator(); + function Dataset(o, www) { + o = o || {}; + o.templates = o.templates || {}; + o.templates.notFound = o.templates.notFound || o.templates.empty; + if (!o.source) { + $.error("missing source"); + } + if (!o.node) { + $.error("missing node"); + } + if (o.name && !isValidName(o.name)) { + $.error("invalid dataset name: " + o.name); + } + www.mixin(this); + this.highlight = !!o.highlight; + this.name = _.toStr(o.name || nameGenerator()); + this.limit = o.limit || 5; + this.displayFn = getDisplayFn(o.display || o.displayKey); + this.templates = getTemplates(o.templates, this.displayFn); + this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source; + this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async; + this._resetLastSuggestion(); + this.$el = $(o.node).attr("role", "presentation").addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name); + } + Dataset.extractData = function extractData(el) { + var $el = $(el); + if ($el.data(keys.obj)) { + return { + dataset: $el.data(keys.dataset) || "", + val: $el.data(keys.val) || "", + obj: $el.data(keys.obj) || null + }; + } + return null; + }; + _.mixin(Dataset.prototype, EventEmitter, { + _overwrite: function overwrite(query, suggestions) { + suggestions = suggestions || []; + if (suggestions.length) { + this._renderSuggestions(query, suggestions); + } else if (this.async && this.templates.pending) { + this._renderPending(query); + } else if (!this.async && this.templates.notFound) { + this._renderNotFound(query); + } else { + this._empty(); + } + this.trigger("rendered", suggestions, false, this.name); + }, + _append: function append(query, suggestions) { + suggestions = suggestions || []; + if (suggestions.length && this.$lastSuggestion.length) { + this._appendSuggestions(query, suggestions); + } else if (suggestions.length) { + this._renderSuggestions(query, suggestions); + } else if (!this.$lastSuggestion.length && this.templates.notFound) { + this._renderNotFound(query); + } + this.trigger("rendered", suggestions, true, this.name); + }, + _renderSuggestions: function renderSuggestions(query, suggestions) { + var $fragment; + $fragment = this._getSuggestionsFragment(query, suggestions); + this.$lastSuggestion = $fragment.children().last(); + this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions)); + }, + _appendSuggestions: function appendSuggestions(query, suggestions) { + var $fragment, $lastSuggestion; + $fragment = this._getSuggestionsFragment(query, suggestions); + $lastSuggestion = $fragment.children().last(); + this.$lastSuggestion.after($fragment); + this.$lastSuggestion = $lastSuggestion; + }, + _renderPending: function renderPending(query) { + var template = this.templates.pending; + this._resetLastSuggestion(); + template && this.$el.html(template({ + query: query, + dataset: this.name + })); + }, + _renderNotFound: function renderNotFound(query) { + var template = this.templates.notFound; + this._resetLastSuggestion(); + template && this.$el.html(template({ + query: query, + dataset: this.name + })); + }, + _empty: function empty() { + this.$el.empty(); + this._resetLastSuggestion(); + }, + _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) { + var that = this, fragment; + fragment = document.createDocumentFragment(); + _.each(suggestions, function getSuggestionNode(suggestion) { + var $el, context; + context = that._injectQuery(query, suggestion); + $el = $(that.templates.suggestion(context)).data(keys.dataset, that.name).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable); + fragment.appendChild($el[0]); + }); + this.highlight && highlight({ + className: this.classes.highlight, + node: fragment, + pattern: query + }); + return $(fragment); + }, + _getFooter: function getFooter(query, suggestions) { + return this.templates.footer ? this.templates.footer({ + query: query, + suggestions: suggestions, + dataset: this.name + }) : null; + }, + _getHeader: function getHeader(query, suggestions) { + return this.templates.header ? this.templates.header({ + query: query, + suggestions: suggestions, + dataset: this.name + }) : null; + }, + _resetLastSuggestion: function resetLastSuggestion() { + this.$lastSuggestion = $(); + }, + _injectQuery: function injectQuery(query, obj) { + return _.isObject(obj) ? _.mixin({ + _query: query + }, obj) : obj; + }, + update: function update(query) { + var that = this, canceled = false, syncCalled = false, rendered = 0; + this.cancel(); + this.cancel = function cancel() { + canceled = true; + that.cancel = $.noop; + that.async && that.trigger("asyncCanceled", query, that.name); + }; + this.source(query, sync, async); + !syncCalled && sync([]); + function sync(suggestions) { + if (syncCalled) { + return; + } + syncCalled = true; + suggestions = (suggestions || []).slice(0, that.limit); + rendered = suggestions.length; + that._overwrite(query, suggestions); + if (rendered < that.limit && that.async) { + that.trigger("asyncRequested", query, that.name); + } + } + function async(suggestions) { + suggestions = suggestions || []; + if (!canceled && rendered < that.limit) { + that.cancel = $.noop; + var idx = Math.abs(rendered - that.limit); + rendered += idx; + that._append(query, suggestions.slice(0, idx)); + that.async && that.trigger("asyncReceived", query, that.name); + } + } + }, + cancel: $.noop, + clear: function clear() { + this._empty(); + this.cancel(); + this.trigger("cleared"); + }, + isEmpty: function isEmpty() { + return this.$el.is(":empty"); + }, + destroy: function destroy() { + this.$el = $("
                      "); + } + }); + return Dataset; + function getDisplayFn(display) { + display = display || _.stringify; + return _.isFunction(display) ? display : displayFn; + function displayFn(obj) { + return obj[display]; + } + } + function getTemplates(templates, displayFn) { + return { + notFound: templates.notFound && _.templatify(templates.notFound), + pending: templates.pending && _.templatify(templates.pending), + header: templates.header && _.templatify(templates.header), + footer: templates.footer && _.templatify(templates.footer), + suggestion: templates.suggestion || suggestionTemplate + }; + function suggestionTemplate(context) { + return $('
                      ').attr("id", _.guid()).text(displayFn(context)); + } + } + function isValidName(str) { + return /^[_a-zA-Z0-9-]+$/.test(str); + } + }(); + var Menu = function() { + "use strict"; + function Menu(o, www) { + var that = this; + o = o || {}; + if (!o.node) { + $.error("node is required"); + } + www.mixin(this); + this.$node = $(o.node); + this.query = null; + this.datasets = _.map(o.datasets, initializeDataset); + function initializeDataset(oDataset) { + var node = that.$node.find(oDataset.node).first(); + oDataset.node = node.length ? node : $("
                      ").appendTo(that.$node); + return new Dataset(oDataset, www); + } + } + _.mixin(Menu.prototype, EventEmitter, { + _onSelectableClick: function onSelectableClick($e) { + this.trigger("selectableClicked", $($e.currentTarget)); + }, + _onRendered: function onRendered(type, dataset, suggestions, async) { + this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); + this.trigger("datasetRendered", dataset, suggestions, async); + }, + _onCleared: function onCleared() { + this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); + this.trigger("datasetCleared"); + }, + _propagate: function propagate() { + this.trigger.apply(this, arguments); + }, + _allDatasetsEmpty: function allDatasetsEmpty() { + return _.every(this.datasets, _.bind(function isDatasetEmpty(dataset) { + var isEmpty = dataset.isEmpty(); + this.$node.attr("aria-expanded", !isEmpty); + return isEmpty; + }, this)); + }, + _getSelectables: function getSelectables() { + return this.$node.find(this.selectors.selectable); + }, + _removeCursor: function _removeCursor() { + var $selectable = this.getActiveSelectable(); + $selectable && $selectable.removeClass(this.classes.cursor); + }, + _ensureVisible: function ensureVisible($el) { + var elTop, elBottom, nodeScrollTop, nodeHeight; + elTop = $el.position().top; + elBottom = elTop + $el.outerHeight(true); + nodeScrollTop = this.$node.scrollTop(); + nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10); + if (elTop < 0) { + this.$node.scrollTop(nodeScrollTop + elTop); + } else if (nodeHeight < elBottom) { + this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight)); + } + }, + bind: function() { + var that = this, onSelectableClick; + onSelectableClick = _.bind(this._onSelectableClick, this); + this.$node.on("click.tt", this.selectors.selectable, onSelectableClick); + this.$node.on("mouseover", this.selectors.selectable, function() { + that.setCursor($(this)); + }); + this.$node.on("mouseleave", function() { + that._removeCursor(); + }); + _.each(this.datasets, function(dataset) { + dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that); + }); + return this; + }, + isOpen: function isOpen() { + return this.$node.hasClass(this.classes.open); + }, + open: function open() { + this.$node.scrollTop(0); + this.$node.addClass(this.classes.open); + }, + close: function close() { + this.$node.attr("aria-expanded", false); + this.$node.removeClass(this.classes.open); + this._removeCursor(); + }, + setLanguageDirection: function setLanguageDirection(dir) { + this.$node.attr("dir", dir); + }, + selectableRelativeToCursor: function selectableRelativeToCursor(delta) { + var $selectables, $oldCursor, oldIndex, newIndex; + $oldCursor = this.getActiveSelectable(); + $selectables = this._getSelectables(); + oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1; + newIndex = oldIndex + delta; + newIndex = (newIndex + 1) % ($selectables.length + 1) - 1; + newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex; + return newIndex === -1 ? null : $selectables.eq(newIndex); + }, + setCursor: function setCursor($selectable) { + this._removeCursor(); + if ($selectable = $selectable && $selectable.first()) { + $selectable.addClass(this.classes.cursor); + this._ensureVisible($selectable); + } + }, + getSelectableData: function getSelectableData($el) { + return $el && $el.length ? Dataset.extractData($el) : null; + }, + getActiveSelectable: function getActiveSelectable() { + var $selectable = this._getSelectables().filter(this.selectors.cursor).first(); + return $selectable.length ? $selectable : null; + }, + getTopSelectable: function getTopSelectable() { + var $selectable = this._getSelectables().first(); + return $selectable.length ? $selectable : null; + }, + update: function update(query) { + var isValidUpdate = query !== this.query; + if (isValidUpdate) { + this.query = query; + _.each(this.datasets, updateDataset); + } + return isValidUpdate; + function updateDataset(dataset) { + dataset.update(query); + } + }, + empty: function empty() { + _.each(this.datasets, clearDataset); + this.query = null; + this.$node.addClass(this.classes.empty); + function clearDataset(dataset) { + dataset.clear(); + } + }, + destroy: function destroy() { + this.$node.off(".tt"); + this.$node = $("
                      "); + _.each(this.datasets, destroyDataset); + function destroyDataset(dataset) { + dataset.destroy(); + } + } + }); + return Menu; + }(); + var Status = function() { + "use strict"; + function Status(options) { + this.$el = $("", { + role: "status", + "aria-live": "polite" + }).css({ + position: "absolute", + padding: "0", + border: "0", + height: "1px", + width: "1px", + "margin-bottom": "-1px", + "margin-right": "-1px", + overflow: "hidden", + clip: "rect(0 0 0 0)", + "white-space": "nowrap" + }); + options.$input.after(this.$el); + _.each(options.menu.datasets, _.bind(function(dataset) { + if (dataset.onSync) { + dataset.onSync("rendered", _.bind(this.update, this)); + dataset.onSync("cleared", _.bind(this.cleared, this)); + } + }, this)); + } + _.mixin(Status.prototype, { + update: function update(event, suggestions) { + var length = suggestions.length; + var words; + if (length === 1) { + words = { + result: "result", + is: "is" + }; + } else { + words = { + result: "results", + is: "are" + }; + } + this.$el.text(length + " " + words.result + " " + words.is + " available, use up and down arrow keys to navigate."); + }, + cleared: function() { + this.$el.text(""); + } + }); + return Status; + }(); + var DefaultMenu = function() { + "use strict"; + var s = Menu.prototype; + function DefaultMenu() { + Menu.apply(this, [].slice.call(arguments, 0)); + } + _.mixin(DefaultMenu.prototype, Menu.prototype, { + open: function open() { + !this._allDatasetsEmpty() && this._show(); + return s.open.apply(this, [].slice.call(arguments, 0)); + }, + close: function close() { + this._hide(); + return s.close.apply(this, [].slice.call(arguments, 0)); + }, + _onRendered: function onRendered() { + if (this._allDatasetsEmpty()) { + this._hide(); + } else { + this.isOpen() && this._show(); + } + return s._onRendered.apply(this, [].slice.call(arguments, 0)); + }, + _onCleared: function onCleared() { + if (this._allDatasetsEmpty()) { + this._hide(); + } else { + this.isOpen() && this._show(); + } + return s._onCleared.apply(this, [].slice.call(arguments, 0)); + }, + setLanguageDirection: function setLanguageDirection(dir) { + this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl); + return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0)); + }, + _hide: function hide() { + this.$node.hide(); + }, + _show: function show() { + this.$node.css("display", "block"); + } + }); + return DefaultMenu; + }(); + var Typeahead = function() { + "use strict"; + function Typeahead(o, www) { + var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged; + o = o || {}; + if (!o.input) { + $.error("missing input"); + } + if (!o.menu) { + $.error("missing menu"); + } + if (!o.eventBus) { + $.error("missing event bus"); + } + www.mixin(this); + this.eventBus = o.eventBus; + this.minLength = _.isNumber(o.minLength) ? o.minLength : 1; + this.input = o.input; + this.menu = o.menu; + this.enabled = true; + this.autoselect = !!o.autoselect; + this.active = false; + this.input.hasFocus() && this.activate(); + this.dir = this.input.getLangDir(); + this._hacks(); + this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this); + onFocused = c(this, "activate", "open", "_onFocused"); + onBlurred = c(this, "deactivate", "_onBlurred"); + onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed"); + onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed"); + onEscKeyed = c(this, "isActive", "_onEscKeyed"); + onUpKeyed = c(this, "isActive", "open", "_onUpKeyed"); + onDownKeyed = c(this, "isActive", "open", "_onDownKeyed"); + onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed"); + onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed"); + onQueryChanged = c(this, "_openIfActive", "_onQueryChanged"); + onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged"); + this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this); + } + _.mixin(Typeahead.prototype, { + _hacks: function hacks() { + var $input, $menu; + $input = this.input.$input || $("
                      "); + $menu = this.menu.$node || $("
                      "); + $input.on("blur.tt", function($e) { + var active, isActive, hasActive; + active = document.activeElement; + isActive = $menu.is(active); + hasActive = $menu.has(active).length > 0; + if (_.isMsie() && (isActive || hasActive)) { + $e.preventDefault(); + $e.stopImmediatePropagation(); + _.defer(function() { + $input.focus(); + }); + } + }); + $menu.on("mousedown.tt", function($e) { + $e.preventDefault(); + }); + }, + _onSelectableClicked: function onSelectableClicked(type, $el) { + this.select($el); + }, + _onDatasetCleared: function onDatasetCleared() { + this._updateHint(); + }, + _onDatasetRendered: function onDatasetRendered(type, suggestions, async, dataset) { + this._updateHint(); + if (this.autoselect) { + var cursorClass = this.selectors.cursor.substr(1); + this.menu.$node.find(this.selectors.suggestion).first().addClass(cursorClass); + } + this.eventBus.trigger("render", suggestions, async, dataset); + }, + _onAsyncRequested: function onAsyncRequested(type, dataset, query) { + this.eventBus.trigger("asyncrequest", query, dataset); + }, + _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) { + this.eventBus.trigger("asynccancel", query, dataset); + }, + _onAsyncReceived: function onAsyncReceived(type, dataset, query) { + this.eventBus.trigger("asyncreceive", query, dataset); + }, + _onFocused: function onFocused() { + this._minLengthMet() && this.menu.update(this.input.getQuery()); + }, + _onBlurred: function onBlurred() { + if (this.input.hasQueryChangedSinceLastFocus()) { + this.eventBus.trigger("change", this.input.getQuery()); + } + }, + _onEnterKeyed: function onEnterKeyed(type, $e) { + var $selectable; + if ($selectable = this.menu.getActiveSelectable()) { + if (this.select($selectable)) { + $e.preventDefault(); + $e.stopPropagation(); + } + } else if (this.autoselect) { + if (this.select(this.menu.getTopSelectable())) { + $e.preventDefault(); + $e.stopPropagation(); + } + } + }, + _onTabKeyed: function onTabKeyed(type, $e) { + var $selectable; + if ($selectable = this.menu.getActiveSelectable()) { + this.select($selectable) && $e.preventDefault(); + } else if ($selectable = this.menu.getTopSelectable()) { + this.autocomplete($selectable) && $e.preventDefault(); + } + }, + _onEscKeyed: function onEscKeyed() { + this.close(); + }, + _onUpKeyed: function onUpKeyed() { + this.moveCursor(-1); + }, + _onDownKeyed: function onDownKeyed() { + this.moveCursor(+1); + }, + _onLeftKeyed: function onLeftKeyed() { + if (this.dir === "rtl" && this.input.isCursorAtEnd()) { + this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); + } + }, + _onRightKeyed: function onRightKeyed() { + if (this.dir === "ltr" && this.input.isCursorAtEnd()) { + this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); + } + }, + _onQueryChanged: function onQueryChanged(e, query) { + this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty(); + }, + _onWhitespaceChanged: function onWhitespaceChanged() { + this._updateHint(); + }, + _onLangDirChanged: function onLangDirChanged(e, dir) { + if (this.dir !== dir) { + this.dir = dir; + this.menu.setLanguageDirection(dir); + } + }, + _openIfActive: function openIfActive() { + this.isActive() && this.open(); + }, + _minLengthMet: function minLengthMet(query) { + query = _.isString(query) ? query : this.input.getQuery() || ""; + return query.length >= this.minLength; + }, + _updateHint: function updateHint() { + var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match; + $selectable = this.menu.getTopSelectable(); + data = this.menu.getSelectableData($selectable); + val = this.input.getInputValue(); + if (data && !_.isBlankString(val) && !this.input.hasOverflow()) { + query = Input.normalizeQuery(val); + escapedQuery = _.escapeRegExChars(query); + frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i"); + match = frontMatchRegEx.exec(data.val); + match && this.input.setHint(val + match[1]); + } else { + this.input.clearHint(); + } + }, + isEnabled: function isEnabled() { + return this.enabled; + }, + enable: function enable() { + this.enabled = true; + }, + disable: function disable() { + this.enabled = false; + }, + isActive: function isActive() { + return this.active; + }, + activate: function activate() { + if (this.isActive()) { + return true; + } else if (!this.isEnabled() || this.eventBus.before("active")) { + return false; + } else { + this.active = true; + this.eventBus.trigger("active"); + return true; + } + }, + deactivate: function deactivate() { + if (!this.isActive()) { + return true; + } else if (this.eventBus.before("idle")) { + return false; + } else { + this.active = false; + this.close(); + this.eventBus.trigger("idle"); + return true; + } + }, + isOpen: function isOpen() { + return this.menu.isOpen(); + }, + open: function open() { + if (!this.isOpen() && !this.eventBus.before("open")) { + this.menu.open(); + this._updateHint(); + this.eventBus.trigger("open"); + } + return this.isOpen(); + }, + close: function close() { + if (this.isOpen() && !this.eventBus.before("close")) { + this.menu.close(); + this.input.clearHint(); + this.input.resetInputValue(); + this.eventBus.trigger("close"); + } + return !this.isOpen(); + }, + setVal: function setVal(val) { + this.input.setQuery(_.toStr(val)); + }, + getVal: function getVal() { + return this.input.getQuery(); + }, + select: function select($selectable) { + var data = this.menu.getSelectableData($selectable); + if (data && !this.eventBus.before("select", data.obj, data.dataset)) { + this.input.setQuery(data.val, true); + this.eventBus.trigger("select", data.obj, data.dataset); + this.close(); + return true; + } + return false; + }, + autocomplete: function autocomplete($selectable) { + var query, data, isValid; + query = this.input.getQuery(); + data = this.menu.getSelectableData($selectable); + isValid = data && query !== data.val; + if (isValid && !this.eventBus.before("autocomplete", data.obj, data.dataset)) { + this.input.setQuery(data.val); + this.eventBus.trigger("autocomplete", data.obj, data.dataset); + return true; + } + return false; + }, + moveCursor: function moveCursor(delta) { + var query, $candidate, data, suggestion, datasetName, cancelMove, id; + query = this.input.getQuery(); + $candidate = this.menu.selectableRelativeToCursor(delta); + data = this.menu.getSelectableData($candidate); + suggestion = data ? data.obj : null; + datasetName = data ? data.dataset : null; + id = $candidate ? $candidate.attr("id") : null; + this.input.trigger("cursorchange", id); + cancelMove = this._minLengthMet() && this.menu.update(query); + if (!cancelMove && !this.eventBus.before("cursorchange", suggestion, datasetName)) { + this.menu.setCursor($candidate); + if (data) { + this.input.setInputValue(data.val); + } else { + this.input.resetInputValue(); + this._updateHint(); + } + this.eventBus.trigger("cursorchange", suggestion, datasetName); + return true; + } + return false; + }, + destroy: function destroy() { + this.input.destroy(); + this.menu.destroy(); + } + }); + return Typeahead; + function c(ctx) { + var methods = [].slice.call(arguments, 1); + return function() { + var args = [].slice.call(arguments); + _.each(methods, function(method) { + return ctx[method].apply(ctx, args); + }); + }; + } + }(); + (function() { + "use strict"; + var old, keys, methods; + old = $.fn.typeahead; + keys = { + www: "tt-www", + attrs: "tt-attrs", + typeahead: "tt-typeahead" + }; + methods = { + initialize: function initialize(o, datasets) { + var www; + datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1); + o = o || {}; + www = WWW(o.classNames); + return this.each(attach); + function attach() { + var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, status, typeahead, MenuConstructor; + _.each(datasets, function(d) { + d.highlight = !!o.highlight; + }); + $input = $(this); + $wrapper = $(www.html.wrapper); + $hint = $elOrNull(o.hint); + $menu = $elOrNull(o.menu); + defaultHint = o.hint !== false && !$hint; + defaultMenu = o.menu !== false && !$menu; + defaultHint && ($hint = buildHintFromInput($input, www)); + defaultMenu && ($menu = $(www.html.menu).css(www.css.menu)); + $hint && $hint.val(""); + $input = prepInput($input, www); + if (defaultHint || defaultMenu) { + $wrapper.css(www.css.wrapper); + $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint); + $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null); + } + MenuConstructor = defaultMenu ? DefaultMenu : Menu; + eventBus = new EventBus({ + el: $input + }); + input = new Input({ + hint: $hint, + input: $input + }, www); + menu = new MenuConstructor({ + node: $menu, + datasets: datasets + }, www); + status = new Status({ + $input: $input, + menu: menu + }); + typeahead = new Typeahead({ + input: input, + menu: menu, + eventBus: eventBus, + minLength: o.minLength, + autoselect: o.autoselect + }, www); + $input.data(keys.www, www); + $input.data(keys.typeahead, typeahead); + } + }, + isEnabled: function isEnabled() { + var enabled; + ttEach(this.first(), function(t) { + enabled = t.isEnabled(); + }); + return enabled; + }, + enable: function enable() { + ttEach(this, function(t) { + t.enable(); + }); + return this; + }, + disable: function disable() { + ttEach(this, function(t) { + t.disable(); + }); + return this; + }, + isActive: function isActive() { + var active; + ttEach(this.first(), function(t) { + active = t.isActive(); + }); + return active; + }, + activate: function activate() { + ttEach(this, function(t) { + t.activate(); + }); + return this; + }, + deactivate: function deactivate() { + ttEach(this, function(t) { + t.deactivate(); + }); + return this; + }, + isOpen: function isOpen() { + var open; + ttEach(this.first(), function(t) { + open = t.isOpen(); + }); + return open; + }, + open: function open() { + ttEach(this, function(t) { + t.open(); + }); + return this; + }, + close: function close() { + ttEach(this, function(t) { + t.close(); + }); + return this; + }, + select: function select(el) { + var success = false, $el = $(el); + ttEach(this.first(), function(t) { + success = t.select($el); + }); + return success; + }, + autocomplete: function autocomplete(el) { + var success = false, $el = $(el); + ttEach(this.first(), function(t) { + success = t.autocomplete($el); + }); + return success; + }, + moveCursor: function moveCursoe(delta) { + var success = false; + ttEach(this.first(), function(t) { + success = t.moveCursor(delta); + }); + return success; + }, + val: function val(newVal) { + var query; + if (!arguments.length) { + ttEach(this.first(), function(t) { + query = t.getVal(); + }); + return query; + } else { + ttEach(this, function(t) { + t.setVal(_.toStr(newVal)); + }); + return this; + } + }, + destroy: function destroy() { + ttEach(this, function(typeahead, $input) { + revert($input); + typeahead.destroy(); + }); + return this; + } + }; + $.fn.typeahead = function(method) { + if (methods[method]) { + return methods[method].apply(this, [].slice.call(arguments, 1)); + } else { + return methods.initialize.apply(this, arguments); + } + }; + $.fn.typeahead.noConflict = function noConflict() { + $.fn.typeahead = old; + return this; + }; + function ttEach($els, fn) { + $els.each(function() { + var $input = $(this), typeahead; + (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input); + }); + } + function buildHintFromInput($input, www) { + return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop({ + readonly: true, + required: false + }).removeAttr("id name placeholder").removeClass("required").attr({ + spellcheck: "false", + tabindex: -1 + }); + } + function prepInput($input, www) { + $input.data(keys.attrs, { + dir: $input.attr("dir"), + autocomplete: $input.attr("autocomplete"), + spellcheck: $input.attr("spellcheck"), + style: $input.attr("style") + }); + $input.addClass(www.classes.input).attr({ + spellcheck: false + }); + try { + !$input.attr("dir") && $input.attr("dir", "auto"); + } catch (e) {} + return $input; + } + function getBackgroundStyles($el) { + return { + backgroundAttachment: $el.css("background-attachment"), + backgroundClip: $el.css("background-clip"), + backgroundColor: $el.css("background-color"), + backgroundImage: $el.css("background-image"), + backgroundOrigin: $el.css("background-origin"), + backgroundPosition: $el.css("background-position"), + backgroundRepeat: $el.css("background-repeat"), + backgroundSize: $el.css("background-size") + }; + } + function revert($input) { + var www, $wrapper; + www = $input.data(keys.www); + $wrapper = $input.parent().filter(www.selectors.wrapper); + _.each($input.data(keys.attrs), function(val, key) { + _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val); + }); + $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input); + if ($wrapper.length) { + $input.detach().insertAfter($wrapper); + $wrapper.remove(); + } + } + function $elOrNull(obj) { + var isValid, $el; + isValid = _.isJQuery(obj) || _.isElement(obj); + $el = isValid ? $(obj).first() : []; + return $el.length ? $el : null; + } + })(); +}); \ No newline at end of file diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/micro-example.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/micro-example.html new file mode 100644 index 0000000..3ae38ac --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/micro-example.html @@ -0,0 +1,262 @@ + + + + Micro Example Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Micro Example

                      +
                      /** AppDelegate.swift */
                      +import UIKit
                      +import InAppPurchaseLib
                      +
                      +@UIApplicationMain
                      +class AppDelegate: UIResponder, UIApplicationDelegate {
                      +  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      +    // Initialize the library
                      +    InAppPurchase.initialize(
                      +      iapProducts: [
                      +        IAPProduct(productIdentifier: "my_product", productType: .nonConsumable)
                      +      ],
                      +      validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678"
                      +    )
                      +    return true
                      +  }
                      +
                      +  func applicationWillTerminate(_ application: UIApplication) {
                      +    // Clean
                      +    InAppPurchase.stop()
                      +  }
                      +}
                      +
                      +
                      /** ViewController.swift */
                      +import UIKit
                      +import StoreKit
                      +import InAppPurchaseLib
                      +
                      +class ViewController: UIViewController {
                      +  private var loaderView = LoaderView()
                      +  @IBOutlet weak var statusLabel: UILabel!
                      +  @IBOutlet weak var productTitleLabel: UILabel!
                      +  @IBOutlet weak var productDescriptionLabel: UILabel!
                      +  @IBOutlet weak var purchaseButton: UIButton!
                      +  @IBOutlet weak var restorePurchasesButton: UIButton!
                      +
                      +  override func viewDidLoad() {
                      +    super.viewDidLoad()
                      +    // Add action for purchases and restore butons.
                      +    purchaseButton.addTarget(self, action: #selector(self.purchase), for: .touchUpInside)
                      +    restorePurchasesButton.addTarget(self, action: #selector(self.restorePurchases), for: .touchUpInside)
                      +  }
                      +
                      +  override func viewWillAppear(_ animated: Bool) {
                      +    self.refreshView()
                      +    InAppPurchase.refresh(callback: { _ in
                      +      self.refreshView()
                      +    })
                      +  }
                      +
                      +  func refreshView() {
                      +    guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product") else {
                      +      self.productTitleLabel.text = "Product unavailable"
                      +      return
                      +    }
                      +    // Display product information.
                      +    productTitleLabel.text = product.localizedTitle
                      +    productDescriptionLabel.text = product.localizedDescription
                      +    purchaseButton.setTitle(product.localizedPrice, for: .normal)
                      +
                      +    // Disable the button if the product has already been purchased.
                      +    if InAppPurchase.hasActivePurchase(for: "my_product") {
                      +      statusLabel.text = "OWNED"
                      +      purchaseButton.isPointerInteractionEnabled = false
                      +    }
                      +  }
                      +
                      +  @IBAction func purchase(_ sender: Any) {
                      +    self.loaderView.show()
                      +    InAppPurchase.purchase(
                      +      productIdentifier: "my_product",
                      +      callback: { result in
                      +        self.loaderView.hide()
                      +      })
                      +  }
                      +
                      +  @IBAction func restorePurchases(_ sender: Any) {
                      +    self.loaderView.show()
                      +    InAppPurchase.restorePurchases(callback: { result in
                      +      self.loaderView.hide()
                      +    })
                      +  }
                      +}
                      +
                      + +
                      +
                      + + +
                      +
                      + + +
                      + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/purchasing.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/purchasing.html new file mode 100644 index 0000000..7a6996c --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/purchasing.html @@ -0,0 +1,245 @@ + + + + Purchasing Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Purchasing

                      + +

                      The purchase process is generally a little bit more involving than most people would expect. Why is it not just: purchase → on success unlock the feature?

                      + +

                      Several reasons:

                      + +
                        +
                      • In-app purchases can be initiated outside the app
                      • +
                      • In-app purchases can be deferred, pending parental approval
                      • +
                      • Apple wants to be sure you delivered the product before charging the user
                      • +
                      + +

                      That is why the process looks like so:

                      + +
                        +
                      • being ready to handle purchase events from app startup
                      • +
                      • finalizing transactions when product delivery is complete
                      • +
                      • sending purchase request, for which successful doesn’t always mean complete
                      • +
                      +

                      Initiating a purchase

                      + +

                      To initiate a purchase, use the InAppPurchase.purchase() function. It takes the productIdentifier and a callback function, called when the purchase has been processed.

                      + +

                      Important: Do not process the purchase here, we’ll handle that later!

                      + +

                      From this callback, you can for example unlock the UI by hiding your loading indicator and display a message to the user.

                      + +

                      Example:

                      +
                      self.loaderView.show()
                      +InAppPurchase.purchase(
                      +  productIdentifier: "my_product_id",
                      +  callback: { _ in
                      +    self.loaderView.hide()
                      +})
                      +
                      + +

                      This simple example locks the UI with a loader when the purchase is in progress. We’ll see later how the purchase has to be processed by your applicaiton.

                      + +

                      The callback also gives more information about the outcome of the purchase, you might want to use it to update your UI as well. Note that some events are useful for analytics. So here’s a more complete example.

                      +
                      self.loaderView.show()
                      +InAppPurchase.purchase(
                      +  productIdentifier: "my_product_id",
                      +  callback: { result in
                      +    self.loaderView.hide()
                      +
                      +    switch result.state {
                      +    case .purchased:
                      +      // Product successfully purchased
                      +      // Reminder: Do not process the purchase here, only update your UI.
                      +      //           that's why we do not send data to analytics.
                      +      openThankYouScreen()
                      +    case .failed:
                      +      // Purchase failed
                      +      // - Human formated reason can be found in result.localizedDescription
                      +      // - More details in either result.skError or result.iapError
                      +      showError(result.localizedDescription)
                      +    case .deferred:
                      +      // The purchase is deferred, waiting for the parent's approval
                      +      openWaitingParentApprovalScreen()
                      +    case .cancelled:
                      +      // The user canceled the request, generally only useful for analytics.
                      +  }
                      +})
                      +
                      + +

                      If the purchase fails, result will contain either .skError, a SKError from StoreKit, or .iapError, an IAPError.

                      + +

                      Tip: After a successful purchase, you should see a new transaction in Fovea’s dashboard.

                      + +
                      +
                      + + +
                      +
                      + + +
                      + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/refreshing.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/refreshing.html new file mode 100644 index 0000000..56e094a --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/refreshing.html @@ -0,0 +1,189 @@ + + + + Refreshing Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Refreshing

                      + +

                      Data might change or not be yet available when your “product” view is presented. In order to properly handle those cases, you should refresh your view after refreshing in-app products metadata. You want to be sure you’re displaying up-to-date information.

                      + +

                      To achieve this, call InAppPurchase.refresh() when your view is presented.

                      +
                      override func viewWillAppear(_ animated: Bool) {
                      +  self.refreshView()
                      +  InAppPurchase.refresh(callback: { _ in
                      +      self.refreshView()
                      +  })
                      +}
                      +
                      + +
                      +
                      + + +
                      +
                      + + +
                      + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/restoring-purchases.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/restoring-purchases.html new file mode 100644 index 0000000..ab44024 --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/restoring-purchases.html @@ -0,0 +1,201 @@ + + + + Restoring purchases Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Restoring purchases

                      + +

                      Except if you only sell consumable products, Apple requires that you provide a “Restore Purchases” button to your users. In general, it is found in your application settings.

                      + +

                      Call this method when this button is pressed.

                      +
                      @IBAction func restorePurchases(_ sender: Any) {
                      +  self.loaderView.show()
                      +  InAppPurchase.restorePurchases(callback: { result in
                      +      self.loaderView.hide()
                      +      switch result.state {
                      +      case .succeeded:
                      +          if result.addedPurchases > 0 {
                      +              print("Restore purchases successful.")
                      +          } else {
                      +              print("No purchase to restore.")
                      +          }
                      +      case .failed:
                      +          print("Restore purchases failed.")
                      +      }
                      +  })
                      +}
                      +
                      + +

                      The callback method is called once the operation is complete. You can use it to unlock the UI, by hiding your loader for example, and display the adapted message to the user.

                      + +
                      +
                      + + +
                      +
                      + + +
                      + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/search.json b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/search.json new file mode 100644 index 0000000..ca5875b --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/search.json @@ -0,0 +1 @@ +{"Protocols/IAPErrorProtocol.html#/s:16InAppPurchaseLib16IAPErrorProtocolP4codeAA0E4CodeOvp":{"name":"code","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorProtocol"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO21libraryNotInitializedyA2CmF":{"name":"libraryNotInitialized","abstract":"

                      You must call the initialize fuction before using the library.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO23bundleIdentifierInvalidyA2CmF":{"name":"bundleIdentifierInvalid","abstract":"

                      The Bundle Identifier is invalid.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO19validatorUrlInvalidyA2CmF":{"name":"validatorUrlInvalid","abstract":"

                      The Validator URL String is invalid.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO20refreshReceiptFailedyA2CmF":{"name":"refreshReceiptFailed","abstract":"

                      Failed to refresh the App Store receipt.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO21validateReceiptFailedyA2CmF":{"name":"validateReceiptFailed","abstract":"

                      Failed to validate the App Store receipt with Fovea.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO17readReceiptFailedyA2CmF":{"name":"readReceiptFailed","abstract":"

                      Failed to read the receipt validation.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO21refreshProductsFailedyA2CmF":{"name":"refreshProductsFailed","abstract":"

                      Failed to refresh products from the App Store.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO15productNotFoundyA2CmF":{"name":"productNotFound","abstract":"

                      The product was not found on the App Store and cannot be purchased.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO010cannotMakeC0yA2CmF":{"name":"cannotMakePurchase","abstract":"

                      The user is not allowed to authorize payments.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO17alreadyPurchasingyA2CmF":{"name":"alreadyPurchasing","abstract":"

                      A purchase is already in progress.

                      ","parent_name":"IAPErrorCode"},"Structs/IAPError.html#/s:16InAppPurchaseLib8IAPErrorV4codeAA0E4CodeOvp":{"name":"code","abstract":"

                      The error code.

                      ","parent_name":"IAPError"},"Structs/IAPError.html#/s:16InAppPurchaseLib8IAPErrorV20localizedDescriptionSSvp":{"name":"localizedDescription","abstract":"

                      The error description.

                      ","parent_name":"IAPError"},"Enums/IAPRefreshResultState.html#/s:16InAppPurchaseLib21IAPRefreshResultStateO9succeededyA2CmF":{"name":"succeeded","abstract":"

                      Refresh was successful.

                      ","parent_name":"IAPRefreshResultState"},"Enums/IAPRefreshResultState.html#/s:16InAppPurchaseLib21IAPRefreshResultStateO6failedyA2CmF":{"name":"failed","abstract":"

                      Refresh failed.

                      ","parent_name":"IAPRefreshResultState"},"Enums/IAPRefreshResultState.html#/s:16InAppPurchaseLib21IAPRefreshResultStateO7skippedyA2CmF":{"name":"skipped","abstract":"

                      Refresh has been skipped because it is not necessary.

                      ","parent_name":"IAPRefreshResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO9purchasedyA2CmF":{"name":"purchased","abstract":"

                      The purchase was successful.

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO6failedyA2CmF":{"name":"failed","abstract":"

                      Puchase failed.

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO9cancelledyA2CmF":{"name":"cancelled","abstract":"

                      The purchase was cancelled by the user.

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO8deferredyA2CmF":{"name":"deferred","abstract":"

                      The purchase is deferred.

                      ","parent_name":"IAPPurchaseResultState"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV5stateAA0eF5StateOvp":{"name":"state","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV8iapErrorAA8IAPErrorVSgvp":{"name":"iapError","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV14addedPurchasesSivp":{"name":"addedPurchases","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV16updatedPurchasesSivp":{"name":"updatedPurchases","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV5stateAA0eF5StateOvp":{"name":"state","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV8iapErrorAA8IAPErrorVSgvp":{"name":"iapError","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV7skErrorSC11SKErrorCodeLeVSgvp":{"name":"skError","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV20localizedDescriptionSSSgvp":{"name":"localizedDescription","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Enums/IAPPeriodFormat.html#/s:16InAppPurchaseLib15IAPPeriodFormatO5shortyA2CmF":{"name":"short","abstract":"

                      Undocumented

                      ","parent_name":"IAPPeriodFormat"},"Enums/IAPPeriodFormat.html#/s:16InAppPurchaseLib15IAPPeriodFormatO4longyA2CmF":{"name":"long","abstract":"

                      Undocumented

                      ","parent_name":"IAPPeriodFormat"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE21localizedPeriodFormatAC09IAPPeriodH0OvpZ":{"name":"localizedPeriodFormat","abstract":"

                      Undocumented

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE28hasIntroductoryPriceEligibleSbyF":{"name":"hasIntroductoryPriceEligible()","abstract":"

                      Checks if the product has an introductory price the user is eligible to.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE14localizedPriceSSvp":{"name":"localizedPrice","abstract":"

                      Returns a localized string with the cost of the product in the local currency.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE27localizedSubscriptionPeriodSSSgvp":{"name":"localizedSubscriptionPeriod","abstract":"

                      Returns a localized string with the period of the subscription product.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE26localizedIntroductoryPriceSSSgvp":{"name":"localizedIntroductoryPrice","abstract":"

                      Returns a localized string with the introductory price if available, in the local currency.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE27localizedIntroductoryPeriodSSSgvp":{"name":"localizedIntroductoryPeriod","abstract":"

                      Returns a localized string with the introductory price period of the subscription product.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE29localizedIntroductoryDurationSSSgvp":{"name":"localizedIntroductoryDuration","abstract":"

                      Returns a localized string with the duration of the introductory price.

                      ","parent_name":"SKProduct"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO10consumableyA2CmF":{"name":"consumable","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO13nonConsumableyA2CmF":{"name":"nonConsumable","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO23nonRenewingSubscriptionyA2CmF":{"name":"nonRenewingSubscription","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO25autoRenewableSubscriptionyA2CmF":{"name":"autoRenewableSubscription","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Structs/IAPProduct.html#/s:16InAppPurchaseLib10IAPProductV17productIdentifierSSvp":{"name":"productIdentifier","abstract":"

                      The identifier of the product.

                      ","parent_name":"IAPProduct"},"Structs/IAPProduct.html#/s:16InAppPurchaseLib10IAPProductV11productTypeAA0eG0Ovp":{"name":"productType","abstract":"

                      The type of the product.

                      ","parent_name":"IAPProduct"},"Structs/IAPProduct.html#/s:16InAppPurchaseLib10IAPProductV17productIdentifier0F4TypeACSS_AA0eH0Otcfc":{"name":"init(productIdentifier:productType:)","abstract":"

                      Initializes an IAPProduct with its identifier and type.

                      ","parent_name":"IAPProduct"},"Protocols/IAPPurchaseDelegate.html#/s:16InAppPurchaseLib19IAPPurchaseDelegateP16productPurchased0G10IdentifierySS_tF":{"name":"productPurchased(productIdentifier:)","abstract":"

                      Called when a product is newly purchased, updated or restored.

                      ","parent_name":"IAPPurchaseDelegate"},"Classes/DefaultPurchaseDelegate.html#/s:16InAppPurchaseLib07DefaultC8DelegateCACycfc":{"name":"init()","abstract":"

                      Undocumented

                      ","parent_name":"DefaultPurchaseDelegate"},"Classes/DefaultPurchaseDelegate.html#/s:16InAppPurchaseLib07DefaultC8DelegateC16productPurchased0G10IdentifierySS_tF":{"name":"productPurchased(productIdentifier:)","abstract":"

                      Finish the product transactions when a product is newly purchased, updated or restored.

                      ","parent_name":"DefaultPurchaseDelegate"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP11iapProductsSayAA10IAPProductVGvpZ":{"name":"iapProducts","abstract":"

                      The array of IAPProduct.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP18validatorUrlStringSSSgvpZ":{"name":"validatorUrlString","abstract":"

                      The validator url retrieved from Fovea.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP03iapC8DelegateAA011IAPPurchaseF0_pSgvpZ":{"name":"iapPurchaseDelegate","abstract":"

                      The instance of class that adopts the IAPPurchaseDelegate protocol.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP19applicationUsernameSSSgvpZ":{"name":"applicationUsername","abstract":"

                      The user name, if your app implements user login.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP10initialize11iapProducts18validatorUrlString0fC8Delegate19applicationUsernameySayAA10IAPProductVG_SSAA011IAPPurchaseK0_pSSSgtFZ":{"name":"initialize(iapProducts:validatorUrlString:iapPurchaseDelegate:applicationUsername:)","abstract":"

                      Start observing the payment queue, as soon as possible, and refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP4stopyyFZ":{"name":"stop()","abstract":"

                      Stop observing the payment queue, when the application will terminate, for proper cleanup.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP7refresh8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"refresh(callback:)","abstract":"

                      Refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP11getProductsSaySo9SKProductCGyFZ":{"name":"getProducts()","abstract":"

                      Gets all products retrieved from the App Store

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP12getProductBy10identifierSo9SKProductCSgSS_tFZ":{"name":"getProductBy(identifier:)","abstract":"

                      Gets the product by its identifier from the list of products retrieved from the App Store.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP15canMakePaymentsSbyFZ":{"name":"canMakePayments()","abstract":"

                      Checks if the user is allowed to authorize payments.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP8purchase17productIdentifier8quantity8callbackySS_SiyAA17IAPPurchaseResultVctFZ":{"name":"purchase(productIdentifier:quantity:callback:)","abstract":"

                      Request a Payment from the App Store.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP16restorePurchases8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"restorePurchases(callback:)","abstract":"

                      Restore purchased products.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP18finishTransactions3forySS_tFZ":{"name":"finishTransactions(for:)","abstract":"

                      Finish all transactions for the product.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP22hasDeferredTransaction3forSbSS_tFZ":{"name":"hasDeferredTransaction(for:)","abstract":"

                      Checks if the last transaction state for a given product was deferred.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP19hasAlreadyPurchasedSbyFZ":{"name":"hasAlreadyPurchased()","abstract":"

                      Checks if the user has already purchased at least one product.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP09hasActiveC03forSbSS_tFZ":{"name":"hasActivePurchase(for:)","abstract":"

                      Checks if the user currently own (or is subscribed to) a given product (nonConsumable or autoRenewableSubscription).

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP21hasActiveSubscriptionSbyFZ":{"name":"hasActiveSubscription()","abstract":"

                      Checks if the user has an active auto renewable subscription regardless of the product identifier.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP03getC4Date3for10Foundation0F0VSgSS_tFZ":{"name":"getPurchaseDate(for:)","abstract":"

                      Returns the latest purchased date for a given product.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP13getExpiryDate3for10Foundation0G0VSgSS_tFZ":{"name":"getExpiryDate(for:)","abstract":"

                      Returns the expiry date for a subcription. May be past or future.

                      ","parent_name":"InAppPurchaseLib"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C11iapProductsSayAA10IAPProductVGvpZ":{"name":"iapProducts","abstract":"

                      The array of IAPProduct.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C18validatorUrlStringSSSgvpZ":{"name":"validatorUrlString","abstract":"

                      The validator url retrieved from Fovea.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C03iapC8DelegateAA011IAPPurchaseF0_pSgvpZ":{"name":"iapPurchaseDelegate","abstract":"

                      The instance of class that adopts the IAPPurchaseDelegate protocol.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C19applicationUsernameSSSgvpZ":{"name":"applicationUsername","abstract":"

                      The user name, if your app implements user login.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C10initialize11iapProducts18validatorUrlString0fC8Delegate19applicationUsernameySayAA10IAPProductVG_SSAA011IAPPurchaseK0_pSSSgtFZ":{"name":"initialize(iapProducts:validatorUrlString:iapPurchaseDelegate:applicationUsername:)","abstract":"

                      Start observing the payment queue, as soon as possible, and refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C4stopyyFZ":{"name":"stop()","abstract":"

                      Stop observing the payment queue, when the application will terminate, for proper cleanup.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C7refresh8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"refresh(callback:)","abstract":"

                      Refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C11getProductsSaySo9SKProductCGyFZ":{"name":"getProducts()","abstract":"

                      Gets all products retrieved from the App Store

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C12getProductBy10identifierSo9SKProductCSgSS_tFZ":{"name":"getProductBy(identifier:)","abstract":"

                      Gets the product by its identifier from the list of products retrieved from the App Store.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C15canMakePaymentsSbyFZ":{"name":"canMakePayments()","abstract":"

                      Checks if the user is allowed to authorize payments.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C8purchase17productIdentifier8quantity8callbackySS_SiyAA17IAPPurchaseResultVctFZ":{"name":"purchase(productIdentifier:quantity:callback:)","abstract":"

                      Request a Payment from the App Store.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C16restorePurchases8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"restorePurchases(callback:)","abstract":"

                      Restore purchased products.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C18finishTransactions3forySS_tFZ":{"name":"finishTransactions(for:)","abstract":"

                      Finish all transactions for the product.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C22hasDeferredTransaction3forSbSS_tFZ":{"name":"hasDeferredTransaction(for:)","abstract":"

                      Checks if the last transaction state for a given product was deferred.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C19hasAlreadyPurchasedSbyFZ":{"name":"hasAlreadyPurchased()","abstract":"

                      Checks if the user has already purchased at least one product.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C09hasActiveC03forSbSS_tFZ":{"name":"hasActivePurchase(for:)","abstract":"

                      Checks if the user currently own (or is subscribed to) a given product (nonConsumable or autoRenewableSubscription).

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C21hasActiveSubscriptionSbyFZ":{"name":"hasActiveSubscription()","abstract":"

                      Checks if the user has an active auto renewable subscription regardless of the product identifier.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C03getC4Date3for10Foundation0F0VSgSS_tFZ":{"name":"getPurchaseDate(for:)","abstract":"

                      Returns the latest purchased date for a given product.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C13getExpiryDate3for10Foundation0G0VSgSS_tFZ":{"name":"getExpiryDate(for:)","abstract":"

                      Returns the expiry date for a subcription. May be past or future.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html":{"name":"InAppPurchase"},"Protocols/InAppPurchaseLib.html":{"name":"InAppPurchaseLib","abstract":"

                      The protocol that InAppPurchase adopts.

                      "},"Classes/DefaultPurchaseDelegate.html":{"name":"DefaultPurchaseDelegate","abstract":"

                      The default implementation of IAPPurchaseDelegate if no other is provided. It is enough if you only have non-consumable and/or auto-renewable subscription products.

                      "},"Protocols/IAPPurchaseDelegate.html":{"name":"IAPPurchaseDelegate","abstract":"

                      The protocol that you must adopt if you have consumable and/or non-renewing subscription products.

                      "},"Structs/IAPProduct.html":{"name":"IAPProduct","abstract":"

                      Undocumented

                      "},"Enums/IAPProductType.html":{"name":"IAPProductType","abstract":"

                      Undocumented

                      "},"Extensions/SKProduct.html":{"name":"SKProduct"},"Enums/IAPPeriodFormat.html":{"name":"IAPPeriodFormat","abstract":"

                      Undocumented

                      "},"API%20documentation.html#/s:16InAppPurchaseLib19IAPPurchaseCallbacka":{"name":"IAPPurchaseCallback","abstract":"

                      Undocumented

                      "},"API%20documentation.html#/s:16InAppPurchaseLib18IAPRefreshCallbacka":{"name":"IAPRefreshCallback","abstract":"

                      Undocumented

                      "},"Structs/IAPPurchaseResult.html":{"name":"IAPPurchaseResult","abstract":"

                      The result returned in the purchase() callback.

                      "},"Structs/IAPRefreshResult.html":{"name":"IAPRefreshResult","abstract":"

                      The result returned in the refresh() or restorePurchases() callback.

                      "},"Enums/IAPPurchaseResultState.html":{"name":"IAPPurchaseResultState","abstract":"

                      The list of the different states of the IAPPurchaseResult.

                      "},"Enums/IAPRefreshResultState.html":{"name":"IAPRefreshResultState","abstract":"

                      The list of the different states of the IAPRefreshResult.

                      "},"Structs/IAPError.html":{"name":"IAPError","abstract":"

                      When calling refresh(), purchase() or restorePurchases(), the callback can return an IAPError if the state is failed.

                      "},"Enums/IAPErrorCode.html":{"name":"IAPErrorCode","abstract":"

                      The list of error codes that can be returned by the library.

                      "},"Protocols/IAPErrorProtocol.html":{"name":"IAPErrorProtocol","abstract":"

                      Undocumented

                      "},"initialization.html":{"name":"Initialization"},"displaying-products.html":{"name":"Displaying products"},"displaying-subscriptions.html":{"name":"Displaying subscriptions"},"refreshing.html":{"name":"Refreshing"},"purchasing.html":{"name":"Purchasing"},"handling-purchases.html":{"name":"Handling purchases"},"restoring-purchases.html":{"name":"Restoring purchases"},"displaying-products-with-purchases.html":{"name":"Displaying products with purchases"},"errors.html":{"name":"Errors"},"analytics.html":{"name":"Analytics"},"server-integration.html":{"name":"Server integration"},"installation.html":{"name":"Installation"},"micro-example.html":{"name":"Micro Example"},"Getting%20Started.html":{"name":"Getting Started"},"Usage.html":{"name":"Usage"},"API%20documentation.html":{"name":"API documentation"}} \ No newline at end of file diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/server-integration.html b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/server-integration.html new file mode 100644 index 0000000..ab51e7d --- /dev/null +++ b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/server-integration.html @@ -0,0 +1,198 @@ + + + + Server integration Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Server integration

                      + +

                      In more advanced use cases, you have a server component. Users are logged in and you’ll like to unlock the content for this user on your server. The safest approach is to setup a Webhook on Fovea. You’ll receive notifications from Fovea that transaction have been processed and/or subscriptions updated.

                      + +

                      The information sent from Fovea has been verified from Apple’s server, which makes it way more trustable than information sent from your app itself.

                      + +

                      To take advantage of this, you have to inform the library of your application username. This applicationUsername can be provided as a parameter of the InAppPurchase.initialize method and updated later by changing the associated property.

                      + +

                      Example:

                      +
                      InAppPurchase.initialize(
                      +  iapProducts: [...],
                      +  validatorUrlString: "..."),
                      +  applicationUsername: UserSession.getUserId())
                      +
                      +// later ...
                      +InAppPurchase.applicationUsername = UserSession.getUserId()
                      +
                      + +

                      If a user account is mandatory in your app, you will want to delay calls to InAppPurchase.initialize() to when your user’s session is ready.

                      + +

                      Do not hesitate to contact Fovea for help.

                      + +
                      +
                      + + +
                      +
                      + + +
                      + diff --git a/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/docSet.dsidx b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/docSet.dsidx new file mode 100644 index 0000000..f1134e8 Binary files /dev/null and b/docs/docsets/InAppPurchaseLib.docset/Contents/Resources/docSet.dsidx differ diff --git a/docs/docsets/InAppPurchaseLib.tgz b/docs/docsets/InAppPurchaseLib.tgz new file mode 100644 index 0000000..4181fb9 Binary files /dev/null and b/docs/docsets/InAppPurchaseLib.tgz differ diff --git a/docs/errors.html b/docs/errors.html new file mode 100644 index 0000000..33fa397 --- /dev/null +++ b/docs/errors.html @@ -0,0 +1,206 @@ + + + + Errors Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Errors

                      + +

                      When calling refresh(), purchase() or restorePurchases(), the callback can return an IAPError if the state is failed. +Here is the list of IAPErrorCode you can receive:

                      + +
                        +
                      • Errors returned by refresh(), purchase() or restorePurchases()

                        + +
                          +
                        • libraryNotInitialized - You must call the initialize fuction before using the library.
                        • +
                        • bundleIdentifierInvalid - The Bundle Identifier is invalid.
                        • +
                        • validatorUrlInvalid - The Validator URL String is invalid.
                        • +
                        • refreshReceiptFailed - Failed to refresh the App Store receipt.
                        • +
                        • validateReceiptFailed - Failed to validate the App Store receipt with Fovea.
                        • +
                        • readReceiptFailed - Failed to read the receipt validation.
                        • +
                      • +
                      • Errors returned by refresh()

                        + +
                          +
                        • refreshProductsFailed - Failed to refresh products from the App Store.
                        • +
                      • +
                      • Errors returned by purchase()

                        + +
                          +
                        • productNotFound - The product was not found on the App Store and cannot be purchased.
                        • +
                        • cannotMakePurchase - The user is not allowed to authorize payments.
                        • +
                        • alreadyPurchasing - A purchase is already in progress.
                        • +
                      • +
                      + +
                      +
                      + + +
                      +
                      + + +
                      + diff --git a/docs/handling-purchases.html b/docs/handling-purchases.html new file mode 100644 index 0000000..00379e9 --- /dev/null +++ b/docs/handling-purchases.html @@ -0,0 +1,271 @@ + + + + Handling purchases Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Handling purchases

                      + +

                      Finally, the magic happened: a user purchased one of your products! Let’s see how we handle the different types of products.

                      + + + +

                      +

                      Non-Consumables

                      + +

                      Wherever your app needs to know if a non-consumable product has been purchased, use InAppPurchase.hasActivePurchase(for: +productIdentifier). This will return true if the user currently owns the product.

                      + +

                      Note: The last known state for the user’s purchases is stored as UserDefaults. As such, their status is always available to your app, even when offline.

                      + +

                      If you have a server that needs to know about the purchase. You should rely on Fovea’s webhook instead of doing anything in here. We will see that later in the Server integration section.

                      + +

                      +

                      Auto-Renewable Subscriptions

                      + +

                      As with non-consumables, you will use InAppPurchase.hasActivePurchase(for: productIdentifier) to check if the user is an active subscriber to a given product.

                      + +

                      You might also like to call refresh regularly, for example when entering your main view. When appropriate, the library will refresh the receipt to detect subscription renewals or expiry.

                      + +

                      As we’ve seend in the Refreshing section:

                      +
                      override func viewWillAppear(_ animated: Bool) {
                      +  self.refreshView()
                      +  InAppPurchase.refresh(callback: { _ in
                      +      self.refreshView()
                      +  })
                      +}
                      +
                      + +

                      Note: Don’t be reluctant to call refresh() often. Internally, the library ensures heavy operation are only performed if necessary: for example when a subscription just expired. So in 99% of cases this call will result in no-operations.

                      + +

                      +

                      Consumables

                      + +

                      If the purchased products in a consumable, your app is responsible for delivering the purchase then acknowlege that you’ve done so. Delivering generally consists in increasing a counter for some sort of virtual currency.

                      + +

                      Your app can be notified of a purchase at any time. So the library asks you to provide an IAPPurchaseDelegate from initialization.

                      + +

                      In InAppPurchase.initialize(), we can pass an IAPPurchaseDelegate instance. This object implements the productPurchased(productIdentifier:) function, which is called whenever a purchase is approved.

                      + +

                      Here’s a example implementation:

                      +
                      class AppDelegate: UIResponder, UIApplicationDelegate, IAPPurchaseDelegate {
                      +  ...
                      +  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      +    InAppPurchase.initialize(
                      +      iapProducts: [...],
                      +      iapPurchaseDelegate: self, // ADDED: iapPurchaseDelegate
                      +      validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678")
                      +  }
                      +
                      +  // IAPPurchaseDelegate implementation
                      +  func productPurchased(productIdentifier: String) {
                      +    // TODO
                      +  }
                      +}
                      +
                      + +

                      It’s also important to know that when a purchase is approved, money isn’t yet to reach your bank account. You have to acknowledge delivery of the (virtual) item to finalize the transaction. That is why we have to call InAppPurchase.finishTransactions(for: productIdentifier) as soon as we delivered the product.

                      + +

                      Example

                      + +

                      Let’s define a class that adopts the IAPPurchaseDelegate protocol, it can very well be your application delegate.

                      +
                      func productPurchased(productIdentifier: String) {
                      +  switch productIdenfier {
                      +  case "10_silver":
                      +    addSilver(10)
                      +  case "100_silver":
                      +    addSilver(100)
                      +  }
                      +  InAppPurchase.finishTransactions(for: productIdentifier)
                      +  Analytics.trackEvent("purchase succeeded", productIdentifier)
                      +}
                      +
                      + +

                      Here, we implement our own unlocking logic and call InAppPurchase.finishTransactions() afterward (assuming addSilver is synchronous).

                      + +

                      Note: productPurchased is called when a purchase has been confirmed by Fovea’s receipt validator. If you have a server, he probably already has been notified of this purchase using the webhook.

                      + +

                      Reminder: Keep in mind that purchase notifications might occur even if you never called the InAppPurchase.purchase() function: purchases can be made from another device or the AppStore, they can be approved by parents when the app isn’t running, purchase flows can be interupted, etc. The pattern above ensures your app is always ready to handle purchase events.

                      + +

                      +

                      Non-Renewing Subscriptions

                      + +

                      For non-renewing subscriptions, delivering consists in increasing the amount of time a user can access a given feature. Apple doesn’t manage the length and expiry of non-renewing subscriptions: you have to do this yourself, as for consumables.

                      + +

                      Basically, everything is identical to consumables.

                      + +
                      +
                      + + +
                      +
                      + + +
                      + diff --git a/docs/jazzy/img/carat.png b/docs/img/carat.png similarity index 100% rename from docs/jazzy/img/carat.png rename to docs/img/carat.png diff --git a/docs/jazzy/img/dash.png b/docs/img/dash.png similarity index 100% rename from docs/jazzy/img/dash.png rename to docs/img/dash.png diff --git a/docs/jazzy/img/gh.png b/docs/img/gh.png similarity index 100% rename from docs/jazzy/img/gh.png rename to docs/img/gh.png diff --git a/docs/img/spinner.gif b/docs/img/spinner.gif new file mode 100644 index 0000000..e3038d0 Binary files /dev/null and b/docs/img/spinner.gif differ diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..268c210 --- /dev/null +++ b/docs/index.html @@ -0,0 +1,325 @@ + + + + InAppPurchaseLib Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      + +

                      + +
                      +

                      An easy-to-use Swift library for In-App Purchases, using Fovea.Billing for receipts validation.

                      +
                      +

                      Features

                      + +
                        +
                      • ✅ Purchase a product
                      • +
                      • ✅ Restore purchased products
                      • +
                      • ✅ Verify transactions with the App Store on Fovea.Billing server
                      • +
                      • ✅ Handle and notify payment transaction states
                      • +
                      • ✅ Retreive products information from the App Store
                      • +
                      • ✅ Support all product types (consumable, non-consumable, auto-renewable subscription, non-renewing subscription)
                      • +
                      • ✅ Status of purchases available when offline
                      • +
                      • ✅ Server integration with a Webhook
                      • +
                      +

                      Getting Started

                      + +

                      If you haven’t already, I highly recommend your read the Overview and Preparing section of Apple’s In-App Purchase official documentation.

                      +

                      Installation

                      + +
                        +
                      • Select your project in Xcode
                      • +
                      • Go to the section Swift Package
                      • +
                      • Click on (+) Add Package Dependency
                      • +
                      • Copy the Git URL: https://github.com/iridescent-dev/iap-swift-lib.git
                      • +
                      • Click on Next > Next
                      • +
                      • Make sure your project is selected in Add to target
                      • +
                      • Click on Finish
                      • +
                      + +

                      Note: You have to import InAppPurchaseLib wherever you use the library.

                      +

                      Micro Example

                      +
                      /** AppDelegate.swift */
                      +import UIKit
                      +import InAppPurchaseLib
                      +
                      +@UIApplicationMain
                      +class AppDelegate: UIResponder, UIApplicationDelegate {
                      +  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      +    // Initialize the library
                      +    InAppPurchase.initialize(
                      +      iapProducts: [
                      +        IAPProduct(productIdentifier: "my_product", productType: .nonConsumable)
                      +      ],
                      +      validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678"
                      +    )
                      +    return true
                      +  }
                      +
                      +  func applicationWillTerminate(_ application: UIApplication) {
                      +    // clean
                      +    InAppPurchase.stop()
                      +  }
                      +}
                      +
                      +
                      /** ViewController.swift */
                      +import UIKit
                      +import StoreKit
                      +import InAppPurchaseLib
                      +
                      +class ViewController: UIViewController {
                      +  private var loaderView = LoaderView()
                      +  @IBOutlet weak var statusLabel: UILabel!
                      +  @IBOutlet weak var productTitleLabel: UILabel!
                      +  @IBOutlet weak var productDescriptionLabel: UILabel!
                      +  @IBOutlet weak var purchaseButton: UIButton!
                      +  @IBOutlet weak var restorePurchasesButton: UIButton!
                      +
                      +  override func viewDidLoad() {
                      +    super.viewDidLoad()
                      +    // Add action for purchases and restore butons.
                      +    purchaseButton.addTarget(self, action: #selector(self.purchase), for: .touchUpInside)
                      +    restorePurchasesButton.addTarget(self, action: #selector(self.restorePurchases), for: .touchUpInside)
                      +  }
                      +
                      +  override func viewWillAppear(_ animated: Bool) {
                      +    self.refreshView()
                      +    InAppPurchase.refresh(callback: { _ in
                      +      self.refreshView()
                      +    })
                      +  }
                      +
                      +  func refreshView() {
                      +    guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product") else {
                      +      self.productTitleLabel.text = "Product unavailable"
                      +      return
                      +    }
                      +    // Display product information.
                      +    productTitleLabel.text = product.localizedTitle
                      +    productDescriptionLabel.text = product.localizedDescription
                      +    purchaseButton.setTitle(product.localizedPrice, for: .normal)
                      +
                      +    // Disable the button if the product has already been purchased.
                      +    if InAppPurchase.hasActivePurchase(for: "my_product") {
                      +      statusLabel.text = "OWNED"
                      +      purchaseButton.isPointerInteractionEnabled = false
                      +    }
                      +  }
                      +
                      +  @IBAction func purchase(_ sender: Any) {
                      +    self.loaderView.show()
                      +    InAppPurchase.purchase(
                      +      productIdentifier: "my_product",
                      +      callback: { result in
                      +        self.loaderView.hide()
                      +      })
                      +  }
                      +
                      +  @IBAction func restorePurchases(_ sender: Any) {
                      +    self.loaderView.show()
                      +    InAppPurchase.restorePurchases(callback: { result in
                      +      self.loaderView.hide()
                      +    })
                      +  }
                      +}
                      +
                      +

                      Documentation

                      + + + +

                      See also:

                      + + +

                      Xcode Demo Project

                      + +

                      Do not hesitate to check the demo project available on here: iap-swift-lib-demo.

                      +

                      Coding

                      + +

                      Generate the documentation, using Jazzy by running the following command:

                      +
                      jazzy
                      +
                      +

                      Troubleshooting

                      + +

                      Common issues are covered here: https://github.com/iridescent-dev/iap-swift-lib/wiki/Troubleshooting

                      +

                      License

                      + +

                      InAppPurchaseLib is open-sourced library licensed under the MIT License. See LICENSE for details.

                      + +
                      +
                      + + +
                      +
                      + + + + diff --git a/docs/initialization.html b/docs/initialization.html new file mode 100644 index 0000000..a87c6e0 --- /dev/null +++ b/docs/initialization.html @@ -0,0 +1,227 @@ + + + + Initialization Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Initialization

                      + +

                      Before everything else the library must be initialized. This has to happen as soon as possible. A good way is to call the InAppPurchase.initialize() method when the application did finish launching. In the background, this will load your products and refresh the status of purchases and subscriptions.

                      + +

                      InAppPurchase.initialize() requires the following arguments:

                      + +
                        +
                      • iapProducts - An array of IAPProduct
                      • +
                      • validatorUrlString - The validator url retrieved from Fovea
                      • +
                      + +

                      Each IAPProduct contains the following fields:

                      + +
                        +
                      • productIdentifier - The product unique identifier
                      • +
                      • productType - The IAPProductType (consumable, nonConsumable, nonRenewingSubscription or autoRenewableSubscription)
                      • +
                      + +

                      Example:

                      + +

                      A good place is generally in your application delegate’s didFinishLaunchingWithOptions function, like below:

                      +
                      import InAppPurchaseLib
                      +
                      +class AppDelegate: UIResponder, UIApplicationDelegate, IAPPurchaseDelegate {
                      +  ...
                      +  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      +    InAppPurchase.initialize(
                      +      iapProducts: [
                      +        IAPProduct(productIdentifier: "monthly_plan", productType: .autoRenewableSubscription),
                      +        IAPProduct(productIdentifier: "yearly_plan",  productType: .autoRenewableSubscription),
                      +        IAPProduct(productIdentifier: "disable_ads",  productType: .nonConsumable)
                      +      ],
                      +      validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678")
                      +  }
                      +
                      +  func productPurchased(productIdentifier: String) {
                      +    // ... process purchase (we'll see that later)
                      +  }
                      +}
                      +
                      + +

                      You should also call the stop method when the application will terminate, for proper cleanup.

                      +
                        func applicationWillTerminate(_ application: UIApplication) {
                      +    InAppPurchase.stop()
                      +  }
                      +
                      + +

                      For more advanced use cases, in particular when you have implemented user login, you’ll have to make some adjustments. We’ll learn more about this in the Server integration section.

                      + +

                      Tip: If initialization was successful, you should see a new receipt validation event in Fovea’s Dashboard.

                      + +
                      +
                      + + +
                      +
                      + + + + diff --git a/docs/installation.html b/docs/installation.html new file mode 100644 index 0000000..637dbb0 --- /dev/null +++ b/docs/installation.html @@ -0,0 +1,194 @@ + + + + Installation Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Installation

                      + +

                      + +

                      + +
                        +
                      • Select your project in Xcode
                      • +
                      • Go to the section Swift Package
                      • +
                      • Click on (+) Add Package Dependency
                      • +
                      • Copy the Git URL: https://github.com/iridescent-dev/iap-swift-lib.git
                      • +
                      • Click on Next > Next
                      • +
                      • Make sure your project is selected in Add to target
                      • +
                      • Click on Finish
                      • +
                      + +

                      Note: You have to import InAppPurchaseLib wherever you use the library.

                      + +
                      +
                      + + +
                      +
                      + + + + diff --git a/docs/jazzy/Classes.html b/docs/jazzy/Classes.html deleted file mode 100644 index d33eafb..0000000 --- a/docs/jazzy/Classes.html +++ /dev/null @@ -1,205 +0,0 @@ - - - - Classes Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      Classes

                      -

                      The following classes are available globally.

                      - -
                      -
                      -
                      - -
                      -
                      -
                      - - -
                      - -

                      The protocol that you must adopt.

                      -

                      -
                      -
                      - -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/Enums.html b/docs/jazzy/Enums.html deleted file mode 100644 index b724f25..0000000 --- a/docs/jazzy/Enums.html +++ /dev/null @@ -1,276 +0,0 @@ - - - - Enumerations Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      Enumerations

                      -

                      The following enumerations are available globally.

                      - -
                      -
                      -
                      -
                        -
                      • - -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public enum IAPPurchaseResultState
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPRefreshResultState - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public enum IAPRefreshResultState
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPErrorCode - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public enum IAPErrorCode
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPProductType - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public enum IAPProductType
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPPeriodFormat - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public enum IAPPeriodFormat
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/Enums/IAPPeriodFormat.html b/docs/jazzy/Enums/IAPPeriodFormat.html deleted file mode 100644 index b5080fe..0000000 --- a/docs/jazzy/Enums/IAPPeriodFormat.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - IAPPeriodFormat Enumeration Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      IAPPeriodFormat

                      -
                      -
                      -
                      public enum IAPPeriodFormat
                      - -
                      -
                      -

                      Undocumented

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - short - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        case short
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - long - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        case long
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/Enums/IAPRefreshResultState.html b/docs/jazzy/Enums/IAPRefreshResultState.html deleted file mode 100644 index ce460b0..0000000 --- a/docs/jazzy/Enums/IAPRefreshResultState.html +++ /dev/null @@ -1,223 +0,0 @@ - - - - IAPRefreshResultState Enumeration Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      IAPRefreshResultState

                      -
                      -
                      -
                      public enum IAPRefreshResultState
                      - -
                      -
                      -

                      Undocumented

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - succeeded - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        case succeeded
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - failed - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        case failed
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - skipped - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        case skipped
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/Extensions.html b/docs/jazzy/Extensions.html deleted file mode 100644 index 922e9fa..0000000 --- a/docs/jazzy/Extensions.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - Extensions Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      Extensions

                      -

                      The following extensions are available globally.

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - SKProduct - -
                        -
                        -
                        -
                        -
                        -
                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        extension SKProduct
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/Protocols.html b/docs/jazzy/Protocols.html deleted file mode 100644 index 33bac01..0000000 --- a/docs/jazzy/Protocols.html +++ /dev/null @@ -1,233 +0,0 @@ - - - - Protocols Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      Protocols

                      -

                      The following protocols are available globally.

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - IAPErrorProtocol - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public protocol IAPErrorProtocol : LocalizedError
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - InAppPurchaseLib - -
                        -
                        -
                        -
                        -
                        -
                        -

                        The protocol that InAppPurchase` adopts.

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public protocol InAppPurchaseLib
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - - -
                      - -

                      The protocol that you must adopt.

                      -

                      -
                      -
                      -
                        -
                      • -
                        - - - - IAPPurchaseDelegate - -
                        -
                        -
                        -
                        -
                        -
                        -

                        The protocol that you must adopt if you have consumable and/or nonRenewingSubscription products.

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public protocol IAPPurchaseDelegate
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/Protocols/IAPErrorProtocol.html b/docs/jazzy/Protocols/IAPErrorProtocol.html deleted file mode 100644 index 39a040c..0000000 --- a/docs/jazzy/Protocols/IAPErrorProtocol.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - IAPErrorProtocol Protocol Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      IAPErrorProtocol

                      -
                      -
                      -
                      public protocol IAPErrorProtocol : LocalizedError
                      - -
                      -
                      -

                      Undocumented

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - code - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        var code: IAPErrorCode { get }
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/Protocols/IAPPurchaseDelegate.html b/docs/jazzy/Protocols/IAPPurchaseDelegate.html deleted file mode 100644 index ced2b91..0000000 --- a/docs/jazzy/Protocols/IAPPurchaseDelegate.html +++ /dev/null @@ -1,193 +0,0 @@ - - - - IAPPurchaseDelegate Protocol Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      IAPPurchaseDelegate

                      -
                      -
                      -
                      public protocol IAPPurchaseDelegate
                      - -
                      -
                      -

                      The protocol that you must adopt if you have consumable and/or nonRenewingSubscription products.

                      - -
                      -
                      -
                      -
                        -
                      • - -
                        -
                        -
                        -
                        -
                        -

                        Called when a product is newly purchased, updated or restored.

                        -
                        -

                        Important

                        -

                        You have to acknowledge delivery of the (virtual) item to finalize the transaction. Then you have to call InAppPurchase.finishTransactions(for: productIdentifier)as soon as you have delivered the product.

                        - -
                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        func productPurchased(productIdentifier: String)
                        - -
                        -
                        -
                        -

                        Parameters

                        - - - - - - - -
                        - - productIdentifier - - -
                        -

                        The identifier of the product.

                        -
                        -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/Structs.html b/docs/jazzy/Structs.html deleted file mode 100644 index 7b7bec2..0000000 --- a/docs/jazzy/Structs.html +++ /dev/null @@ -1,248 +0,0 @@ - - - - Structures Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      Structures

                      -

                      The following structures are available globally.

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - IAPPurchaseResult - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public struct IAPPurchaseResult
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPRefreshResult - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public struct IAPRefreshResult
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPError - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public struct IAPError : IAPErrorProtocol
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPProduct - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public struct IAPProduct
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/Structs/IAPError.html b/docs/jazzy/Structs/IAPError.html deleted file mode 100644 index b1e121c..0000000 --- a/docs/jazzy/Structs/IAPError.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - IAPError Structure Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      IAPError

                      -
                      -
                      -
                      public struct IAPError : IAPErrorProtocol
                      - -
                      -
                      -

                      Undocumented

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - code - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public var code: IAPErrorCode
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - localizedDescription - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public var localizedDescription: String { get }
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/Typealiases.html b/docs/jazzy/Typealiases.html deleted file mode 100644 index 17dd0f5..0000000 --- a/docs/jazzy/Typealiases.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - Type Aliases Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      Type Aliases

                      -

                      The following type aliases are available globally.

                      - -
                      -
                      -
                      - -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/css/jazzy.css b/docs/jazzy/css/jazzy.css deleted file mode 100644 index c3090c0..0000000 --- a/docs/jazzy/css/jazzy.css +++ /dev/null @@ -1,374 +0,0 @@ -html, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td { - background: transparent; - border: 0; - margin: 0; - outline: 0; - padding: 0; - vertical-align: baseline; } - -body { - background-color: #f2f2f2; - font-family: Helvetica, freesans, Arial, sans-serif; - font-size: 14px; - -webkit-font-smoothing: subpixel-antialiased; - word-wrap: break-word; } - -h1, h2, h3 { - margin-top: 0.8em; - margin-bottom: 0.3em; - font-weight: 100; - color: black; } - -h1 { - font-size: 2.5em; } - -h2 { - font-size: 2em; - border-bottom: 1px solid #e2e2e2; } - -h4 { - font-size: 13px; - line-height: 1.5; - margin-top: 21px; } - -h5 { - font-size: 1.1em; } - -h6 { - font-size: 1.1em; - color: #777; } - -.section-name { - color: gray; - display: block; - font-family: Helvetica; - font-size: 22px; - font-weight: 100; - margin-bottom: 15px; } - -pre, code { - font: 0.95em Menlo, monospace; - color: #777; - word-wrap: normal; } - -p code, li code { - background-color: #eee; - padding: 2px 4px; - border-radius: 4px; } - -a { - color: #0088cc; - text-decoration: none; } - -ul { - padding-left: 15px; } - -li { - line-height: 1.8em; } - -img { - max-width: 100%; } - -blockquote { - margin-left: 0; - padding: 0 10px; - border-left: 4px solid #ccc; } - -.content-wrapper { - margin: 0 auto; - width: 980px; } - -header { - font-size: 0.85em; - line-height: 26px; - background-color: #414141; - position: fixed; - width: 100%; - z-index: 2; } - header img { - padding-right: 6px; - vertical-align: -4px; - height: 16px; } - header a { - color: #fff; } - header p { - float: left; - color: #999; } - header .header-right { - float: right; - margin-left: 16px; } - -#breadcrumbs { - background-color: #f2f2f2; - height: 27px; - padding-top: 17px; - position: fixed; - width: 100%; - z-index: 2; - margin-top: 26px; } - #breadcrumbs #carat { - height: 10px; - margin: 0 5px; } - -.sidebar { - background-color: #f9f9f9; - border: 1px solid #e2e2e2; - overflow-y: auto; - overflow-x: hidden; - position: fixed; - top: 70px; - bottom: 0; - width: 230px; - word-wrap: normal; } - -.nav-groups { - list-style-type: none; - background: #fff; - padding-left: 0; } - -.nav-group-name { - border-bottom: 1px solid #e2e2e2; - font-size: 1.1em; - font-weight: 100; - padding: 15px 0 15px 20px; } - .nav-group-name > a { - color: #333; } - -.nav-group-tasks { - margin-top: 5px; } - -.nav-group-task { - font-size: 0.9em; - list-style-type: none; - white-space: nowrap; } - .nav-group-task a { - color: #888; } - -.main-content { - background-color: #fff; - border: 1px solid #e2e2e2; - margin-left: 246px; - position: absolute; - overflow: hidden; - padding-bottom: 20px; - top: 70px; - width: 734px; } - .main-content p, .main-content a, .main-content code, .main-content em, .main-content ul, .main-content table, .main-content blockquote { - margin-bottom: 1em; } - .main-content p { - line-height: 1.8em; } - .main-content section .section:first-child { - margin-top: 0; - padding-top: 0; } - .main-content section .task-group-section .task-group:first-of-type { - padding-top: 10px; } - .main-content section .task-group-section .task-group:first-of-type .section-name { - padding-top: 15px; } - .main-content section .heading:before { - content: ""; - display: block; - padding-top: 70px; - margin: -70px 0 0; } - .main-content .section-name p { - margin-bottom: inherit; - line-height: inherit; } - .main-content .section-name code { - background-color: inherit; - padding: inherit; - color: inherit; } - -.section { - padding: 0 25px; } - -.highlight { - background-color: #eee; - padding: 10px 12px; - border: 1px solid #e2e2e2; - border-radius: 4px; - overflow-x: auto; } - -.declaration .highlight { - overflow-x: initial; - padding: 0 40px 40px 0; - margin-bottom: -25px; - background-color: transparent; - border: none; } - -.section-name { - margin: 0; - margin-left: 18px; } - -.task-group-section { - padding-left: 6px; - border-top: 1px solid #e2e2e2; } - -.task-group { - padding-top: 0px; } - -.task-name-container a[name]:before { - content: ""; - display: block; - padding-top: 70px; - margin: -70px 0 0; } - -.section-name-container { - position: relative; - display: inline-block; } - .section-name-container .section-name-link { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - margin-bottom: 0; } - .section-name-container .section-name { - position: relative; - pointer-events: none; - z-index: 1; } - .section-name-container .section-name a { - pointer-events: auto; } - -.item { - padding-top: 8px; - width: 100%; - list-style-type: none; } - .item a[name]:before { - content: ""; - display: block; - padding-top: 70px; - margin: -70px 0 0; } - .item code { - background-color: transparent; - padding: 0; } - .item .token, .item .direct-link { - display: inline-block; - text-indent: -20px; - padding-left: 3px; - margin-left: 35px; - font-size: 11.9px; - transition: all 300ms; } - .item .token-open { - margin-left: 20px; } - .item .discouraged { - text-decoration: line-through; } - .item .declaration-note { - font-size: .85em; - color: gray; - font-style: italic; } - -.pointer-container { - border-bottom: 1px solid #e2e2e2; - left: -23px; - padding-bottom: 13px; - position: relative; - width: 110%; } - -.pointer { - background: #f9f9f9; - border-left: 1px solid #e2e2e2; - border-top: 1px solid #e2e2e2; - height: 12px; - left: 21px; - top: -7px; - -webkit-transform: rotate(45deg); - -moz-transform: rotate(45deg); - -o-transform: rotate(45deg); - transform: rotate(45deg); - position: absolute; - width: 12px; } - -.height-container { - display: none; - left: -25px; - padding: 0 25px; - position: relative; - width: 100%; - overflow: hidden; } - .height-container .section { - background: #f9f9f9; - border-bottom: 1px solid #e2e2e2; - left: -25px; - position: relative; - width: 100%; - padding-top: 10px; - padding-bottom: 5px; } - -.aside, .language { - padding: 6px 12px; - margin: 12px 0; - border-left: 5px solid #dddddd; - overflow-y: hidden; } - .aside .aside-title, .language .aside-title { - font-size: 9px; - letter-spacing: 2px; - text-transform: uppercase; - padding-bottom: 0; - margin: 0; - color: #aaa; - -webkit-user-select: none; } - .aside p:last-child, .language p:last-child { - margin-bottom: 0; } - -.language { - border-left: 5px solid #cde9f4; } - .language .aside-title { - color: #4b8afb; } - -.aside-warning, .aside-deprecated, .aside-unavailable { - border-left: 5px solid #ff6666; } - .aside-warning .aside-title, .aside-deprecated .aside-title, .aside-unavailable .aside-title { - color: #ff0000; } - -.graybox { - border-collapse: collapse; - width: 100%; } - .graybox p { - margin: 0; - word-break: break-word; - min-width: 50px; } - .graybox td { - border: 1px solid #e2e2e2; - padding: 5px 25px 5px 10px; - vertical-align: middle; } - .graybox tr td:first-of-type { - text-align: right; - padding: 7px; - vertical-align: top; - word-break: normal; - width: 40px; } - -.slightly-smaller { - font-size: 0.9em; } - -#footer { - position: relative; - top: 10px; - bottom: 0px; - margin-left: 25px; } - #footer p { - margin: 0; - color: #aaa; - font-size: 0.8em; } - -html.dash header, html.dash #breadcrumbs, html.dash .sidebar { - display: none; } - -html.dash .main-content { - width: 980px; - margin-left: 0; - border: none; - width: 100%; - top: 0; - padding-bottom: 0; } - -html.dash .height-container { - display: block; } - -html.dash .item .token { - margin-left: 0; } - -html.dash .content-wrapper { - width: auto; } - -html.dash #footer { - position: static; } diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes.html b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes.html deleted file mode 100644 index d33eafb..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Classes.html +++ /dev/null @@ -1,205 +0,0 @@ - - - - Classes Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      Classes

                      -

                      The following classes are available globally.

                      - -
                      -
                      -
                      - -
                      -
                      -
                      - - -
                      - -

                      The protocol that you must adopt.

                      -

                      -
                      -
                      - -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums.html b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums.html deleted file mode 100644 index b724f25..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums.html +++ /dev/null @@ -1,276 +0,0 @@ - - - - Enumerations Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      Enumerations

                      -

                      The following enumerations are available globally.

                      - -
                      -
                      -
                      -
                        -
                      • - -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public enum IAPPurchaseResultState
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPRefreshResultState - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public enum IAPRefreshResultState
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPErrorCode - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public enum IAPErrorCode
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPProductType - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public enum IAPProductType
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPPeriodFormat - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public enum IAPPeriodFormat
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPPeriodFormat.html b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPPeriodFormat.html deleted file mode 100644 index b5080fe..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPPeriodFormat.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - IAPPeriodFormat Enumeration Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      IAPPeriodFormat

                      -
                      -
                      -
                      public enum IAPPeriodFormat
                      - -
                      -
                      -

                      Undocumented

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - short - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        case short
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - long - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        case long
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPRefreshResultState.html b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPRefreshResultState.html deleted file mode 100644 index ce460b0..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Enums/IAPRefreshResultState.html +++ /dev/null @@ -1,223 +0,0 @@ - - - - IAPRefreshResultState Enumeration Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      IAPRefreshResultState

                      -
                      -
                      -
                      public enum IAPRefreshResultState
                      - -
                      -
                      -

                      Undocumented

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - succeeded - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        case succeeded
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - failed - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        case failed
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - skipped - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        case skipped
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Extensions.html b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Extensions.html deleted file mode 100644 index 922e9fa..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Extensions.html +++ /dev/null @@ -1,163 +0,0 @@ - - - - Extensions Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      Extensions

                      -

                      The following extensions are available globally.

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - SKProduct - -
                        -
                        -
                        -
                        -
                        -
                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        extension SKProduct
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols.html b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols.html deleted file mode 100644 index 33bac01..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols.html +++ /dev/null @@ -1,233 +0,0 @@ - - - - Protocols Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      Protocols

                      -

                      The following protocols are available globally.

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - IAPErrorProtocol - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public protocol IAPErrorProtocol : LocalizedError
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - InAppPurchaseLib - -
                        -
                        -
                        -
                        -
                        -
                        -

                        The protocol that InAppPurchase` adopts.

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public protocol InAppPurchaseLib
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - - -
                      - -

                      The protocol that you must adopt.

                      -

                      -
                      -
                      -
                        -
                      • -
                        - - - - IAPPurchaseDelegate - -
                        -
                        -
                        -
                        -
                        -
                        -

                        The protocol that you must adopt if you have consumable and/or nonRenewingSubscription products.

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public protocol IAPPurchaseDelegate
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/IAPErrorProtocol.html b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/IAPErrorProtocol.html deleted file mode 100644 index 39a040c..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/IAPErrorProtocol.html +++ /dev/null @@ -1,169 +0,0 @@ - - - - IAPErrorProtocol Protocol Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      IAPErrorProtocol

                      -
                      -
                      -
                      public protocol IAPErrorProtocol : LocalizedError
                      - -
                      -
                      -

                      Undocumented

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - code - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        var code: IAPErrorCode { get }
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/IAPPurchaseDelegate.html b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/IAPPurchaseDelegate.html deleted file mode 100644 index ced2b91..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Protocols/IAPPurchaseDelegate.html +++ /dev/null @@ -1,193 +0,0 @@ - - - - IAPPurchaseDelegate Protocol Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      IAPPurchaseDelegate

                      -
                      -
                      -
                      public protocol IAPPurchaseDelegate
                      - -
                      -
                      -

                      The protocol that you must adopt if you have consumable and/or nonRenewingSubscription products.

                      - -
                      -
                      -
                      -
                        -
                      • - -
                        -
                        -
                        -
                        -
                        -

                        Called when a product is newly purchased, updated or restored.

                        -
                        -

                        Important

                        -

                        You have to acknowledge delivery of the (virtual) item to finalize the transaction. Then you have to call InAppPurchase.finishTransactions(for: productIdentifier)as soon as you have delivered the product.

                        - -
                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        func productPurchased(productIdentifier: String)
                        - -
                        -
                        -
                        -

                        Parameters

                        - - - - - - - -
                        - - productIdentifier - - -
                        -

                        The identifier of the product.

                        -
                        -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs.html b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs.html deleted file mode 100644 index 7b7bec2..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs.html +++ /dev/null @@ -1,248 +0,0 @@ - - - - Structures Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      Structures

                      -

                      The following structures are available globally.

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - IAPPurchaseResult - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public struct IAPPurchaseResult
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPRefreshResult - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public struct IAPRefreshResult
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPError - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public struct IAPError : IAPErrorProtocol
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - IAPProduct - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - - See more -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public struct IAPProduct
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPError.html b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPError.html deleted file mode 100644 index b1e121c..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Structs/IAPError.html +++ /dev/null @@ -1,196 +0,0 @@ - - - - IAPError Structure Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      IAPError

                      -
                      -
                      -
                      public struct IAPError : IAPErrorProtocol
                      - -
                      -
                      -

                      Undocumented

                      - -
                      -
                      -
                      -
                        -
                      • -
                        - - - - code - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public var code: IAPErrorCode
                        - -
                        -
                        -
                        -
                        -
                      • -
                      • -
                        - - - - localizedDescription - -
                        -
                        -
                        -
                        -
                        -
                        -

                        Undocumented

                        - -
                        -
                        -

                        Declaration

                        -
                        -

                        Swift

                        -
                        public var localizedDescription: String { get }
                        - -
                        -
                        -
                        -
                        -
                      • -
                      -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Typealiases.html b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Typealiases.html deleted file mode 100644 index 17dd0f5..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/Typealiases.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - Type Aliases Reference - - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      -

                      Type Aliases

                      -

                      The following type aliases are available globally.

                      - -
                      -
                      -
                      - -
                      -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/css/jazzy.css b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/css/jazzy.css deleted file mode 100644 index c3090c0..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/css/jazzy.css +++ /dev/null @@ -1,374 +0,0 @@ -html, body, div, span, h1, h3, h4, p, a, code, em, img, ul, li, table, tbody, tr, td { - background: transparent; - border: 0; - margin: 0; - outline: 0; - padding: 0; - vertical-align: baseline; } - -body { - background-color: #f2f2f2; - font-family: Helvetica, freesans, Arial, sans-serif; - font-size: 14px; - -webkit-font-smoothing: subpixel-antialiased; - word-wrap: break-word; } - -h1, h2, h3 { - margin-top: 0.8em; - margin-bottom: 0.3em; - font-weight: 100; - color: black; } - -h1 { - font-size: 2.5em; } - -h2 { - font-size: 2em; - border-bottom: 1px solid #e2e2e2; } - -h4 { - font-size: 13px; - line-height: 1.5; - margin-top: 21px; } - -h5 { - font-size: 1.1em; } - -h6 { - font-size: 1.1em; - color: #777; } - -.section-name { - color: gray; - display: block; - font-family: Helvetica; - font-size: 22px; - font-weight: 100; - margin-bottom: 15px; } - -pre, code { - font: 0.95em Menlo, monospace; - color: #777; - word-wrap: normal; } - -p code, li code { - background-color: #eee; - padding: 2px 4px; - border-radius: 4px; } - -a { - color: #0088cc; - text-decoration: none; } - -ul { - padding-left: 15px; } - -li { - line-height: 1.8em; } - -img { - max-width: 100%; } - -blockquote { - margin-left: 0; - padding: 0 10px; - border-left: 4px solid #ccc; } - -.content-wrapper { - margin: 0 auto; - width: 980px; } - -header { - font-size: 0.85em; - line-height: 26px; - background-color: #414141; - position: fixed; - width: 100%; - z-index: 2; } - header img { - padding-right: 6px; - vertical-align: -4px; - height: 16px; } - header a { - color: #fff; } - header p { - float: left; - color: #999; } - header .header-right { - float: right; - margin-left: 16px; } - -#breadcrumbs { - background-color: #f2f2f2; - height: 27px; - padding-top: 17px; - position: fixed; - width: 100%; - z-index: 2; - margin-top: 26px; } - #breadcrumbs #carat { - height: 10px; - margin: 0 5px; } - -.sidebar { - background-color: #f9f9f9; - border: 1px solid #e2e2e2; - overflow-y: auto; - overflow-x: hidden; - position: fixed; - top: 70px; - bottom: 0; - width: 230px; - word-wrap: normal; } - -.nav-groups { - list-style-type: none; - background: #fff; - padding-left: 0; } - -.nav-group-name { - border-bottom: 1px solid #e2e2e2; - font-size: 1.1em; - font-weight: 100; - padding: 15px 0 15px 20px; } - .nav-group-name > a { - color: #333; } - -.nav-group-tasks { - margin-top: 5px; } - -.nav-group-task { - font-size: 0.9em; - list-style-type: none; - white-space: nowrap; } - .nav-group-task a { - color: #888; } - -.main-content { - background-color: #fff; - border: 1px solid #e2e2e2; - margin-left: 246px; - position: absolute; - overflow: hidden; - padding-bottom: 20px; - top: 70px; - width: 734px; } - .main-content p, .main-content a, .main-content code, .main-content em, .main-content ul, .main-content table, .main-content blockquote { - margin-bottom: 1em; } - .main-content p { - line-height: 1.8em; } - .main-content section .section:first-child { - margin-top: 0; - padding-top: 0; } - .main-content section .task-group-section .task-group:first-of-type { - padding-top: 10px; } - .main-content section .task-group-section .task-group:first-of-type .section-name { - padding-top: 15px; } - .main-content section .heading:before { - content: ""; - display: block; - padding-top: 70px; - margin: -70px 0 0; } - .main-content .section-name p { - margin-bottom: inherit; - line-height: inherit; } - .main-content .section-name code { - background-color: inherit; - padding: inherit; - color: inherit; } - -.section { - padding: 0 25px; } - -.highlight { - background-color: #eee; - padding: 10px 12px; - border: 1px solid #e2e2e2; - border-radius: 4px; - overflow-x: auto; } - -.declaration .highlight { - overflow-x: initial; - padding: 0 40px 40px 0; - margin-bottom: -25px; - background-color: transparent; - border: none; } - -.section-name { - margin: 0; - margin-left: 18px; } - -.task-group-section { - padding-left: 6px; - border-top: 1px solid #e2e2e2; } - -.task-group { - padding-top: 0px; } - -.task-name-container a[name]:before { - content: ""; - display: block; - padding-top: 70px; - margin: -70px 0 0; } - -.section-name-container { - position: relative; - display: inline-block; } - .section-name-container .section-name-link { - position: absolute; - top: 0; - left: 0; - bottom: 0; - right: 0; - margin-bottom: 0; } - .section-name-container .section-name { - position: relative; - pointer-events: none; - z-index: 1; } - .section-name-container .section-name a { - pointer-events: auto; } - -.item { - padding-top: 8px; - width: 100%; - list-style-type: none; } - .item a[name]:before { - content: ""; - display: block; - padding-top: 70px; - margin: -70px 0 0; } - .item code { - background-color: transparent; - padding: 0; } - .item .token, .item .direct-link { - display: inline-block; - text-indent: -20px; - padding-left: 3px; - margin-left: 35px; - font-size: 11.9px; - transition: all 300ms; } - .item .token-open { - margin-left: 20px; } - .item .discouraged { - text-decoration: line-through; } - .item .declaration-note { - font-size: .85em; - color: gray; - font-style: italic; } - -.pointer-container { - border-bottom: 1px solid #e2e2e2; - left: -23px; - padding-bottom: 13px; - position: relative; - width: 110%; } - -.pointer { - background: #f9f9f9; - border-left: 1px solid #e2e2e2; - border-top: 1px solid #e2e2e2; - height: 12px; - left: 21px; - top: -7px; - -webkit-transform: rotate(45deg); - -moz-transform: rotate(45deg); - -o-transform: rotate(45deg); - transform: rotate(45deg); - position: absolute; - width: 12px; } - -.height-container { - display: none; - left: -25px; - padding: 0 25px; - position: relative; - width: 100%; - overflow: hidden; } - .height-container .section { - background: #f9f9f9; - border-bottom: 1px solid #e2e2e2; - left: -25px; - position: relative; - width: 100%; - padding-top: 10px; - padding-bottom: 5px; } - -.aside, .language { - padding: 6px 12px; - margin: 12px 0; - border-left: 5px solid #dddddd; - overflow-y: hidden; } - .aside .aside-title, .language .aside-title { - font-size: 9px; - letter-spacing: 2px; - text-transform: uppercase; - padding-bottom: 0; - margin: 0; - color: #aaa; - -webkit-user-select: none; } - .aside p:last-child, .language p:last-child { - margin-bottom: 0; } - -.language { - border-left: 5px solid #cde9f4; } - .language .aside-title { - color: #4b8afb; } - -.aside-warning, .aside-deprecated, .aside-unavailable { - border-left: 5px solid #ff6666; } - .aside-warning .aside-title, .aside-deprecated .aside-title, .aside-unavailable .aside-title { - color: #ff0000; } - -.graybox { - border-collapse: collapse; - width: 100%; } - .graybox p { - margin: 0; - word-break: break-word; - min-width: 50px; } - .graybox td { - border: 1px solid #e2e2e2; - padding: 5px 25px 5px 10px; - vertical-align: middle; } - .graybox tr td:first-of-type { - text-align: right; - padding: 7px; - vertical-align: top; - word-break: normal; - width: 40px; } - -.slightly-smaller { - font-size: 0.9em; } - -#footer { - position: relative; - top: 10px; - bottom: 0px; - margin-left: 25px; } - #footer p { - margin: 0; - color: #aaa; - font-size: 0.8em; } - -html.dash header, html.dash #breadcrumbs, html.dash .sidebar { - display: none; } - -html.dash .main-content { - width: 980px; - margin-left: 0; - border: none; - width: 100%; - top: 0; - padding-bottom: 0; } - -html.dash .height-container { - display: block; } - -html.dash .item .token { - margin-left: 0; } - -html.dash .content-wrapper { - width: auto; } - -html.dash #footer { - position: static; } diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/index.html b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/index.html deleted file mode 100644 index e633951..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/index.html +++ /dev/null @@ -1,699 +0,0 @@ - - - - InAppPurchaseLib Reference - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      - -

                      - -

                      - -
                      -

                      An easy-to-use library for In-App Purchases, using Fovea.Billing for receipts validation.

                      -
                      - - -

                      Features

                      - -
                        -
                      • ✅ Purchase a product
                      • -
                      • ✅ Restore purchased products
                      • -
                      • ✅ Verify transactions with the App Store on Fovea.Billing server
                      • -
                      • ✅ Handle and notify payment transaction states
                      • -
                      • ✅ Retreive products information from the App Store
                      • -
                      • ✅ Support all product types (consumable, non-consumable, auto-renewable subscription, non-renewing subscription)
                      • -
                      • ✅ Status of purchases available when offline
                      • -
                      • ✅ Server integration with a Webhook
                      • -
                      -

                      Getting Started

                      - -

                      If you haven’t already, I highly recommend your read the Overview and Preparing section of Apple’s In-App Purchase official documentation

                      -

                      Requirements

                      - -
                        -
                      • Configure your App and Xcode to support In-App Purchases. - -
                      • -
                      • Create and configure your Fovea.Billing project account: - -
                          -
                        • Set your bundle ID
                        • -
                        • The iOS Shared Secret (or shared key) is to be retrieved from AppStoreConnect
                        • -
                        • The iOS Subscription Status URL (only if you want subscriptions)
                        • -
                      • -
                      -

                      Installation

                      - -

                      - -

                      - -
                        -
                      • Select your project in Xcode
                      • -
                      • Go to the section Swift Package
                      • -
                      • Click on (+) Add Package Dependency
                      • -
                      • Copy the Git URL: https://github.com/iridescent-dev/iap-swift-lib.git
                      • -
                      • Click on Next > Next
                      • -
                      • Make sure your project is selected in Add to target
                      • -
                      • Click on Finish
                      • -
                      - -

                      Note: You have to import InAppPurchaseLib wherever you use the library.

                      -

                      Usage

                      - -

                      The process of implementing in-app purchases involves several steps:

                      - -
                        -
                      1. Displaying the list of purchasable products
                      2. -
                      3. Initiating a purchase
                      4. -
                      5. Delivering and finalizing a purchase
                      6. -
                      7. Checking the current ownership of non-consumables and subscriptions
                      8. -
                      9. Implementing the Restore Purchases button
                      10. -
                      -

                      Initialization

                      - -

                      Before everything else the library must be initialized. This has to happen as soon as possible. A good way is to call the InAppPurchase.initialize() method when the application did finish launching. In the background, this will load your products and refresh the status of purchases and subscriptions.

                      - -

                      InAppPurchase.initialize() accepts the following arguments:

                      - -
                        -
                      • iapProducts - An array of IAPProduct (REQUIRED)
                      • -
                      • validatorUrlString - The validator url retrieved from Fovea (REQUIRED)
                      • -
                      • applicationUsername - The user name, if your app implements user login (optional)
                      • -
                      - -

                      Each IAPProduct contains the following fields:

                      - -
                        -
                      • productIdentifier - The product unique identifier
                      • -
                      • productType - The IAPProductType (consumable, nonConsumable, nonRenewingSubscription or autoRenewableSubscription)
                      • -
                      - -

                      Example:

                      - -

                      A good place is generally in your application delegate’s didFinishLaunchingWithOptions function, like below:

                      -
                      import InAppPurchaseLib
                      -
                      -class AppDelegate: UIResponder, UIApplicationDelegate, IAPPurchaseDelegate {
                      -  ...
                      -  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      -    InAppPurchase.initialize(
                      -      iapProducts: [
                      -        IAPProduct(productIdentifier: "monthly_plan", productType: .autoRenewableSubscription),
                      -        IAPProduct(productIdentifier: "yearly_plan",  productType: .autoRenewableSubscription),
                      -        IAPProduct(productIdentifier: "disable_ads",  productType: .nonConsumable)
                      -      ],
                      -      validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678")
                      -  }
                      -
                      -  func productPurchased(productIdentifier: String) {
                      -    // ... process purchase (we'll see that later)
                      -  }
                      -}
                      -
                      - -

                      You should also call the stop method when the application will terminate, for proper cleanup.

                      -
                        func applicationWillTerminate(_ application: UIApplication) {
                      -    InAppPurchase.stop()
                      -  }
                      -
                      - -

                      For more advanced use cases, in particular when you have implemented user login, you’ll have to make some adjustments. We’ll learn more about this in the Server integration section.

                      - -

                      Tip: If initialization was successful, you should see a new receipt validation event in Fovea’s Dashboard.

                      -

                      Displaying products

                      - -

                      Let’s start with the simplest case: you have a single product.

                      - -

                      You can retrieve all information about this product using the function InAppPurchase.getProductBy(identifier: "my_product_id"). This returns an SKProduct extended with helpful methods.

                      - -

                      Those are the most important:

                      - -
                        -
                      • productIdentifier: String - The string that identifies the product to the Apple AppStore.
                      • -
                      • localizedTitle: String - The name of the product, in the language of the device, as retrieved from the AppStore.
                      • -
                      • localizedDescription: String - A description of the product, in the language of the device, as retrieved from the AppStore.
                      • -
                      • localizedPrice: String - The cost of the product in the local currency (read-only property added by this library).
                      • -
                      - -

                      Example:

                      - -

                      You can add a function similar to this to your view.

                      -
                      @objc func refreshView() {
                      -  guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else {
                      -    self.titleLabel.text = "Product unavailable"
                      -    return
                      -  }
                      -  self.titleLabel.text = product.localizedTitle
                      -  self.descriptionLabel.text = product.localizedDescription
                      -  self.priceLabel.text = product.localizedPrice
                      -}
                      -
                      - -

                      This example assumes self.titleLabel is a UILabel, etc.

                      - -

                      Make sure to call this function when the view appears on screen, for instance by calling it from viewWillAppear.

                      -
                      override func viewWillAppear(_ animated: Bool) {
                      -  self.refreshView()
                      -}
                      -
                      -

                      Displaying subscriptions

                      - -

                      For subscription products, you also have some data about subscription periods and introductory offers.

                      - -
                        -
                      • func hasIntroductoryPriceEligible() -> Bool - The product has an introductory price the user is eligible to.
                      • -
                      • localizedSubscriptionPeriod: String? - The period of the subscription.
                      • -
                      • localizedIntroductoryPrice: String? - The cost of the introductory offer if available in the local currency.
                      • -
                      • localizedIntroductoryPeriod: String? - The subscription period of the introductory offer.
                      • -
                      • localizedIntroductoryDuration: String? - The duration of the introductory offer.
                      • -
                      - -

                      Example

                      -
                      @objc func refreshView() {
                      -  guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else {
                      -    self.titleLabel.text = "Product unavailable"
                      -    return
                      -  }
                      -  self.titleLabel.text = product.localizedTitle
                      -  self.descriptionLabel.text = product.localizedDescription
                      -
                      -  // Format price text. Example: "0,99€ / month for 3 months (then 3,99 € / month)"
                      -  var priceText = "\(product.localizedPrice) / \(product.localizedSubscriptionPeriod!)"
                      -  if product.hasIntroductoryPriceEligible() {
                      -      if product.introductoryPrice!.numberOfPeriods == 1 {
                      -          priceText = "\(product.localizedIntroductoryPrice!) for \(product.localizedIntroductoryDuration!)" +
                      -          " (then \(priceText))"
                      -      } else {
                      -          priceText = "\(product.localizedIntroductoryPrice!) / \(product.localizedIntroductoryPeriod!)" +
                      -          " for \(product.localizedIntroductoryDuration!) (then \(priceText))"
                      -      }
                      -  }
                      -  self.priceLabel.text = priceText
                      -}
                      -
                      - -

                      Note: You have to import StoreKit wherever you use SKProduct.

                      -

                      Refreshing

                      - -

                      Data might change or not be yet available when your “product” view is presented. In order to properly handle those cases, you should refresh your view after refreshing in-app products metadata. You want to be sure you’re displaying up-to-date information.

                      - -

                      To achieve this, call InAppPurchase.refresh() when your view is presented.

                      -
                      override func viewWillAppear(_ animated: Bool) {
                      -  self.refreshView()
                      -  InAppPurchase.refresh(callback: { _ in
                      -      self.refreshView()
                      -  })
                      -}
                      -
                      -

                      Purchasing

                      - -

                      The purchase process is generally a little bit more involving than most people would expect. Why is it not just: purchase → on success unlock the feature?

                      - -

                      Several reasons:

                      - -
                        -
                      • In-app purchases can be initiated outside the app
                      • -
                      • In-app purchases can be deferred, pending parental approval
                      • -
                      • Apple wants to be sure you delivered the product before charging the user
                      • -
                      - -

                      That is why the process looks like so:

                      - -
                        -
                      • being ready to handle purchase events from app startup
                      • -
                      • finalizing transactions when product delivery is complete
                      • -
                      • sending purchase request, for which successful doesn’t always mean complete
                      • -
                      -

                      Initiating a purchase

                      - -

                      To initiate a purchase, use the InAppPurchase.purchase() function. It takes the productIdentifier and a callback function, called when the purchase has been processed.

                      - -

                      Important: Do not process the purchase here, we’ll handle that later!

                      - -

                      From this callback, you can for example unlock the UI by hiding your loading indicator and display a message to the user.

                      - -

                      Example:

                      -
                      self.loaderView.show()
                      -InAppPurchase.purchase(
                      -  productIdentifier: "my_product_id",
                      -  callback: { _ in
                      -    self.loaderView.hide()
                      -})
                      -
                      - -

                      This simple example locks the UI with a loader when the purchase is in progress. We’ll see later how the purchase has to be processed by your applicaiton.

                      - -

                      The callback also gives more information about the outcome of the purchase, you might want to use it to update your UI as well. Note that some events are useful for analytics. So here’s a more complete example.

                      -
                      self.loaderView.show()
                      -InAppPurchase.purchase(
                      -  productIdentifier: "my_product_id",
                      -  callback: { result in
                      -    self.loaderView.hide()
                      -
                      -    switch result.state {
                      -    case .purchased:
                      -      // Product successfully purchased
                      -      // Reminder: Do not process the purchase here, only update your UI.
                      -      //           that's why we do not send data to analytics.
                      -      openThankYouScreen()
                      -    case .failed:
                      -      // Purchase failed
                      -      // - Human formated reason can be found in result.localizedDescription
                      -      // - More details in either result.skError or result.iapError
                      -      showError(result.localizedDescription)
                      -    case .deferred:
                      -      // The purchase is deferred, waiting for the parent's approval
                      -      openWaitingParentApprovalScreen()
                      -    case .cancelled:
                      -      // The user canceled the request, generally only useful for analytics.
                      -  }
                      -})
                      -
                      - -

                      If the purchase fails, result will contain either .skError, a SKError from StoreKit, or .iapError, an IAPError.

                      - -

                      Tip: After a successful purchase, you should see a new transaction in Fovea’s dashboard.

                      -

                      Handling purchases

                      - -

                      Finally, the magic happened: a user purchased one of your products! Let’s see how we handle the different types of products.

                      -

                      Non-Consumables

                      - -

                      Wherever your app needs to know if a non-consumable product has been purchased, use InAppPurchase.hasActivePurchase(for: -productIdentifier). This will return true if the user currently owns the product.

                      - -

                      Note: The last known state for the user’s purchases is stored as UserDefaults. As such, their status is always available to your app, even when offline.

                      - -

                      If you have a server that needs to know about the purchase. You should rely on Fovea’s webhook instead of doing anything in here. We will see that later in the Server integration section.

                      -

                      Auto-Renewable Subscriptions

                      - -

                      As with non-consumables, you will use InAppPurchase.hasActivePurchase(for: productIdentifier) to check if the user is an active subscriber to a given product.

                      - -

                      You might also like to call refresh regularly, for example when entering your main view. When appropriate, the library will refresh the receipt to detect subscription renewals or expiry.

                      - -

                      As we’ve seend in the Refreshing section:

                      -
                      override func viewWillAppear(_ animated: Bool) {
                      -  self.refreshView()
                      -  InAppPurchase.refresh(callback: { _ in
                      -      self.refreshView()
                      -  })
                      -}
                      -
                      - -

                      Note: Don’t be reluctant to call refresh() often. Internally, the library ensures heavy operation are only performed if necessary: for example when a subscription just expired. So in 99% of cases this call will result in no-operations.

                      -

                      Consumables

                      - -

                      If the purchased products in a consumable, your app is responsible for delivering the purchase then acknowlege that you’ve done so. Delivering generally consists in increasing a counter for some sort of virtual currency.

                      - -

                      Your app can be notified of a purchase at any time. So the library asks you to provide an IAPPurchaseDelegate from initialization.

                      - -

                      In InAppPurchase.initialize(), we can pass an IAPPurchaseDelegate instance. This object implements the productPurchased(productIdentifier:) function, which is called whenever a purchase is approved.

                      - -

                      Here’s a example implementation:

                      -
                      class AppDelegate: UIResponder, UIApplicationDelegate, IAPPurchaseDelegate {
                      -  ...
                      -  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      -    InAppPurchase.initialize(
                      -      iapProducts: [...],
                      -      iapPurchaseDelegate: self, // ADDED: iapPurchaseDelegate
                      -      validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678")
                      -  }
                      -
                      -  // IAPPurchaseDelegate implementation
                      -  func productPurchased(productIdentifier: String) {
                      -    // TODO
                      -  }
                      -}
                      -
                      - -

                      It’s also important to know that when a purchase is approved, money isn’t yet to reach your bank account. You have to acknowledge delivery of the (virtual) item to finalize the transaction. That is why we have to call InAppPurchase.finishTransactions(for: productIdentifier) as soon as we delivered the product.

                      - -

                      Example

                      - -

                      Let’s define a class that adopts the IAPPurchaseDelegate protocol, it can very well be your application delegate.

                      -
                      func productPurchased(productIdentifier: String) {
                      -  switch productIdenfier {
                      -  case "10_silver":
                      -    addSilver(10)
                      -  case "100_silver":
                      -    addSilver(100)
                      -  }
                      -  InAppPurchase.finishTransactions(for: productIdentifier)
                      -  Analytics.trackEvent("purchase succeeded", productIdentifier)
                      -}
                      -
                      - -

                      Here, we implement our own unlocking logic and call InAppPurchase.finishTransactions() afterward (assuming addSilver is synchronous).

                      - -

                      Note: productPurchased is called when a purchase has been confirmed by Fovea’s receipt validator. If you have a server, he probably already has been notified of this purchase using the webhook.

                      - -

                      Reminder: Keep in mind that purchase notifications might occur even if you never called the InAppPurchase.purchase() function: purchases can be made from another device or the AppStore, they can be approved by parents when the app isn’t running, purchase flows can be interupted, etc. The pattern above ensures your app is always ready to handle purchase events.

                      -

                      Non-Renewing Subscriptions

                      - -

                      For non-renewing subscriptions, delivering consists in increasing the amount of time a user can access a given feature. Apple doesn’t manage the length and expiry of non-renewing subscriptions: you have to do this yourself, as for consumables.

                      - -

                      Basically, everything is identical to consumables.

                      -

                      Restoring purchases

                      - -

                      Except if you only sell consumable products, Apple requires that you provide a “Restore Purchases” button to your users. In general, it is found in your application settings.

                      - -

                      Call this method when this button is pressed.

                      -
                      @IBAction func restorePurchases(_ sender: Any) {
                      -  self.loaderView.show()
                      -  InAppPurchase.restorePurchases(callback: { result in
                      -      self.loaderView.hide()
                      -      switch result.state {
                      -      case .succeeded:
                      -          if result.addedPurchases > 0 {
                      -              print("Restore purchases successful.")
                      -          } else {
                      -              print("No purchase to restore.")
                      -          }
                      -      case .failed:
                      -          print("Restore purchases failed.")
                      -      }
                      -  })
                      -}
                      -
                      - -

                      The callback method is called once the operation is complete. You can use it to unlock the UI, by hiding your loader for example, and display the adapted message to the user.

                      -

                      Displaying products with purchases

                      - -

                      In your store screen, where you present your products titles and prices with a purchase button, there are some cases to handle that we skipped. Owned products and deferred purchases.

                      -

                      Owned products

                      - -

                      Non-consumables and active auto-renewing subscriptions cannot be purchased again. You should adjust your UI to reflect that state. Refer to InAppPurchase.hasActivePurchase() to and to the example later in this section.

                      -

                      Deferred purchases

                      - -

                      Apple’s Ask to Buy feature lets parents approve any purchases initiated by children, including in-app purchases.

                      - -

                      With Ask to Buy enabled, when a child requests to make a purchase, the app is notified that the purchase is awaiting the parent’s approval in the purchase callback:

                      -
                      InAppPurchase.purchase(
                      -  productIdentifier: productIdentifier,
                      -  callback: { result in
                      -    switch result.state {
                      -    case .deferred:
                      -      // Pending parent approval
                      -  }
                      -})
                      -
                      - -

                      In the deferred case, the child has been notified by StoreKit that the parents have to approve the purchase. He might then close the app and come back later. You don’t have much to do, but to display in your UI that there is a purchase waiting for parental approval in your views.

                      - -

                      We will use the hasDeferredTransaction method:

                      -
                      InAppPurchase.hasDeferredTransaction(for productIdentifier: String) -> Bool
                      -
                      -

                      Example

                      - -

                      Here’s an example that covers what has been discussed above. We will update our example refreshView function from before:

                      -
                      @objc func refreshView() {
                      -  guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else {
                      -    self.titleLabel.text = "Product unavailable"
                      -    return
                      -  }
                      -  self.titleLabel.text = product.localizedTitle
                      -  // ...
                      -
                      -  // "Ask to Buy" deferred purchase waiting for parent's approval
                      -  if InAppPurchase.hasDeferredTransaction(for: "my_product_id") {
                      -    self.statusLabel.text = "Waiting for Approval..."
                      -    self.purchaseButton.isPointerInteractionEnabled = false
                      -  }
                      -  // "Owned" product
                      -  else if InAppPurchase.hasActivePurchase(for: "my_product_id") {
                      -    self.statusLabel.text = "OWNED"
                      -    self.purchaseButton.isPointerInteractionEnabled = false
                      -  }
                      -  else {
                      -    self.purchaseButton.isPointerInteractionEnabled = true
                      -  }
                      -}
                      -
                      - -

                      When a product is owned or has a deferred purchase, we make sure the purchase button is grayed out. We also use a status label to display some details. Of course, you are free to design your UI as you see fit.

                      -

                      Errors

                      - -

                      When calling refresh(), purchase() or restorePurchases(), the callback can return an IAPError if the state is failed. -Here is the list of IAPErrorCode you can receive:

                      - -
                        -
                      • Errors returned by refresh(), purchase() or restorePurchases()

                        - -
                          -
                        • libraryNotInitialized - You must call the initialize fuction before using the library.
                        • -
                        • bundleIdentifierInvalid - The Bundle Identifier is invalid.
                        • -
                        • validatorUrlInvalid - The Validator URL String is invalid.
                        • -
                        • refreshReceiptFailed - Failed to refresh the App Store receipt.
                        • -
                        • validateReceiptFailed - Failed to validate the App Store receipt with Fovea.
                        • -
                        • readReceiptFailed - Failed to read the receipt validation.
                        • -
                      • -
                      • Errors returned by refresh()

                        - -
                          -
                        • refreshProductsFailed - Failed to refresh products from the App Store.
                        • -
                      • -
                      • Errors returned by purchase()

                        - -
                          -
                        • productNotFound - The product was not found on the App Store and cannot be purchased.
                        • -
                        • cannotMakePurchase - The user is not allowed to authorize payments.
                        • -
                        • alreadyPurchasing - A purchase is already in progress.
                        • -
                      • -
                      -

                      Analytics

                      - -

                      Tracking the purchase flow is a common things in apps. Especially as it’s core to your revenue model.

                      - -

                      We can track 5 events, which step in the purchase pipeline a user reached.

                      - -
                        -
                      1. purchase initiated
                      2. -
                      3. purchase cancelled
                      4. -
                      5. purchase failed
                      6. -
                      7. purchase deferred
                      8. -
                      9. purchase succeeded
                      10. -
                      - -

                      Here’s a quick example showing how to implement this correctly.

                      -
                      func makePurchase() {
                      -  Analytics.trackEvent("purchase initiated")
                      -  InAppPurchase.purchase(
                      -    productIdentifier: "my_product_id",
                      -    callback: { result in
                      -      switch result.state {
                      -      case .purchased:
                      -        // Reminder: We are not processing the purchase here, only updating your UI.
                      -        //           That's why we do not send an event to analytics.
                      -      case .failed:
                      -        Analytics.trackEvent("purchase failed")
                      -      case .deferred:
                      -        Analytics.trackEvent("purchase deferred")
                      -      case .cancelled:
                      -        Analytics.trackEvent("purchase cancelled")
                      -    }
                      -  })
                      -}
                      -
                      -// IAPPurchaseDelegate implementation
                      -func productPurchased(productIdentifier: String) {
                      -  Analytics.trackEvent("purchase succeeded")
                      -  InAppPurchase.finishTransactions(for: productIdentifier)
                      -}
                      -
                      - -

                      The important part to remember is that a purchase can occur outside your app (or be approved when the app is not running), that’s why tracking purchase succeeded has to be part of the productPurchased delegate function.

                      - -

                      Refer to the Consumables section to learn more about the productPurchased function.

                      -

                      Server integration

                      - -

                      In more advanced use cases, you have a server component. Users are logged in and you’ll like to unlock the content for this user on your server. The safest approach is to setup a Webhook on Fovea. You’ll receive notifications from Fovea that transaction have been processed and/or subscriptions updated.

                      - -

                      The information sent from Fovea has been verified from Apple’s server, which makes it way more trustable than information sent from your app itself.

                      - -

                      To take advantage of this, you have to inform the library of your application username. This applicationUsername can be provided as a parameter of the InAppPurchase.initialize method and updated later by changing the associated property.

                      - -

                      Example:

                      -
                      InAppPurchase.initialize(
                      -  iapProducts: [...],
                      -  validatorUrlString: "..."),
                      -  applicationUsername: UserSession.getUserId())
                      -
                      -// later ...
                      -InAppPurchase.applicationUsername = UserSession.getUserId()
                      -
                      - -

                      If a user account is mandatory in your app, you will want to delay calls to InAppPurchase.initialize() to when your user’s session is ready.

                      - -

                      Do not hesitate to contact Fovea for help.

                      -

                      Xcode Demo Project

                      - -

                      Do not hesitate to check the demo project available on here: iap-swift-lib-demo.

                      -

                      References

                      - - -

                      Coding

                      - -

                      Generate the documentation, using this fork of swift-doc (on --minimum-access-level is part of the main distrib).

                      -
                      swift-doc generate sources --module-name InAppPurchase --format html --output docs --minimum-access-level public --base-url /iap-swift-lib/
                      -
                      -

                      Troubleshooting

                      - -

                      Common issues are covered here: https://github.com/iridescent-dev/iap-swift-lib/wiki/Troubleshooting

                      -

                      License

                      - -

                      InAppPurchaseLib is open-sourced library licensed under the MIT License. See LICENSE for details.

                      - -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/search.json b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/search.json deleted file mode 100644 index df4266d..0000000 --- a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/Documents/search.json +++ /dev/null @@ -1 +0,0 @@ -{"Typealiases.html#/s:16InAppPurchaseLib19IAPPurchaseCallbacka":{"name":"IAPPurchaseCallback","abstract":"

                      Undocumented

                      "},"Typealiases.html#/s:16InAppPurchaseLib18IAPRefreshCallbacka":{"name":"IAPRefreshCallback","abstract":"

                      Undocumented

                      "},"Structs/IAPProduct.html#/s:16InAppPurchaseLib10IAPProductV17productIdentifierSSvp":{"name":"productIdentifier","abstract":"

                      The identifier of the product.

                      ","parent_name":"IAPProduct"},"Structs/IAPProduct.html#/s:16InAppPurchaseLib10IAPProductV11productTypeAA0eG0Ovp":{"name":"productType","abstract":"

                      The type of the product.

                      ","parent_name":"IAPProduct"},"Structs/IAPProduct.html#/s:16InAppPurchaseLib10IAPProductV17productIdentifier0F4TypeACSS_AA0eH0Otcfc":{"name":"init(productIdentifier:productType:)","abstract":"

                      Initializes an IAPProduct with its identifier and type.

                      ","parent_name":"IAPProduct"},"Structs/IAPError.html#/s:16InAppPurchaseLib8IAPErrorV4codeAA0E4CodeOvp":{"name":"code","abstract":"

                      Undocumented

                      ","parent_name":"IAPError"},"Structs/IAPError.html#/s:16InAppPurchaseLib8IAPErrorV20localizedDescriptionSSvp":{"name":"localizedDescription","abstract":"

                      Undocumented

                      ","parent_name":"IAPError"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV5stateAA0eF5StateOvp":{"name":"state","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV8iapErrorAA8IAPErrorVSgvp":{"name":"iapError","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV14addedPurchasesSivp":{"name":"addedPurchases","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV16updatedPurchasesSivp":{"name":"updatedPurchases","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV5stateAA0eF5StateOvp":{"name":"state","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV8iapErrorAA8IAPErrorVSgvp":{"name":"iapError","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV7skErrorSC11SKErrorCodeLeVSgvp":{"name":"skError","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV20localizedDescriptionSSSgvp":{"name":"localizedDescription","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html":{"name":"IAPPurchaseResult","abstract":"

                      Undocumented

                      "},"Structs/IAPRefreshResult.html":{"name":"IAPRefreshResult","abstract":"

                      Undocumented

                      "},"Structs/IAPError.html":{"name":"IAPError","abstract":"

                      Undocumented

                      "},"Structs/IAPProduct.html":{"name":"IAPProduct","abstract":"

                      Undocumented

                      "},"Protocols/IAPPurchaseDelegate.html#/s:16InAppPurchaseLib19IAPPurchaseDelegateP16productPurchased0G10IdentifierySS_tF":{"name":"productPurchased(productIdentifier:)","abstract":"

                      Called when a product is newly purchased, updated or restored.

                      ","parent_name":"IAPPurchaseDelegate"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP11iapProductsSayAA10IAPProductVGvpZ":{"name":"iapProducts","abstract":"

                      The array of IAPProduct.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP18validatorUrlStringSSSgvpZ":{"name":"validatorUrlString","abstract":"

                      The validator url retrieved from Fovea.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP03iapC8DelegateAA011IAPPurchaseF0_pSgvpZ":{"name":"iapPurchaseDelegate","abstract":"

                      The instance of class that adopts the IAPPurchaseDelegate protocol.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP19applicationUsernameSSSgvpZ":{"name":"applicationUsername","abstract":"

                      The user name, if your app implements user login.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP10initialize11iapProducts18validatorUrlString0fC8Delegate19applicationUsernameySayAA10IAPProductVG_SSAA011IAPPurchaseK0_pSSSgtFZ":{"name":"initialize(iapProducts:validatorUrlString:iapPurchaseDelegate:applicationUsername:)","abstract":"

                      Start observing the payment queue, as soon as possible, and refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP4stopyyFZ":{"name":"stop()","abstract":"

                      Stop observing the payment queue, when the application will terminate, for proper cleanup.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP7refresh8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"refresh(callback:)","abstract":"

                      Refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP11getProductsSaySo9SKProductCGyFZ":{"name":"getProducts()","abstract":"

                      Gets all products retrieved from the App Store

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP12getProductBy10identifierSo9SKProductCSgSS_tFZ":{"name":"getProductBy(identifier:)","abstract":"

                      Gets the product by its identifier from the list of products retrieved from the App Store.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP15canMakePaymentsSbyFZ":{"name":"canMakePayments()","abstract":"

                      Checks if the user is allowed to authorize payments.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP8purchase17productIdentifier8quantity8callbackySS_SiyAA17IAPPurchaseResultVctFZ":{"name":"purchase(productIdentifier:quantity:callback:)","abstract":"

                      Request a Payment from the App Store.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP16restorePurchases8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"restorePurchases(callback:)","abstract":"

                      Restore purchased products.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP18finishTransactions3forySS_tFZ":{"name":"finishTransactions(for:)","abstract":"

                      Finish all transactions for the product.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP22hasDeferredTransaction3forSbSS_tFZ":{"name":"hasDeferredTransaction(for:)","abstract":"

                      Checks if the last transaction state for a given product was deferred.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP19hasAlreadyPurchasedSbyFZ":{"name":"hasAlreadyPurchased()","abstract":"

                      Checks if the user has already purchased at least one product.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP09hasActiveC03forSbSS_tFZ":{"name":"hasActivePurchase(for:)","abstract":"

                      Checks if the user currently own (or is subscribed to) a given product (nonConsumable or autoRenewableSubscription).

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP21hasActiveSubscriptionSbyFZ":{"name":"hasActiveSubscription()","abstract":"

                      Checks if the user has an active auto renewable subscription regardless of the product identifier.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP03getC4Date3for10Foundation0F0VSgSS_tFZ":{"name":"getPurchaseDate(for:)","abstract":"

                      Returns the latest purchased date for a given product.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP13getExpiryDate3for10Foundation0G0VSgSS_tFZ":{"name":"getExpiryDate(for:)","abstract":"

                      Returns the expiry date for a subcription. May be past or future.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/IAPErrorProtocol.html#/s:16InAppPurchaseLib16IAPErrorProtocolP4codeAA0E4CodeOvp":{"name":"code","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorProtocol"},"Protocols/IAPErrorProtocol.html":{"name":"IAPErrorProtocol","abstract":"

                      Undocumented

                      "},"Protocols/InAppPurchaseLib.html":{"name":"InAppPurchaseLib","abstract":"

                      The protocol that InAppPurchase` adopts.

                      "},"Protocols/IAPPurchaseDelegate.html":{"name":"IAPPurchaseDelegate","abstract":"

                      The protocol that you must adopt if you have consumable and/or nonRenewingSubscription products.

                      "},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE21localizedPeriodFormatAC09IAPPeriodH0OvpZ":{"name":"localizedPeriodFormat","abstract":"

                      Undocumented

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE28hasIntroductoryPriceEligibleSbyF":{"name":"hasIntroductoryPriceEligible()","abstract":"

                      Checks if the product has an introductory price the user is eligible to.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE14localizedPriceSSvp":{"name":"localizedPrice","abstract":"

                      Returns a localized string with the cost of the product in the local currency.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE27localizedSubscriptionPeriodSSSgvp":{"name":"localizedSubscriptionPeriod","abstract":"

                      Returns a localized string with the period of the subscription product.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE26localizedIntroductoryPriceSSSgvp":{"name":"localizedIntroductoryPrice","abstract":"

                      Returns a localized string with the introductory price if available, in the local currency.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE27localizedIntroductoryPeriodSSSgvp":{"name":"localizedIntroductoryPeriod","abstract":"

                      Returns a localized string with the introductory price period of the subscription product.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE29localizedIntroductoryDurationSSSgvp":{"name":"localizedIntroductoryDuration","abstract":"

                      Returns a localized string with the duration of the introductory price.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html":{"name":"SKProduct"},"Enums/IAPPeriodFormat.html#/s:16InAppPurchaseLib15IAPPeriodFormatO5shortyA2CmF":{"name":"short","abstract":"

                      Undocumented

                      ","parent_name":"IAPPeriodFormat"},"Enums/IAPPeriodFormat.html#/s:16InAppPurchaseLib15IAPPeriodFormatO4longyA2CmF":{"name":"long","abstract":"

                      Undocumented

                      ","parent_name":"IAPPeriodFormat"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO10consumableyA2CmF":{"name":"consumable","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO13nonConsumableyA2CmF":{"name":"nonConsumable","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO23nonRenewingSubscriptionyA2CmF":{"name":"nonRenewingSubscription","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO25autoRenewableSubscriptionyA2CmF":{"name":"autoRenewableSubscription","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO21libraryNotInitializedyA2CmF":{"name":"libraryNotInitialized","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO15productNotFoundyA2CmF":{"name":"productNotFound","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO010cannotMakeC0yA2CmF":{"name":"cannotMakePurchase","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO17alreadyPurchasingyA2CmF":{"name":"alreadyPurchasing","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO23bundleIdentifierInvalidyA2CmF":{"name":"bundleIdentifierInvalid","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO19validatorUrlInvalidyA2CmF":{"name":"validatorUrlInvalid","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO20refreshReceiptFailedyA2CmF":{"name":"refreshReceiptFailed","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO21validateReceiptFailedyA2CmF":{"name":"validateReceiptFailed","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO17readReceiptFailedyA2CmF":{"name":"readReceiptFailed","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO21refreshProductsFailedyA2CmF":{"name":"refreshProductsFailed","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPRefreshResultState.html#/s:16InAppPurchaseLib21IAPRefreshResultStateO9succeededyA2CmF":{"name":"succeeded","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResultState"},"Enums/IAPRefreshResultState.html#/s:16InAppPurchaseLib21IAPRefreshResultStateO6failedyA2CmF":{"name":"failed","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResultState"},"Enums/IAPRefreshResultState.html#/s:16InAppPurchaseLib21IAPRefreshResultStateO7skippedyA2CmF":{"name":"skipped","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO9purchasedyA2CmF":{"name":"purchased","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO6failedyA2CmF":{"name":"failed","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO9cancelledyA2CmF":{"name":"cancelled","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO8deferredyA2CmF":{"name":"deferred","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html":{"name":"IAPPurchaseResultState","abstract":"

                      Undocumented

                      "},"Enums/IAPRefreshResultState.html":{"name":"IAPRefreshResultState","abstract":"

                      Undocumented

                      "},"Enums/IAPErrorCode.html":{"name":"IAPErrorCode","abstract":"

                      Undocumented

                      "},"Enums/IAPProductType.html":{"name":"IAPProductType","abstract":"

                      Undocumented

                      "},"Enums/IAPPeriodFormat.html":{"name":"IAPPeriodFormat","abstract":"

                      Undocumented

                      "},"Classes/DefaultPurchaseDelegate.html#/s:16InAppPurchaseLib07DefaultC8DelegateCACycfc":{"name":"init()","abstract":"

                      Undocumented

                      ","parent_name":"DefaultPurchaseDelegate"},"Classes/DefaultPurchaseDelegate.html#/s:16InAppPurchaseLib07DefaultC8DelegateC16productPurchased0G10IdentifierySS_tF":{"name":"productPurchased(productIdentifier:)","abstract":"

                      Finish the product transactions when a product is newly purchased, updated or restored.

                      ","parent_name":"DefaultPurchaseDelegate"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C11iapProductsSayAA10IAPProductVGvpZ":{"name":"iapProducts","abstract":"

                      The array of IAPProduct.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C18validatorUrlStringSSSgvpZ":{"name":"validatorUrlString","abstract":"

                      The validator url retrieved from Fovea.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C03iapC8DelegateAA011IAPPurchaseF0_pSgvpZ":{"name":"iapPurchaseDelegate","abstract":"

                      The instance of class that adopts the IAPPurchaseDelegate protocol.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C19applicationUsernameSSSgvpZ":{"name":"applicationUsername","abstract":"

                      The user name, if your app implements user login.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C10initialize11iapProducts18validatorUrlString0fC8Delegate19applicationUsernameySayAA10IAPProductVG_SSAA011IAPPurchaseK0_pSSSgtFZ":{"name":"initialize(iapProducts:validatorUrlString:iapPurchaseDelegate:applicationUsername:)","abstract":"

                      Start observing the payment queue, as soon as possible, and refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C4stopyyFZ":{"name":"stop()","abstract":"

                      Stop observing the payment queue, when the application will terminate, for proper cleanup.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C7refresh8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"refresh(callback:)","abstract":"

                      Refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C11getProductsSaySo9SKProductCGyFZ":{"name":"getProducts()","abstract":"

                      Gets all products retrieved from the App Store

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C12getProductBy10identifierSo9SKProductCSgSS_tFZ":{"name":"getProductBy(identifier:)","abstract":"

                      Gets the product by its identifier from the list of products retrieved from the App Store.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C15canMakePaymentsSbyFZ":{"name":"canMakePayments()","abstract":"

                      Checks if the user is allowed to authorize payments.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C8purchase17productIdentifier8quantity8callbackySS_SiyAA17IAPPurchaseResultVctFZ":{"name":"purchase(productIdentifier:quantity:callback:)","abstract":"

                      Request a Payment from the App Store.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C16restorePurchases8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"restorePurchases(callback:)","abstract":"

                      Restore purchased products.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C18finishTransactions3forySS_tFZ":{"name":"finishTransactions(for:)","abstract":"

                      Finish all transactions for the product.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C22hasDeferredTransaction3forSbSS_tFZ":{"name":"hasDeferredTransaction(for:)","abstract":"

                      Checks if the last transaction state for a given product was deferred.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C19hasAlreadyPurchasedSbyFZ":{"name":"hasAlreadyPurchased()","abstract":"

                      Checks if the user has already purchased at least one product.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C09hasActiveC03forSbSS_tFZ":{"name":"hasActivePurchase(for:)","abstract":"

                      Checks if the user currently own (or is subscribed to) a given product (nonConsumable or autoRenewableSubscription).

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C21hasActiveSubscriptionSbyFZ":{"name":"hasActiveSubscription()","abstract":"

                      Checks if the user has an active auto renewable subscription regardless of the product identifier.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C03getC4Date3for10Foundation0F0VSgSS_tFZ":{"name":"getPurchaseDate(for:)","abstract":"

                      Returns the latest purchased date for a given product.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C13getExpiryDate3for10Foundation0G0VSgSS_tFZ":{"name":"getExpiryDate(for:)","abstract":"

                      Returns the expiry date for a subcription. May be past or future.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html":{"name":"InAppPurchase","abstract":"

                      Undocumented

                      "},"Classes/DefaultPurchaseDelegate.html":{"name":"DefaultPurchaseDelegate","abstract":"

                      The default implementation of IAPPurchaseDelegate if no other is provided.

                      "},"Classes.html":{"name":"Classes","abstract":"

                      The following classes are available globally.

                      "},"Enums.html":{"name":"Enumerations","abstract":"

                      The following enumerations are available globally.

                      "},"Extensions.html":{"name":"Extensions","abstract":"

                      The following extensions are available globally.

                      "},"Protocols.html":{"name":"Protocols","abstract":"

                      The following protocols are available globally.

                      "},"Structs.html":{"name":"Structures","abstract":"

                      The following structures are available globally.

                      "},"Typealiases.html":{"name":"Type Aliases","abstract":"

                      The following type aliases are available globally.

                      "}} \ No newline at end of file diff --git a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/docSet.dsidx b/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/docSet.dsidx deleted file mode 100644 index cf3069f..0000000 Binary files a/docs/jazzy/docsets/InAppPurchaseLib.docset/Contents/Resources/docSet.dsidx and /dev/null differ diff --git a/docs/jazzy/docsets/InAppPurchaseLib.tgz b/docs/jazzy/docsets/InAppPurchaseLib.tgz deleted file mode 100644 index 1579f81..0000000 Binary files a/docs/jazzy/docsets/InAppPurchaseLib.tgz and /dev/null differ diff --git a/docs/jazzy/index.html b/docs/jazzy/index.html deleted file mode 100644 index e633951..0000000 --- a/docs/jazzy/index.html +++ /dev/null @@ -1,699 +0,0 @@ - - - - InAppPurchaseLib Reference - - - - - - - - - -
                      -
                      -

                      InAppPurchaseLib (52% documented)

                      -

                      View on GitHub

                      -
                      -
                      -
                      - -
                      -
                      - -
                      -
                      -
                      - -

                      - -

                      - -
                      -

                      An easy-to-use library for In-App Purchases, using Fovea.Billing for receipts validation.

                      -
                      - - -

                      Features

                      - -
                        -
                      • ✅ Purchase a product
                      • -
                      • ✅ Restore purchased products
                      • -
                      • ✅ Verify transactions with the App Store on Fovea.Billing server
                      • -
                      • ✅ Handle and notify payment transaction states
                      • -
                      • ✅ Retreive products information from the App Store
                      • -
                      • ✅ Support all product types (consumable, non-consumable, auto-renewable subscription, non-renewing subscription)
                      • -
                      • ✅ Status of purchases available when offline
                      • -
                      • ✅ Server integration with a Webhook
                      • -
                      -

                      Getting Started

                      - -

                      If you haven’t already, I highly recommend your read the Overview and Preparing section of Apple’s In-App Purchase official documentation

                      -

                      Requirements

                      - -
                        -
                      • Configure your App and Xcode to support In-App Purchases. - -
                      • -
                      • Create and configure your Fovea.Billing project account: - -
                          -
                        • Set your bundle ID
                        • -
                        • The iOS Shared Secret (or shared key) is to be retrieved from AppStoreConnect
                        • -
                        • The iOS Subscription Status URL (only if you want subscriptions)
                        • -
                      • -
                      -

                      Installation

                      - -

                      - -

                      - -
                        -
                      • Select your project in Xcode
                      • -
                      • Go to the section Swift Package
                      • -
                      • Click on (+) Add Package Dependency
                      • -
                      • Copy the Git URL: https://github.com/iridescent-dev/iap-swift-lib.git
                      • -
                      • Click on Next > Next
                      • -
                      • Make sure your project is selected in Add to target
                      • -
                      • Click on Finish
                      • -
                      - -

                      Note: You have to import InAppPurchaseLib wherever you use the library.

                      -

                      Usage

                      - -

                      The process of implementing in-app purchases involves several steps:

                      - -
                        -
                      1. Displaying the list of purchasable products
                      2. -
                      3. Initiating a purchase
                      4. -
                      5. Delivering and finalizing a purchase
                      6. -
                      7. Checking the current ownership of non-consumables and subscriptions
                      8. -
                      9. Implementing the Restore Purchases button
                      10. -
                      -

                      Initialization

                      - -

                      Before everything else the library must be initialized. This has to happen as soon as possible. A good way is to call the InAppPurchase.initialize() method when the application did finish launching. In the background, this will load your products and refresh the status of purchases and subscriptions.

                      - -

                      InAppPurchase.initialize() accepts the following arguments:

                      - -
                        -
                      • iapProducts - An array of IAPProduct (REQUIRED)
                      • -
                      • validatorUrlString - The validator url retrieved from Fovea (REQUIRED)
                      • -
                      • applicationUsername - The user name, if your app implements user login (optional)
                      • -
                      - -

                      Each IAPProduct contains the following fields:

                      - -
                        -
                      • productIdentifier - The product unique identifier
                      • -
                      • productType - The IAPProductType (consumable, nonConsumable, nonRenewingSubscription or autoRenewableSubscription)
                      • -
                      - -

                      Example:

                      - -

                      A good place is generally in your application delegate’s didFinishLaunchingWithOptions function, like below:

                      -
                      import InAppPurchaseLib
                      -
                      -class AppDelegate: UIResponder, UIApplicationDelegate, IAPPurchaseDelegate {
                      -  ...
                      -  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      -    InAppPurchase.initialize(
                      -      iapProducts: [
                      -        IAPProduct(productIdentifier: "monthly_plan", productType: .autoRenewableSubscription),
                      -        IAPProduct(productIdentifier: "yearly_plan",  productType: .autoRenewableSubscription),
                      -        IAPProduct(productIdentifier: "disable_ads",  productType: .nonConsumable)
                      -      ],
                      -      validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678")
                      -  }
                      -
                      -  func productPurchased(productIdentifier: String) {
                      -    // ... process purchase (we'll see that later)
                      -  }
                      -}
                      -
                      - -

                      You should also call the stop method when the application will terminate, for proper cleanup.

                      -
                        func applicationWillTerminate(_ application: UIApplication) {
                      -    InAppPurchase.stop()
                      -  }
                      -
                      - -

                      For more advanced use cases, in particular when you have implemented user login, you’ll have to make some adjustments. We’ll learn more about this in the Server integration section.

                      - -

                      Tip: If initialization was successful, you should see a new receipt validation event in Fovea’s Dashboard.

                      -

                      Displaying products

                      - -

                      Let’s start with the simplest case: you have a single product.

                      - -

                      You can retrieve all information about this product using the function InAppPurchase.getProductBy(identifier: "my_product_id"). This returns an SKProduct extended with helpful methods.

                      - -

                      Those are the most important:

                      - -
                        -
                      • productIdentifier: String - The string that identifies the product to the Apple AppStore.
                      • -
                      • localizedTitle: String - The name of the product, in the language of the device, as retrieved from the AppStore.
                      • -
                      • localizedDescription: String - A description of the product, in the language of the device, as retrieved from the AppStore.
                      • -
                      • localizedPrice: String - The cost of the product in the local currency (read-only property added by this library).
                      • -
                      - -

                      Example:

                      - -

                      You can add a function similar to this to your view.

                      -
                      @objc func refreshView() {
                      -  guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else {
                      -    self.titleLabel.text = "Product unavailable"
                      -    return
                      -  }
                      -  self.titleLabel.text = product.localizedTitle
                      -  self.descriptionLabel.text = product.localizedDescription
                      -  self.priceLabel.text = product.localizedPrice
                      -}
                      -
                      - -

                      This example assumes self.titleLabel is a UILabel, etc.

                      - -

                      Make sure to call this function when the view appears on screen, for instance by calling it from viewWillAppear.

                      -
                      override func viewWillAppear(_ animated: Bool) {
                      -  self.refreshView()
                      -}
                      -
                      -

                      Displaying subscriptions

                      - -

                      For subscription products, you also have some data about subscription periods and introductory offers.

                      - -
                        -
                      • func hasIntroductoryPriceEligible() -> Bool - The product has an introductory price the user is eligible to.
                      • -
                      • localizedSubscriptionPeriod: String? - The period of the subscription.
                      • -
                      • localizedIntroductoryPrice: String? - The cost of the introductory offer if available in the local currency.
                      • -
                      • localizedIntroductoryPeriod: String? - The subscription period of the introductory offer.
                      • -
                      • localizedIntroductoryDuration: String? - The duration of the introductory offer.
                      • -
                      - -

                      Example

                      -
                      @objc func refreshView() {
                      -  guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else {
                      -    self.titleLabel.text = "Product unavailable"
                      -    return
                      -  }
                      -  self.titleLabel.text = product.localizedTitle
                      -  self.descriptionLabel.text = product.localizedDescription
                      -
                      -  // Format price text. Example: "0,99€ / month for 3 months (then 3,99 € / month)"
                      -  var priceText = "\(product.localizedPrice) / \(product.localizedSubscriptionPeriod!)"
                      -  if product.hasIntroductoryPriceEligible() {
                      -      if product.introductoryPrice!.numberOfPeriods == 1 {
                      -          priceText = "\(product.localizedIntroductoryPrice!) for \(product.localizedIntroductoryDuration!)" +
                      -          " (then \(priceText))"
                      -      } else {
                      -          priceText = "\(product.localizedIntroductoryPrice!) / \(product.localizedIntroductoryPeriod!)" +
                      -          " for \(product.localizedIntroductoryDuration!) (then \(priceText))"
                      -      }
                      -  }
                      -  self.priceLabel.text = priceText
                      -}
                      -
                      - -

                      Note: You have to import StoreKit wherever you use SKProduct.

                      -

                      Refreshing

                      - -

                      Data might change or not be yet available when your “product” view is presented. In order to properly handle those cases, you should refresh your view after refreshing in-app products metadata. You want to be sure you’re displaying up-to-date information.

                      - -

                      To achieve this, call InAppPurchase.refresh() when your view is presented.

                      -
                      override func viewWillAppear(_ animated: Bool) {
                      -  self.refreshView()
                      -  InAppPurchase.refresh(callback: { _ in
                      -      self.refreshView()
                      -  })
                      -}
                      -
                      -

                      Purchasing

                      - -

                      The purchase process is generally a little bit more involving than most people would expect. Why is it not just: purchase → on success unlock the feature?

                      - -

                      Several reasons:

                      - -
                        -
                      • In-app purchases can be initiated outside the app
                      • -
                      • In-app purchases can be deferred, pending parental approval
                      • -
                      • Apple wants to be sure you delivered the product before charging the user
                      • -
                      - -

                      That is why the process looks like so:

                      - -
                        -
                      • being ready to handle purchase events from app startup
                      • -
                      • finalizing transactions when product delivery is complete
                      • -
                      • sending purchase request, for which successful doesn’t always mean complete
                      • -
                      -

                      Initiating a purchase

                      - -

                      To initiate a purchase, use the InAppPurchase.purchase() function. It takes the productIdentifier and a callback function, called when the purchase has been processed.

                      - -

                      Important: Do not process the purchase here, we’ll handle that later!

                      - -

                      From this callback, you can for example unlock the UI by hiding your loading indicator and display a message to the user.

                      - -

                      Example:

                      -
                      self.loaderView.show()
                      -InAppPurchase.purchase(
                      -  productIdentifier: "my_product_id",
                      -  callback: { _ in
                      -    self.loaderView.hide()
                      -})
                      -
                      - -

                      This simple example locks the UI with a loader when the purchase is in progress. We’ll see later how the purchase has to be processed by your applicaiton.

                      - -

                      The callback also gives more information about the outcome of the purchase, you might want to use it to update your UI as well. Note that some events are useful for analytics. So here’s a more complete example.

                      -
                      self.loaderView.show()
                      -InAppPurchase.purchase(
                      -  productIdentifier: "my_product_id",
                      -  callback: { result in
                      -    self.loaderView.hide()
                      -
                      -    switch result.state {
                      -    case .purchased:
                      -      // Product successfully purchased
                      -      // Reminder: Do not process the purchase here, only update your UI.
                      -      //           that's why we do not send data to analytics.
                      -      openThankYouScreen()
                      -    case .failed:
                      -      // Purchase failed
                      -      // - Human formated reason can be found in result.localizedDescription
                      -      // - More details in either result.skError or result.iapError
                      -      showError(result.localizedDescription)
                      -    case .deferred:
                      -      // The purchase is deferred, waiting for the parent's approval
                      -      openWaitingParentApprovalScreen()
                      -    case .cancelled:
                      -      // The user canceled the request, generally only useful for analytics.
                      -  }
                      -})
                      -
                      - -

                      If the purchase fails, result will contain either .skError, a SKError from StoreKit, or .iapError, an IAPError.

                      - -

                      Tip: After a successful purchase, you should see a new transaction in Fovea’s dashboard.

                      -

                      Handling purchases

                      - -

                      Finally, the magic happened: a user purchased one of your products! Let’s see how we handle the different types of products.

                      -

                      Non-Consumables

                      - -

                      Wherever your app needs to know if a non-consumable product has been purchased, use InAppPurchase.hasActivePurchase(for: -productIdentifier). This will return true if the user currently owns the product.

                      - -

                      Note: The last known state for the user’s purchases is stored as UserDefaults. As such, their status is always available to your app, even when offline.

                      - -

                      If you have a server that needs to know about the purchase. You should rely on Fovea’s webhook instead of doing anything in here. We will see that later in the Server integration section.

                      -

                      Auto-Renewable Subscriptions

                      - -

                      As with non-consumables, you will use InAppPurchase.hasActivePurchase(for: productIdentifier) to check if the user is an active subscriber to a given product.

                      - -

                      You might also like to call refresh regularly, for example when entering your main view. When appropriate, the library will refresh the receipt to detect subscription renewals or expiry.

                      - -

                      As we’ve seend in the Refreshing section:

                      -
                      override func viewWillAppear(_ animated: Bool) {
                      -  self.refreshView()
                      -  InAppPurchase.refresh(callback: { _ in
                      -      self.refreshView()
                      -  })
                      -}
                      -
                      - -

                      Note: Don’t be reluctant to call refresh() often. Internally, the library ensures heavy operation are only performed if necessary: for example when a subscription just expired. So in 99% of cases this call will result in no-operations.

                      -

                      Consumables

                      - -

                      If the purchased products in a consumable, your app is responsible for delivering the purchase then acknowlege that you’ve done so. Delivering generally consists in increasing a counter for some sort of virtual currency.

                      - -

                      Your app can be notified of a purchase at any time. So the library asks you to provide an IAPPurchaseDelegate from initialization.

                      - -

                      In InAppPurchase.initialize(), we can pass an IAPPurchaseDelegate instance. This object implements the productPurchased(productIdentifier:) function, which is called whenever a purchase is approved.

                      - -

                      Here’s a example implementation:

                      -
                      class AppDelegate: UIResponder, UIApplicationDelegate, IAPPurchaseDelegate {
                      -  ...
                      -  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      -    InAppPurchase.initialize(
                      -      iapProducts: [...],
                      -      iapPurchaseDelegate: self, // ADDED: iapPurchaseDelegate
                      -      validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678")
                      -  }
                      -
                      -  // IAPPurchaseDelegate implementation
                      -  func productPurchased(productIdentifier: String) {
                      -    // TODO
                      -  }
                      -}
                      -
                      - -

                      It’s also important to know that when a purchase is approved, money isn’t yet to reach your bank account. You have to acknowledge delivery of the (virtual) item to finalize the transaction. That is why we have to call InAppPurchase.finishTransactions(for: productIdentifier) as soon as we delivered the product.

                      - -

                      Example

                      - -

                      Let’s define a class that adopts the IAPPurchaseDelegate protocol, it can very well be your application delegate.

                      -
                      func productPurchased(productIdentifier: String) {
                      -  switch productIdenfier {
                      -  case "10_silver":
                      -    addSilver(10)
                      -  case "100_silver":
                      -    addSilver(100)
                      -  }
                      -  InAppPurchase.finishTransactions(for: productIdentifier)
                      -  Analytics.trackEvent("purchase succeeded", productIdentifier)
                      -}
                      -
                      - -

                      Here, we implement our own unlocking logic and call InAppPurchase.finishTransactions() afterward (assuming addSilver is synchronous).

                      - -

                      Note: productPurchased is called when a purchase has been confirmed by Fovea’s receipt validator. If you have a server, he probably already has been notified of this purchase using the webhook.

                      - -

                      Reminder: Keep in mind that purchase notifications might occur even if you never called the InAppPurchase.purchase() function: purchases can be made from another device or the AppStore, they can be approved by parents when the app isn’t running, purchase flows can be interupted, etc. The pattern above ensures your app is always ready to handle purchase events.

                      -

                      Non-Renewing Subscriptions

                      - -

                      For non-renewing subscriptions, delivering consists in increasing the amount of time a user can access a given feature. Apple doesn’t manage the length and expiry of non-renewing subscriptions: you have to do this yourself, as for consumables.

                      - -

                      Basically, everything is identical to consumables.

                      -

                      Restoring purchases

                      - -

                      Except if you only sell consumable products, Apple requires that you provide a “Restore Purchases” button to your users. In general, it is found in your application settings.

                      - -

                      Call this method when this button is pressed.

                      -
                      @IBAction func restorePurchases(_ sender: Any) {
                      -  self.loaderView.show()
                      -  InAppPurchase.restorePurchases(callback: { result in
                      -      self.loaderView.hide()
                      -      switch result.state {
                      -      case .succeeded:
                      -          if result.addedPurchases > 0 {
                      -              print("Restore purchases successful.")
                      -          } else {
                      -              print("No purchase to restore.")
                      -          }
                      -      case .failed:
                      -          print("Restore purchases failed.")
                      -      }
                      -  })
                      -}
                      -
                      - -

                      The callback method is called once the operation is complete. You can use it to unlock the UI, by hiding your loader for example, and display the adapted message to the user.

                      -

                      Displaying products with purchases

                      - -

                      In your store screen, where you present your products titles and prices with a purchase button, there are some cases to handle that we skipped. Owned products and deferred purchases.

                      -

                      Owned products

                      - -

                      Non-consumables and active auto-renewing subscriptions cannot be purchased again. You should adjust your UI to reflect that state. Refer to InAppPurchase.hasActivePurchase() to and to the example later in this section.

                      -

                      Deferred purchases

                      - -

                      Apple’s Ask to Buy feature lets parents approve any purchases initiated by children, including in-app purchases.

                      - -

                      With Ask to Buy enabled, when a child requests to make a purchase, the app is notified that the purchase is awaiting the parent’s approval in the purchase callback:

                      -
                      InAppPurchase.purchase(
                      -  productIdentifier: productIdentifier,
                      -  callback: { result in
                      -    switch result.state {
                      -    case .deferred:
                      -      // Pending parent approval
                      -  }
                      -})
                      -
                      - -

                      In the deferred case, the child has been notified by StoreKit that the parents have to approve the purchase. He might then close the app and come back later. You don’t have much to do, but to display in your UI that there is a purchase waiting for parental approval in your views.

                      - -

                      We will use the hasDeferredTransaction method:

                      -
                      InAppPurchase.hasDeferredTransaction(for productIdentifier: String) -> Bool
                      -
                      -

                      Example

                      - -

                      Here’s an example that covers what has been discussed above. We will update our example refreshView function from before:

                      -
                      @objc func refreshView() {
                      -  guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product_id") else {
                      -    self.titleLabel.text = "Product unavailable"
                      -    return
                      -  }
                      -  self.titleLabel.text = product.localizedTitle
                      -  // ...
                      -
                      -  // "Ask to Buy" deferred purchase waiting for parent's approval
                      -  if InAppPurchase.hasDeferredTransaction(for: "my_product_id") {
                      -    self.statusLabel.text = "Waiting for Approval..."
                      -    self.purchaseButton.isPointerInteractionEnabled = false
                      -  }
                      -  // "Owned" product
                      -  else if InAppPurchase.hasActivePurchase(for: "my_product_id") {
                      -    self.statusLabel.text = "OWNED"
                      -    self.purchaseButton.isPointerInteractionEnabled = false
                      -  }
                      -  else {
                      -    self.purchaseButton.isPointerInteractionEnabled = true
                      -  }
                      -}
                      -
                      - -

                      When a product is owned or has a deferred purchase, we make sure the purchase button is grayed out. We also use a status label to display some details. Of course, you are free to design your UI as you see fit.

                      -

                      Errors

                      - -

                      When calling refresh(), purchase() or restorePurchases(), the callback can return an IAPError if the state is failed. -Here is the list of IAPErrorCode you can receive:

                      - -
                        -
                      • Errors returned by refresh(), purchase() or restorePurchases()

                        - -
                          -
                        • libraryNotInitialized - You must call the initialize fuction before using the library.
                        • -
                        • bundleIdentifierInvalid - The Bundle Identifier is invalid.
                        • -
                        • validatorUrlInvalid - The Validator URL String is invalid.
                        • -
                        • refreshReceiptFailed - Failed to refresh the App Store receipt.
                        • -
                        • validateReceiptFailed - Failed to validate the App Store receipt with Fovea.
                        • -
                        • readReceiptFailed - Failed to read the receipt validation.
                        • -
                      • -
                      • Errors returned by refresh()

                        - -
                          -
                        • refreshProductsFailed - Failed to refresh products from the App Store.
                        • -
                      • -
                      • Errors returned by purchase()

                        - -
                          -
                        • productNotFound - The product was not found on the App Store and cannot be purchased.
                        • -
                        • cannotMakePurchase - The user is not allowed to authorize payments.
                        • -
                        • alreadyPurchasing - A purchase is already in progress.
                        • -
                      • -
                      -

                      Analytics

                      - -

                      Tracking the purchase flow is a common things in apps. Especially as it’s core to your revenue model.

                      - -

                      We can track 5 events, which step in the purchase pipeline a user reached.

                      - -
                        -
                      1. purchase initiated
                      2. -
                      3. purchase cancelled
                      4. -
                      5. purchase failed
                      6. -
                      7. purchase deferred
                      8. -
                      9. purchase succeeded
                      10. -
                      - -

                      Here’s a quick example showing how to implement this correctly.

                      -
                      func makePurchase() {
                      -  Analytics.trackEvent("purchase initiated")
                      -  InAppPurchase.purchase(
                      -    productIdentifier: "my_product_id",
                      -    callback: { result in
                      -      switch result.state {
                      -      case .purchased:
                      -        // Reminder: We are not processing the purchase here, only updating your UI.
                      -        //           That's why we do not send an event to analytics.
                      -      case .failed:
                      -        Analytics.trackEvent("purchase failed")
                      -      case .deferred:
                      -        Analytics.trackEvent("purchase deferred")
                      -      case .cancelled:
                      -        Analytics.trackEvent("purchase cancelled")
                      -    }
                      -  })
                      -}
                      -
                      -// IAPPurchaseDelegate implementation
                      -func productPurchased(productIdentifier: String) {
                      -  Analytics.trackEvent("purchase succeeded")
                      -  InAppPurchase.finishTransactions(for: productIdentifier)
                      -}
                      -
                      - -

                      The important part to remember is that a purchase can occur outside your app (or be approved when the app is not running), that’s why tracking purchase succeeded has to be part of the productPurchased delegate function.

                      - -

                      Refer to the Consumables section to learn more about the productPurchased function.

                      -

                      Server integration

                      - -

                      In more advanced use cases, you have a server component. Users are logged in and you’ll like to unlock the content for this user on your server. The safest approach is to setup a Webhook on Fovea. You’ll receive notifications from Fovea that transaction have been processed and/or subscriptions updated.

                      - -

                      The information sent from Fovea has been verified from Apple’s server, which makes it way more trustable than information sent from your app itself.

                      - -

                      To take advantage of this, you have to inform the library of your application username. This applicationUsername can be provided as a parameter of the InAppPurchase.initialize method and updated later by changing the associated property.

                      - -

                      Example:

                      -
                      InAppPurchase.initialize(
                      -  iapProducts: [...],
                      -  validatorUrlString: "..."),
                      -  applicationUsername: UserSession.getUserId())
                      -
                      -// later ...
                      -InAppPurchase.applicationUsername = UserSession.getUserId()
                      -
                      - -

                      If a user account is mandatory in your app, you will want to delay calls to InAppPurchase.initialize() to when your user’s session is ready.

                      - -

                      Do not hesitate to contact Fovea for help.

                      -

                      Xcode Demo Project

                      - -

                      Do not hesitate to check the demo project available on here: iap-swift-lib-demo.

                      -

                      References

                      - - -

                      Coding

                      - -

                      Generate the documentation, using this fork of swift-doc (on --minimum-access-level is part of the main distrib).

                      -
                      swift-doc generate sources --module-name InAppPurchase --format html --output docs --minimum-access-level public --base-url /iap-swift-lib/
                      -
                      -

                      Troubleshooting

                      - -

                      Common issues are covered here: https://github.com/iridescent-dev/iap-swift-lib/wiki/Troubleshooting

                      -

                      License

                      - -

                      InAppPurchaseLib is open-sourced library licensed under the MIT License. See LICENSE for details.

                      - -
                      -
                      - -
                      -
                      - - - diff --git a/docs/jazzy/search.json b/docs/jazzy/search.json deleted file mode 100644 index df4266d..0000000 --- a/docs/jazzy/search.json +++ /dev/null @@ -1 +0,0 @@ -{"Typealiases.html#/s:16InAppPurchaseLib19IAPPurchaseCallbacka":{"name":"IAPPurchaseCallback","abstract":"

                      Undocumented

                      "},"Typealiases.html#/s:16InAppPurchaseLib18IAPRefreshCallbacka":{"name":"IAPRefreshCallback","abstract":"

                      Undocumented

                      "},"Structs/IAPProduct.html#/s:16InAppPurchaseLib10IAPProductV17productIdentifierSSvp":{"name":"productIdentifier","abstract":"

                      The identifier of the product.

                      ","parent_name":"IAPProduct"},"Structs/IAPProduct.html#/s:16InAppPurchaseLib10IAPProductV11productTypeAA0eG0Ovp":{"name":"productType","abstract":"

                      The type of the product.

                      ","parent_name":"IAPProduct"},"Structs/IAPProduct.html#/s:16InAppPurchaseLib10IAPProductV17productIdentifier0F4TypeACSS_AA0eH0Otcfc":{"name":"init(productIdentifier:productType:)","abstract":"

                      Initializes an IAPProduct with its identifier and type.

                      ","parent_name":"IAPProduct"},"Structs/IAPError.html#/s:16InAppPurchaseLib8IAPErrorV4codeAA0E4CodeOvp":{"name":"code","abstract":"

                      Undocumented

                      ","parent_name":"IAPError"},"Structs/IAPError.html#/s:16InAppPurchaseLib8IAPErrorV20localizedDescriptionSSvp":{"name":"localizedDescription","abstract":"

                      Undocumented

                      ","parent_name":"IAPError"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV5stateAA0eF5StateOvp":{"name":"state","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV8iapErrorAA8IAPErrorVSgvp":{"name":"iapError","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV14addedPurchasesSivp":{"name":"addedPurchases","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV16updatedPurchasesSivp":{"name":"updatedPurchases","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV5stateAA0eF5StateOvp":{"name":"state","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV8iapErrorAA8IAPErrorVSgvp":{"name":"iapError","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV7skErrorSC11SKErrorCodeLeVSgvp":{"name":"skError","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV20localizedDescriptionSSSgvp":{"name":"localizedDescription","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html":{"name":"IAPPurchaseResult","abstract":"

                      Undocumented

                      "},"Structs/IAPRefreshResult.html":{"name":"IAPRefreshResult","abstract":"

                      Undocumented

                      "},"Structs/IAPError.html":{"name":"IAPError","abstract":"

                      Undocumented

                      "},"Structs/IAPProduct.html":{"name":"IAPProduct","abstract":"

                      Undocumented

                      "},"Protocols/IAPPurchaseDelegate.html#/s:16InAppPurchaseLib19IAPPurchaseDelegateP16productPurchased0G10IdentifierySS_tF":{"name":"productPurchased(productIdentifier:)","abstract":"

                      Called when a product is newly purchased, updated or restored.

                      ","parent_name":"IAPPurchaseDelegate"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP11iapProductsSayAA10IAPProductVGvpZ":{"name":"iapProducts","abstract":"

                      The array of IAPProduct.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP18validatorUrlStringSSSgvpZ":{"name":"validatorUrlString","abstract":"

                      The validator url retrieved from Fovea.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP03iapC8DelegateAA011IAPPurchaseF0_pSgvpZ":{"name":"iapPurchaseDelegate","abstract":"

                      The instance of class that adopts the IAPPurchaseDelegate protocol.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP19applicationUsernameSSSgvpZ":{"name":"applicationUsername","abstract":"

                      The user name, if your app implements user login.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP10initialize11iapProducts18validatorUrlString0fC8Delegate19applicationUsernameySayAA10IAPProductVG_SSAA011IAPPurchaseK0_pSSSgtFZ":{"name":"initialize(iapProducts:validatorUrlString:iapPurchaseDelegate:applicationUsername:)","abstract":"

                      Start observing the payment queue, as soon as possible, and refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP4stopyyFZ":{"name":"stop()","abstract":"

                      Stop observing the payment queue, when the application will terminate, for proper cleanup.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP7refresh8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"refresh(callback:)","abstract":"

                      Refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP11getProductsSaySo9SKProductCGyFZ":{"name":"getProducts()","abstract":"

                      Gets all products retrieved from the App Store

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP12getProductBy10identifierSo9SKProductCSgSS_tFZ":{"name":"getProductBy(identifier:)","abstract":"

                      Gets the product by its identifier from the list of products retrieved from the App Store.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP15canMakePaymentsSbyFZ":{"name":"canMakePayments()","abstract":"

                      Checks if the user is allowed to authorize payments.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP8purchase17productIdentifier8quantity8callbackySS_SiyAA17IAPPurchaseResultVctFZ":{"name":"purchase(productIdentifier:quantity:callback:)","abstract":"

                      Request a Payment from the App Store.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP16restorePurchases8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"restorePurchases(callback:)","abstract":"

                      Restore purchased products.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP18finishTransactions3forySS_tFZ":{"name":"finishTransactions(for:)","abstract":"

                      Finish all transactions for the product.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP22hasDeferredTransaction3forSbSS_tFZ":{"name":"hasDeferredTransaction(for:)","abstract":"

                      Checks if the last transaction state for a given product was deferred.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP19hasAlreadyPurchasedSbyFZ":{"name":"hasAlreadyPurchased()","abstract":"

                      Checks if the user has already purchased at least one product.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP09hasActiveC03forSbSS_tFZ":{"name":"hasActivePurchase(for:)","abstract":"

                      Checks if the user currently own (or is subscribed to) a given product (nonConsumable or autoRenewableSubscription).

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP21hasActiveSubscriptionSbyFZ":{"name":"hasActiveSubscription()","abstract":"

                      Checks if the user has an active auto renewable subscription regardless of the product identifier.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP03getC4Date3for10Foundation0F0VSgSS_tFZ":{"name":"getPurchaseDate(for:)","abstract":"

                      Returns the latest purchased date for a given product.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP13getExpiryDate3for10Foundation0G0VSgSS_tFZ":{"name":"getExpiryDate(for:)","abstract":"

                      Returns the expiry date for a subcription. May be past or future.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/IAPErrorProtocol.html#/s:16InAppPurchaseLib16IAPErrorProtocolP4codeAA0E4CodeOvp":{"name":"code","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorProtocol"},"Protocols/IAPErrorProtocol.html":{"name":"IAPErrorProtocol","abstract":"

                      Undocumented

                      "},"Protocols/InAppPurchaseLib.html":{"name":"InAppPurchaseLib","abstract":"

                      The protocol that InAppPurchase` adopts.

                      "},"Protocols/IAPPurchaseDelegate.html":{"name":"IAPPurchaseDelegate","abstract":"

                      The protocol that you must adopt if you have consumable and/or nonRenewingSubscription products.

                      "},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE21localizedPeriodFormatAC09IAPPeriodH0OvpZ":{"name":"localizedPeriodFormat","abstract":"

                      Undocumented

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE28hasIntroductoryPriceEligibleSbyF":{"name":"hasIntroductoryPriceEligible()","abstract":"

                      Checks if the product has an introductory price the user is eligible to.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE14localizedPriceSSvp":{"name":"localizedPrice","abstract":"

                      Returns a localized string with the cost of the product in the local currency.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE27localizedSubscriptionPeriodSSSgvp":{"name":"localizedSubscriptionPeriod","abstract":"

                      Returns a localized string with the period of the subscription product.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE26localizedIntroductoryPriceSSSgvp":{"name":"localizedIntroductoryPrice","abstract":"

                      Returns a localized string with the introductory price if available, in the local currency.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE27localizedIntroductoryPeriodSSSgvp":{"name":"localizedIntroductoryPeriod","abstract":"

                      Returns a localized string with the introductory price period of the subscription product.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE29localizedIntroductoryDurationSSSgvp":{"name":"localizedIntroductoryDuration","abstract":"

                      Returns a localized string with the duration of the introductory price.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html":{"name":"SKProduct"},"Enums/IAPPeriodFormat.html#/s:16InAppPurchaseLib15IAPPeriodFormatO5shortyA2CmF":{"name":"short","abstract":"

                      Undocumented

                      ","parent_name":"IAPPeriodFormat"},"Enums/IAPPeriodFormat.html#/s:16InAppPurchaseLib15IAPPeriodFormatO4longyA2CmF":{"name":"long","abstract":"

                      Undocumented

                      ","parent_name":"IAPPeriodFormat"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO10consumableyA2CmF":{"name":"consumable","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO13nonConsumableyA2CmF":{"name":"nonConsumable","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO23nonRenewingSubscriptionyA2CmF":{"name":"nonRenewingSubscription","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO25autoRenewableSubscriptionyA2CmF":{"name":"autoRenewableSubscription","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO21libraryNotInitializedyA2CmF":{"name":"libraryNotInitialized","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO15productNotFoundyA2CmF":{"name":"productNotFound","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO010cannotMakeC0yA2CmF":{"name":"cannotMakePurchase","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO17alreadyPurchasingyA2CmF":{"name":"alreadyPurchasing","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO23bundleIdentifierInvalidyA2CmF":{"name":"bundleIdentifierInvalid","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO19validatorUrlInvalidyA2CmF":{"name":"validatorUrlInvalid","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO20refreshReceiptFailedyA2CmF":{"name":"refreshReceiptFailed","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO21validateReceiptFailedyA2CmF":{"name":"validateReceiptFailed","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO17readReceiptFailedyA2CmF":{"name":"readReceiptFailed","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO21refreshProductsFailedyA2CmF":{"name":"refreshProductsFailed","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorCode"},"Enums/IAPRefreshResultState.html#/s:16InAppPurchaseLib21IAPRefreshResultStateO9succeededyA2CmF":{"name":"succeeded","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResultState"},"Enums/IAPRefreshResultState.html#/s:16InAppPurchaseLib21IAPRefreshResultStateO6failedyA2CmF":{"name":"failed","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResultState"},"Enums/IAPRefreshResultState.html#/s:16InAppPurchaseLib21IAPRefreshResultStateO7skippedyA2CmF":{"name":"skipped","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO9purchasedyA2CmF":{"name":"purchased","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO6failedyA2CmF":{"name":"failed","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO9cancelledyA2CmF":{"name":"cancelled","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO8deferredyA2CmF":{"name":"deferred","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html":{"name":"IAPPurchaseResultState","abstract":"

                      Undocumented

                      "},"Enums/IAPRefreshResultState.html":{"name":"IAPRefreshResultState","abstract":"

                      Undocumented

                      "},"Enums/IAPErrorCode.html":{"name":"IAPErrorCode","abstract":"

                      Undocumented

                      "},"Enums/IAPProductType.html":{"name":"IAPProductType","abstract":"

                      Undocumented

                      "},"Enums/IAPPeriodFormat.html":{"name":"IAPPeriodFormat","abstract":"

                      Undocumented

                      "},"Classes/DefaultPurchaseDelegate.html#/s:16InAppPurchaseLib07DefaultC8DelegateCACycfc":{"name":"init()","abstract":"

                      Undocumented

                      ","parent_name":"DefaultPurchaseDelegate"},"Classes/DefaultPurchaseDelegate.html#/s:16InAppPurchaseLib07DefaultC8DelegateC16productPurchased0G10IdentifierySS_tF":{"name":"productPurchased(productIdentifier:)","abstract":"

                      Finish the product transactions when a product is newly purchased, updated or restored.

                      ","parent_name":"DefaultPurchaseDelegate"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C11iapProductsSayAA10IAPProductVGvpZ":{"name":"iapProducts","abstract":"

                      The array of IAPProduct.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C18validatorUrlStringSSSgvpZ":{"name":"validatorUrlString","abstract":"

                      The validator url retrieved from Fovea.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C03iapC8DelegateAA011IAPPurchaseF0_pSgvpZ":{"name":"iapPurchaseDelegate","abstract":"

                      The instance of class that adopts the IAPPurchaseDelegate protocol.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C19applicationUsernameSSSgvpZ":{"name":"applicationUsername","abstract":"

                      The user name, if your app implements user login.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C10initialize11iapProducts18validatorUrlString0fC8Delegate19applicationUsernameySayAA10IAPProductVG_SSAA011IAPPurchaseK0_pSSSgtFZ":{"name":"initialize(iapProducts:validatorUrlString:iapPurchaseDelegate:applicationUsername:)","abstract":"

                      Start observing the payment queue, as soon as possible, and refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C4stopyyFZ":{"name":"stop()","abstract":"

                      Stop observing the payment queue, when the application will terminate, for proper cleanup.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C7refresh8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"refresh(callback:)","abstract":"

                      Refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C11getProductsSaySo9SKProductCGyFZ":{"name":"getProducts()","abstract":"

                      Gets all products retrieved from the App Store

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C12getProductBy10identifierSo9SKProductCSgSS_tFZ":{"name":"getProductBy(identifier:)","abstract":"

                      Gets the product by its identifier from the list of products retrieved from the App Store.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C15canMakePaymentsSbyFZ":{"name":"canMakePayments()","abstract":"

                      Checks if the user is allowed to authorize payments.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C8purchase17productIdentifier8quantity8callbackySS_SiyAA17IAPPurchaseResultVctFZ":{"name":"purchase(productIdentifier:quantity:callback:)","abstract":"

                      Request a Payment from the App Store.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C16restorePurchases8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"restorePurchases(callback:)","abstract":"

                      Restore purchased products.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C18finishTransactions3forySS_tFZ":{"name":"finishTransactions(for:)","abstract":"

                      Finish all transactions for the product.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C22hasDeferredTransaction3forSbSS_tFZ":{"name":"hasDeferredTransaction(for:)","abstract":"

                      Checks if the last transaction state for a given product was deferred.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C19hasAlreadyPurchasedSbyFZ":{"name":"hasAlreadyPurchased()","abstract":"

                      Checks if the user has already purchased at least one product.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C09hasActiveC03forSbSS_tFZ":{"name":"hasActivePurchase(for:)","abstract":"

                      Checks if the user currently own (or is subscribed to) a given product (nonConsumable or autoRenewableSubscription).

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C21hasActiveSubscriptionSbyFZ":{"name":"hasActiveSubscription()","abstract":"

                      Checks if the user has an active auto renewable subscription regardless of the product identifier.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C03getC4Date3for10Foundation0F0VSgSS_tFZ":{"name":"getPurchaseDate(for:)","abstract":"

                      Returns the latest purchased date for a given product.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C13getExpiryDate3for10Foundation0G0VSgSS_tFZ":{"name":"getExpiryDate(for:)","abstract":"

                      Returns the expiry date for a subcription. May be past or future.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html":{"name":"InAppPurchase","abstract":"

                      Undocumented

                      "},"Classes/DefaultPurchaseDelegate.html":{"name":"DefaultPurchaseDelegate","abstract":"

                      The default implementation of IAPPurchaseDelegate if no other is provided.

                      "},"Classes.html":{"name":"Classes","abstract":"

                      The following classes are available globally.

                      "},"Enums.html":{"name":"Enumerations","abstract":"

                      The following enumerations are available globally.

                      "},"Extensions.html":{"name":"Extensions","abstract":"

                      The following extensions are available globally.

                      "},"Protocols.html":{"name":"Protocols","abstract":"

                      The following protocols are available globally.

                      "},"Structs.html":{"name":"Structures","abstract":"

                      The following structures are available globally.

                      "},"Typealiases.html":{"name":"Type Aliases","abstract":"

                      The following type aliases are available globally.

                      "}} \ No newline at end of file diff --git a/docs/jazzy/undocumented.json b/docs/jazzy/undocumented.json deleted file mode 100644 index e44d55a..0000000 --- a/docs/jazzy/undocumented.json +++ /dev/null @@ -1,348 +0,0 @@ -{ - "warnings": [ - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 12, - "symbol": "IAPPurchaseCallback", - "symbol_kind": "source.lang.swift.decl.typealias", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 13, - "symbol": "IAPPurchaseResult", - "symbol_kind": "source.lang.swift.decl.struct", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 14, - "symbol": "IAPPurchaseResult.state", - "symbol_kind": "source.lang.swift.decl.var.instance", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 15, - "symbol": "IAPPurchaseResult.iapError", - "symbol_kind": "source.lang.swift.decl.var.instance", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 16, - "symbol": "IAPPurchaseResult.skError", - "symbol_kind": "source.lang.swift.decl.var.instance", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 18, - "symbol": "IAPPurchaseResult.localizedDescription", - "symbol_kind": "source.lang.swift.decl.var.instance", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 25, - "symbol": "IAPPurchaseResultState", - "symbol_kind": "source.lang.swift.decl.enum", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 26, - "symbol": "IAPPurchaseResultState.purchased", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 27, - "symbol": "IAPPurchaseResultState.failed", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 28, - "symbol": "IAPPurchaseResultState.cancelled", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 29, - "symbol": "IAPPurchaseResultState.deferred", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 33, - "symbol": "IAPRefreshCallback", - "symbol_kind": "source.lang.swift.decl.typealias", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 34, - "symbol": "IAPRefreshResult", - "symbol_kind": "source.lang.swift.decl.struct", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 35, - "symbol": "IAPRefreshResult.state", - "symbol_kind": "source.lang.swift.decl.var.instance", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 36, - "symbol": "IAPRefreshResult.iapError", - "symbol_kind": "source.lang.swift.decl.var.instance", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 37, - "symbol": "IAPRefreshResult.addedPurchases", - "symbol_kind": "source.lang.swift.decl.var.instance", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 38, - "symbol": "IAPRefreshResult.updatedPurchases", - "symbol_kind": "source.lang.swift.decl.var.instance", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 41, - "symbol": "IAPRefreshResultState", - "symbol_kind": "source.lang.swift.decl.enum", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 42, - "symbol": "IAPRefreshResultState.succeeded", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 43, - "symbol": "IAPRefreshResultState.failed", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", - "line": 44, - "symbol": "IAPRefreshResultState.skipped", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 11, - "symbol": "IAPErrorProtocol", - "symbol_kind": "source.lang.swift.decl.protocol", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 12, - "symbol": "IAPErrorProtocol.code", - "symbol_kind": "source.lang.swift.decl.var.instance", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 15, - "symbol": "IAPErrorCode", - "symbol_kind": "source.lang.swift.decl.enum", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 16, - "symbol": "IAPErrorCode.libraryNotInitialized", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 17, - "symbol": "IAPErrorCode.productNotFound", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 18, - "symbol": "IAPErrorCode.cannotMakePurchase", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 19, - "symbol": "IAPErrorCode.alreadyPurchasing", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 21, - "symbol": "IAPErrorCode.bundleIdentifierInvalid", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 22, - "symbol": "IAPErrorCode.validatorUrlInvalid", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 23, - "symbol": "IAPErrorCode.refreshReceiptFailed", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 24, - "symbol": "IAPErrorCode.validateReceiptFailed", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 25, - "symbol": "IAPErrorCode.readReceiptFailed", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 27, - "symbol": "IAPErrorCode.refreshProductsFailed", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 30, - "symbol": "IAPError", - "symbol_kind": "source.lang.swift.decl.struct", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 31, - "symbol": "IAPError.code", - "symbol_kind": "source.lang.swift.decl.var.instance", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", - "line": 32, - "symbol": "IAPError.localizedDescription", - "symbol_kind": "source.lang.swift.decl.var.instance", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/InAppPurchase.swift", - "line": 12, - "symbol": "InAppPurchase", - "symbol_kind": "source.lang.swift.decl.class", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/InAppPurchaseLib.swift", - "line": 132, - "symbol": "DefaultPurchaseDelegate.init()", - "symbol_kind": "source.lang.swift.decl.function.method.instance", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/IAPProduct.swift", - "line": 11, - "symbol": "IAPProduct", - "symbol_kind": "source.lang.swift.decl.struct", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/IAPProduct.swift", - "line": 31, - "symbol": "IAPProductType", - "symbol_kind": "source.lang.swift.decl.enum", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/IAPProduct.swift", - "line": 32, - "symbol": "IAPProductType.consumable", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/IAPProduct.swift", - "line": 33, - "symbol": "IAPProductType.nonConsumable", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/IAPProduct.swift", - "line": 34, - "symbol": "IAPProductType.nonRenewingSubscription", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/IAPProduct.swift", - "line": 35, - "symbol": "IAPProductType.autoRenewableSubscription", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/SKProductExtension.swift", - "line": 12, - "symbol": "IAPPeriodFormat", - "symbol_kind": "source.lang.swift.decl.enum", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/SKProductExtension.swift", - "line": 13, - "symbol": "IAPPeriodFormat.short", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/SKProductExtension.swift", - "line": 14, - "symbol": "IAPPeriodFormat.long", - "symbol_kind": "source.lang.swift.decl.enumelement", - "warning": "undocumented" - }, - { - "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/SKProductExtension.swift", - "line": 20, - "symbol": "SKProduct.localizedPeriodFormat", - "symbol_kind": "source.lang.swift.decl.var.static", - "warning": "undocumented" - } - ], - "source_directory": "/Users/veronique/Documents/iap-swift-lib" -} \ No newline at end of file diff --git a/docs/jazzy/js/jazzy.js b/docs/js/jazzy.js similarity index 100% rename from docs/jazzy/js/jazzy.js rename to docs/js/jazzy.js diff --git a/docs/js/jazzy.search.js b/docs/js/jazzy.search.js new file mode 100644 index 0000000..e3d1ab9 --- /dev/null +++ b/docs/js/jazzy.search.js @@ -0,0 +1,70 @@ +$(function(){ + var $typeahead = $('[data-typeahead]'); + var $form = $typeahead.parents('form'); + var searchURL = $form.attr('action'); + + function displayTemplate(result) { + return result.name; + } + + function suggestionTemplate(result) { + var t = '
                      '; + t += '' + result.name + ''; + if (result.parent_name) { + t += '' + result.parent_name + ''; + } + t += '
                      '; + return t; + } + + $typeahead.one('focus', function() { + $form.addClass('loading'); + + $.getJSON(searchURL).then(function(searchData) { + const searchIndex = lunr(function() { + this.ref('url'); + this.field('name'); + this.field('abstract'); + for (const [url, doc] of Object.entries(searchData)) { + this.add({url: url, name: doc.name, abstract: doc.abstract}); + } + }); + + $typeahead.typeahead( + { + highlight: true, + minLength: 3, + autoselect: true + }, + { + limit: 10, + display: displayTemplate, + templates: { suggestion: suggestionTemplate }, + source: function(query, sync) { + const lcSearch = query.toLowerCase(); + const results = searchIndex.query(function(q) { + q.term(lcSearch, { boost: 100 }); + q.term(lcSearch, { + boost: 10, + wildcard: lunr.Query.wildcard.TRAILING + }); + }).map(function(result) { + var doc = searchData[result.ref]; + doc.url = result.ref; + return doc; + }); + sync(results); + } + } + ); + $form.removeClass('loading'); + $typeahead.trigger('focus'); + }); + }); + + var baseURL = searchURL.slice(0, -"search.json".length); + + $typeahead.on('typeahead:select', function(e, result) { + window.location = baseURL + result.url; + }); +}); diff --git a/docs/jazzy/js/jquery.min.js b/docs/js/jquery.min.js similarity index 100% rename from docs/jazzy/js/jquery.min.js rename to docs/js/jquery.min.js diff --git a/docs/js/lunr.min.js b/docs/js/lunr.min.js new file mode 100644 index 0000000..f45a81e --- /dev/null +++ b/docs/js/lunr.min.js @@ -0,0 +1 @@ +!function(){var t,l,c,e,r,h,d,f,p,y,m,g,x,v,w,Q,k,S,E,L,b,P,T,O,I,i,n,s,z=function(e){var t=new z.Builder;return t.pipeline.add(z.trimmer,z.stopWordFilter,z.stemmer),t.searchPipeline.add(z.stemmer),e.call(t,t),t.build()};z.version="2.3.5",z.utils={},z.utils.warn=(t=this,function(e){t.console&&console.warn&&console.warn(e)}),z.utils.asString=function(e){return null==e?"":e.toString()},z.utils.clone=function(e){if(null==e)return e;for(var t=Object.create(null),r=Object.keys(e),i=0;i=this.length)return z.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},z.QueryLexer.prototype.width=function(){return this.pos-this.start},z.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},z.QueryLexer.prototype.backup=function(){this.pos-=1},z.QueryLexer.prototype.acceptDigitRun=function(){for(var e,t;47<(t=(e=this.next()).charCodeAt(0))&&t<58;);e!=z.QueryLexer.EOS&&this.backup()},z.QueryLexer.prototype.more=function(){return this.pos', + menu: '
                      ' + }; + } + function buildSelectors(classes) { + var selectors = {}; + _.each(classes, function(v, k) { + selectors[k] = "." + v; + }); + return selectors; + } + function buildCss() { + var css = { + wrapper: { + position: "relative", + display: "inline-block" + }, + hint: { + position: "absolute", + top: "0", + left: "0", + borderColor: "transparent", + boxShadow: "none", + opacity: "1" + }, + input: { + position: "relative", + verticalAlign: "top", + backgroundColor: "transparent" + }, + inputWithNoHint: { + position: "relative", + verticalAlign: "top" + }, + menu: { + position: "absolute", + top: "100%", + left: "0", + zIndex: "100", + display: "none" + }, + ltr: { + left: "0", + right: "auto" + }, + rtl: { + left: "auto", + right: " 0" + } + }; + if (_.isMsie()) { + _.mixin(css.input, { + backgroundImage: "url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)" + }); + } + return css; + } + }(); + var EventBus = function() { + "use strict"; + var namespace, deprecationMap; + namespace = "typeahead:"; + deprecationMap = { + render: "rendered", + cursorchange: "cursorchanged", + select: "selected", + autocomplete: "autocompleted" + }; + function EventBus(o) { + if (!o || !o.el) { + $.error("EventBus initialized without el"); + } + this.$el = $(o.el); + } + _.mixin(EventBus.prototype, { + _trigger: function(type, args) { + var $e = $.Event(namespace + type); + this.$el.trigger.call(this.$el, $e, args || []); + return $e; + }, + before: function(type) { + var args, $e; + args = [].slice.call(arguments, 1); + $e = this._trigger("before" + type, args); + return $e.isDefaultPrevented(); + }, + trigger: function(type) { + var deprecatedType; + this._trigger(type, [].slice.call(arguments, 1)); + if (deprecatedType = deprecationMap[type]) { + this._trigger(deprecatedType, [].slice.call(arguments, 1)); + } + } + }); + return EventBus; + }(); + var EventEmitter = function() { + "use strict"; + var splitter = /\s+/, nextTick = getNextTick(); + return { + onSync: onSync, + onAsync: onAsync, + off: off, + trigger: trigger + }; + function on(method, types, cb, context) { + var type; + if (!cb) { + return this; + } + types = types.split(splitter); + cb = context ? bindContext(cb, context) : cb; + this._callbacks = this._callbacks || {}; + while (type = types.shift()) { + this._callbacks[type] = this._callbacks[type] || { + sync: [], + async: [] + }; + this._callbacks[type][method].push(cb); + } + return this; + } + function onAsync(types, cb, context) { + return on.call(this, "async", types, cb, context); + } + function onSync(types, cb, context) { + return on.call(this, "sync", types, cb, context); + } + function off(types) { + var type; + if (!this._callbacks) { + return this; + } + types = types.split(splitter); + while (type = types.shift()) { + delete this._callbacks[type]; + } + return this; + } + function trigger(types) { + var type, callbacks, args, syncFlush, asyncFlush; + if (!this._callbacks) { + return this; + } + types = types.split(splitter); + args = [].slice.call(arguments, 1); + while ((type = types.shift()) && (callbacks = this._callbacks[type])) { + syncFlush = getFlush(callbacks.sync, this, [ type ].concat(args)); + asyncFlush = getFlush(callbacks.async, this, [ type ].concat(args)); + syncFlush() && nextTick(asyncFlush); + } + return this; + } + function getFlush(callbacks, context, args) { + return flush; + function flush() { + var cancelled; + for (var i = 0, len = callbacks.length; !cancelled && i < len; i += 1) { + cancelled = callbacks[i].apply(context, args) === false; + } + return !cancelled; + } + } + function getNextTick() { + var nextTickFn; + if (window.setImmediate) { + nextTickFn = function nextTickSetImmediate(fn) { + setImmediate(function() { + fn(); + }); + }; + } else { + nextTickFn = function nextTickSetTimeout(fn) { + setTimeout(function() { + fn(); + }, 0); + }; + } + return nextTickFn; + } + function bindContext(fn, context) { + return fn.bind ? fn.bind(context) : function() { + fn.apply(context, [].slice.call(arguments, 0)); + }; + } + }(); + var highlight = function(doc) { + "use strict"; + var defaults = { + node: null, + pattern: null, + tagName: "strong", + className: null, + wordsOnly: false, + caseSensitive: false, + diacriticInsensitive: false + }; + var accented = { + A: "[AaªÀ-Åà-åĀ-ąǍǎȀ-ȃȦȧᴬᵃḀḁẚẠ-ảₐ℀℁℻⒜Ⓐⓐ㍱-㍴㎀-㎄㎈㎉㎩-㎯㏂㏊㏟㏿Aa]", + B: "[BbᴮᵇḂ-ḇℬ⒝Ⓑⓑ㍴㎅-㎇㏃㏈㏔㏝Bb]", + C: "[CcÇçĆ-čᶜ℀ℂ℃℅℆ℭⅭⅽ⒞Ⓒⓒ㍶㎈㎉㎝㎠㎤㏄-㏇Cc]", + D: "[DdĎďDŽ-džDZ-dzᴰᵈḊ-ḓⅅⅆⅮⅾ⒟Ⓓⓓ㋏㍲㍷-㍹㎗㎭-㎯㏅㏈Dd]", + E: "[EeÈ-Ëè-ëĒ-ěȄ-ȇȨȩᴱᵉḘ-ḛẸ-ẽₑ℡ℯℰⅇ⒠Ⓔⓔ㉐㋍㋎Ee]", + F: "[FfᶠḞḟ℉ℱ℻⒡Ⓕⓕ㎊-㎌㎙ff-fflFf]", + G: "[GgĜ-ģǦǧǴǵᴳᵍḠḡℊ⒢Ⓖⓖ㋌㋍㎇㎍-㎏㎓㎬㏆㏉㏒㏿Gg]", + H: "[HhĤĥȞȟʰᴴḢ-ḫẖℋ-ℎ⒣Ⓗⓗ㋌㍱㎐-㎔㏊㏋㏗Hh]", + I: "[IiÌ-Ïì-ïĨ-İIJijǏǐȈ-ȋᴵᵢḬḭỈ-ịⁱℐℑℹⅈⅠ-ⅣⅥ-ⅨⅪⅫⅰ-ⅳⅵ-ⅸⅺⅻ⒤Ⓘⓘ㍺㏌㏕fiffiIi]", + J: "[JjIJ-ĵLJ-njǰʲᴶⅉ⒥ⒿⓙⱼJj]", + K: "[KkĶķǨǩᴷᵏḰ-ḵK⒦Ⓚⓚ㎄㎅㎉㎏㎑㎘㎞㎢㎦㎪㎸㎾㏀㏆㏍-㏏Kk]", + L: "[LlĹ-ŀLJ-ljˡᴸḶḷḺ-ḽℒℓ℡Ⅼⅼ⒧Ⓛⓛ㋏㎈㎉㏐-㏓㏕㏖㏿flfflLl]", + M: "[MmᴹᵐḾ-ṃ℠™ℳⅯⅿ⒨Ⓜⓜ㍷-㍹㎃㎆㎎㎒㎖㎙-㎨㎫㎳㎷㎹㎽㎿㏁㏂㏎㏐㏔-㏖㏘㏙㏞㏟Mm]", + N: "[NnÑñŃ-ʼnNJ-njǸǹᴺṄ-ṋⁿℕ№⒩Ⓝⓝ㎁㎋㎚㎱㎵㎻㏌㏑Nn]", + O: "[OoºÒ-Öò-öŌ-őƠơǑǒǪǫȌ-ȏȮȯᴼᵒỌ-ỏₒ℅№ℴ⒪Ⓞⓞ㍵㏇㏒㏖Oo]", + P: "[PpᴾᵖṔ-ṗℙ⒫Ⓟⓟ㉐㍱㍶㎀㎊㎩-㎬㎰㎴㎺㏋㏗-㏚Pp]", + Q: "[Qqℚ⒬Ⓠⓠ㏃Qq]", + R: "[RrŔ-řȐ-ȓʳᴿᵣṘ-ṛṞṟ₨ℛ-ℝ⒭Ⓡⓡ㋍㍴㎭-㎯㏚㏛Rr]", + S: "[SsŚ-šſȘșˢṠ-ṣ₨℁℠⒮Ⓢⓢ㎧㎨㎮-㎳㏛㏜stSs]", + T: "[TtŢ-ťȚțᵀᵗṪ-ṱẗ℡™⒯Ⓣⓣ㉐㋏㎔㏏ſtstTt]", + U: "[UuÙ-Üù-üŨ-ųƯưǓǔȔ-ȗᵁᵘᵤṲ-ṷỤ-ủ℆⒰Ⓤⓤ㍳㍺Uu]", + V: "[VvᵛᵥṼ-ṿⅣ-Ⅷⅳ-ⅷ⒱Ⓥⓥⱽ㋎㍵㎴-㎹㏜㏞Vv]", + W: "[WwŴŵʷᵂẀ-ẉẘ⒲Ⓦⓦ㎺-㎿㏝Ww]", + X: "[XxˣẊ-ẍₓ℻Ⅸ-Ⅻⅸ-ⅻ⒳Ⓧⓧ㏓Xx]", + Y: "[YyÝýÿŶ-ŸȲȳʸẎẏẙỲ-ỹ⒴Ⓨⓨ㏉Yy]", + Z: "[ZzŹ-žDZ-dzᶻẐ-ẕℤℨ⒵Ⓩⓩ㎐-㎔Zz]" + }; + return function hightlight(o) { + var regex; + o = _.mixin({}, defaults, o); + if (!o.node || !o.pattern) { + return; + } + o.pattern = _.isArray(o.pattern) ? o.pattern : [ o.pattern ]; + regex = getRegex(o.pattern, o.caseSensitive, o.wordsOnly, o.diacriticInsensitive); + traverse(o.node, hightlightTextNode); + function hightlightTextNode(textNode) { + var match, patternNode, wrapperNode; + if (match = regex.exec(textNode.data)) { + wrapperNode = doc.createElement(o.tagName); + o.className && (wrapperNode.className = o.className); + patternNode = textNode.splitText(match.index); + patternNode.splitText(match[0].length); + wrapperNode.appendChild(patternNode.cloneNode(true)); + textNode.parentNode.replaceChild(wrapperNode, patternNode); + } + return !!match; + } + function traverse(el, hightlightTextNode) { + var childNode, TEXT_NODE_TYPE = 3; + for (var i = 0; i < el.childNodes.length; i++) { + childNode = el.childNodes[i]; + if (childNode.nodeType === TEXT_NODE_TYPE) { + i += hightlightTextNode(childNode) ? 1 : 0; + } else { + traverse(childNode, hightlightTextNode); + } + } + } + }; + function accent_replacer(chr) { + return accented[chr.toUpperCase()] || chr; + } + function getRegex(patterns, caseSensitive, wordsOnly, diacriticInsensitive) { + var escapedPatterns = [], regexStr; + for (var i = 0, len = patterns.length; i < len; i++) { + var escapedWord = _.escapeRegExChars(patterns[i]); + if (diacriticInsensitive) { + escapedWord = escapedWord.replace(/\S/g, accent_replacer); + } + escapedPatterns.push(escapedWord); + } + regexStr = wordsOnly ? "\\b(" + escapedPatterns.join("|") + ")\\b" : "(" + escapedPatterns.join("|") + ")"; + return caseSensitive ? new RegExp(regexStr) : new RegExp(regexStr, "i"); + } + }(window.document); + var Input = function() { + "use strict"; + var specialKeyCodeMap; + specialKeyCodeMap = { + 9: "tab", + 27: "esc", + 37: "left", + 39: "right", + 13: "enter", + 38: "up", + 40: "down" + }; + function Input(o, www) { + o = o || {}; + if (!o.input) { + $.error("input is missing"); + } + www.mixin(this); + this.$hint = $(o.hint); + this.$input = $(o.input); + this.$input.attr({ + "aria-activedescendant": "", + "aria-owns": this.$input.attr("id") + "_listbox", + role: "combobox", + "aria-readonly": "true", + "aria-autocomplete": "list" + }); + $(www.menu).attr("id", this.$input.attr("id") + "_listbox"); + this.query = this.$input.val(); + this.queryWhenFocused = this.hasFocus() ? this.query : null; + this.$overflowHelper = buildOverflowHelper(this.$input); + this._checkLanguageDirection(); + if (this.$hint.length === 0) { + this.setHint = this.getHint = this.clearHint = this.clearHintIfInvalid = _.noop; + } + this.onSync("cursorchange", this._updateDescendent); + } + Input.normalizeQuery = function(str) { + return _.toStr(str).replace(/^\s*/g, "").replace(/\s{2,}/g, " "); + }; + _.mixin(Input.prototype, EventEmitter, { + _onBlur: function onBlur() { + this.resetInputValue(); + this.trigger("blurred"); + }, + _onFocus: function onFocus() { + this.queryWhenFocused = this.query; + this.trigger("focused"); + }, + _onKeydown: function onKeydown($e) { + var keyName = specialKeyCodeMap[$e.which || $e.keyCode]; + this._managePreventDefault(keyName, $e); + if (keyName && this._shouldTrigger(keyName, $e)) { + this.trigger(keyName + "Keyed", $e); + } + }, + _onInput: function onInput() { + this._setQuery(this.getInputValue()); + this.clearHintIfInvalid(); + this._checkLanguageDirection(); + }, + _managePreventDefault: function managePreventDefault(keyName, $e) { + var preventDefault; + switch (keyName) { + case "up": + case "down": + preventDefault = !withModifier($e); + break; + + default: + preventDefault = false; + } + preventDefault && $e.preventDefault(); + }, + _shouldTrigger: function shouldTrigger(keyName, $e) { + var trigger; + switch (keyName) { + case "tab": + trigger = !withModifier($e); + break; + + default: + trigger = true; + } + return trigger; + }, + _checkLanguageDirection: function checkLanguageDirection() { + var dir = (this.$input.css("direction") || "ltr").toLowerCase(); + if (this.dir !== dir) { + this.dir = dir; + this.$hint.attr("dir", dir); + this.trigger("langDirChanged", dir); + } + }, + _setQuery: function setQuery(val, silent) { + var areEquivalent, hasDifferentWhitespace; + areEquivalent = areQueriesEquivalent(val, this.query); + hasDifferentWhitespace = areEquivalent ? this.query.length !== val.length : false; + this.query = val; + if (!silent && !areEquivalent) { + this.trigger("queryChanged", this.query); + } else if (!silent && hasDifferentWhitespace) { + this.trigger("whitespaceChanged", this.query); + } + }, + _updateDescendent: function updateDescendent(event, id) { + this.$input.attr("aria-activedescendant", id); + }, + bind: function() { + var that = this, onBlur, onFocus, onKeydown, onInput; + onBlur = _.bind(this._onBlur, this); + onFocus = _.bind(this._onFocus, this); + onKeydown = _.bind(this._onKeydown, this); + onInput = _.bind(this._onInput, this); + this.$input.on("blur.tt", onBlur).on("focus.tt", onFocus).on("keydown.tt", onKeydown); + if (!_.isMsie() || _.isMsie() > 9) { + this.$input.on("input.tt", onInput); + } else { + this.$input.on("keydown.tt keypress.tt cut.tt paste.tt", function($e) { + if (specialKeyCodeMap[$e.which || $e.keyCode]) { + return; + } + _.defer(_.bind(that._onInput, that, $e)); + }); + } + return this; + }, + focus: function focus() { + this.$input.focus(); + }, + blur: function blur() { + this.$input.blur(); + }, + getLangDir: function getLangDir() { + return this.dir; + }, + getQuery: function getQuery() { + return this.query || ""; + }, + setQuery: function setQuery(val, silent) { + this.setInputValue(val); + this._setQuery(val, silent); + }, + hasQueryChangedSinceLastFocus: function hasQueryChangedSinceLastFocus() { + return this.query !== this.queryWhenFocused; + }, + getInputValue: function getInputValue() { + return this.$input.val(); + }, + setInputValue: function setInputValue(value) { + this.$input.val(value); + this.clearHintIfInvalid(); + this._checkLanguageDirection(); + }, + resetInputValue: function resetInputValue() { + this.setInputValue(this.query); + }, + getHint: function getHint() { + return this.$hint.val(); + }, + setHint: function setHint(value) { + this.$hint.val(value); + }, + clearHint: function clearHint() { + this.setHint(""); + }, + clearHintIfInvalid: function clearHintIfInvalid() { + var val, hint, valIsPrefixOfHint, isValid; + val = this.getInputValue(); + hint = this.getHint(); + valIsPrefixOfHint = val !== hint && hint.indexOf(val) === 0; + isValid = val !== "" && valIsPrefixOfHint && !this.hasOverflow(); + !isValid && this.clearHint(); + }, + hasFocus: function hasFocus() { + return this.$input.is(":focus"); + }, + hasOverflow: function hasOverflow() { + var constraint = this.$input.width() - 2; + this.$overflowHelper.text(this.getInputValue()); + return this.$overflowHelper.width() >= constraint; + }, + isCursorAtEnd: function() { + var valueLength, selectionStart, range; + valueLength = this.$input.val().length; + selectionStart = this.$input[0].selectionStart; + if (_.isNumber(selectionStart)) { + return selectionStart === valueLength; + } else if (document.selection) { + range = document.selection.createRange(); + range.moveStart("character", -valueLength); + return valueLength === range.text.length; + } + return true; + }, + destroy: function destroy() { + this.$hint.off(".tt"); + this.$input.off(".tt"); + this.$overflowHelper.remove(); + this.$hint = this.$input = this.$overflowHelper = $("
                      "); + } + }); + return Input; + function buildOverflowHelper($input) { + return $('').css({ + position: "absolute", + visibility: "hidden", + whiteSpace: "pre", + fontFamily: $input.css("font-family"), + fontSize: $input.css("font-size"), + fontStyle: $input.css("font-style"), + fontVariant: $input.css("font-variant"), + fontWeight: $input.css("font-weight"), + wordSpacing: $input.css("word-spacing"), + letterSpacing: $input.css("letter-spacing"), + textIndent: $input.css("text-indent"), + textRendering: $input.css("text-rendering"), + textTransform: $input.css("text-transform") + }).insertAfter($input); + } + function areQueriesEquivalent(a, b) { + return Input.normalizeQuery(a) === Input.normalizeQuery(b); + } + function withModifier($e) { + return $e.altKey || $e.ctrlKey || $e.metaKey || $e.shiftKey; + } + }(); + var Dataset = function() { + "use strict"; + var keys, nameGenerator; + keys = { + dataset: "tt-selectable-dataset", + val: "tt-selectable-display", + obj: "tt-selectable-object" + }; + nameGenerator = _.getIdGenerator(); + function Dataset(o, www) { + o = o || {}; + o.templates = o.templates || {}; + o.templates.notFound = o.templates.notFound || o.templates.empty; + if (!o.source) { + $.error("missing source"); + } + if (!o.node) { + $.error("missing node"); + } + if (o.name && !isValidName(o.name)) { + $.error("invalid dataset name: " + o.name); + } + www.mixin(this); + this.highlight = !!o.highlight; + this.name = _.toStr(o.name || nameGenerator()); + this.limit = o.limit || 5; + this.displayFn = getDisplayFn(o.display || o.displayKey); + this.templates = getTemplates(o.templates, this.displayFn); + this.source = o.source.__ttAdapter ? o.source.__ttAdapter() : o.source; + this.async = _.isUndefined(o.async) ? this.source.length > 2 : !!o.async; + this._resetLastSuggestion(); + this.$el = $(o.node).attr("role", "presentation").addClass(this.classes.dataset).addClass(this.classes.dataset + "-" + this.name); + } + Dataset.extractData = function extractData(el) { + var $el = $(el); + if ($el.data(keys.obj)) { + return { + dataset: $el.data(keys.dataset) || "", + val: $el.data(keys.val) || "", + obj: $el.data(keys.obj) || null + }; + } + return null; + }; + _.mixin(Dataset.prototype, EventEmitter, { + _overwrite: function overwrite(query, suggestions) { + suggestions = suggestions || []; + if (suggestions.length) { + this._renderSuggestions(query, suggestions); + } else if (this.async && this.templates.pending) { + this._renderPending(query); + } else if (!this.async && this.templates.notFound) { + this._renderNotFound(query); + } else { + this._empty(); + } + this.trigger("rendered", suggestions, false, this.name); + }, + _append: function append(query, suggestions) { + suggestions = suggestions || []; + if (suggestions.length && this.$lastSuggestion.length) { + this._appendSuggestions(query, suggestions); + } else if (suggestions.length) { + this._renderSuggestions(query, suggestions); + } else if (!this.$lastSuggestion.length && this.templates.notFound) { + this._renderNotFound(query); + } + this.trigger("rendered", suggestions, true, this.name); + }, + _renderSuggestions: function renderSuggestions(query, suggestions) { + var $fragment; + $fragment = this._getSuggestionsFragment(query, suggestions); + this.$lastSuggestion = $fragment.children().last(); + this.$el.html($fragment).prepend(this._getHeader(query, suggestions)).append(this._getFooter(query, suggestions)); + }, + _appendSuggestions: function appendSuggestions(query, suggestions) { + var $fragment, $lastSuggestion; + $fragment = this._getSuggestionsFragment(query, suggestions); + $lastSuggestion = $fragment.children().last(); + this.$lastSuggestion.after($fragment); + this.$lastSuggestion = $lastSuggestion; + }, + _renderPending: function renderPending(query) { + var template = this.templates.pending; + this._resetLastSuggestion(); + template && this.$el.html(template({ + query: query, + dataset: this.name + })); + }, + _renderNotFound: function renderNotFound(query) { + var template = this.templates.notFound; + this._resetLastSuggestion(); + template && this.$el.html(template({ + query: query, + dataset: this.name + })); + }, + _empty: function empty() { + this.$el.empty(); + this._resetLastSuggestion(); + }, + _getSuggestionsFragment: function getSuggestionsFragment(query, suggestions) { + var that = this, fragment; + fragment = document.createDocumentFragment(); + _.each(suggestions, function getSuggestionNode(suggestion) { + var $el, context; + context = that._injectQuery(query, suggestion); + $el = $(that.templates.suggestion(context)).data(keys.dataset, that.name).data(keys.obj, suggestion).data(keys.val, that.displayFn(suggestion)).addClass(that.classes.suggestion + " " + that.classes.selectable); + fragment.appendChild($el[0]); + }); + this.highlight && highlight({ + className: this.classes.highlight, + node: fragment, + pattern: query + }); + return $(fragment); + }, + _getFooter: function getFooter(query, suggestions) { + return this.templates.footer ? this.templates.footer({ + query: query, + suggestions: suggestions, + dataset: this.name + }) : null; + }, + _getHeader: function getHeader(query, suggestions) { + return this.templates.header ? this.templates.header({ + query: query, + suggestions: suggestions, + dataset: this.name + }) : null; + }, + _resetLastSuggestion: function resetLastSuggestion() { + this.$lastSuggestion = $(); + }, + _injectQuery: function injectQuery(query, obj) { + return _.isObject(obj) ? _.mixin({ + _query: query + }, obj) : obj; + }, + update: function update(query) { + var that = this, canceled = false, syncCalled = false, rendered = 0; + this.cancel(); + this.cancel = function cancel() { + canceled = true; + that.cancel = $.noop; + that.async && that.trigger("asyncCanceled", query, that.name); + }; + this.source(query, sync, async); + !syncCalled && sync([]); + function sync(suggestions) { + if (syncCalled) { + return; + } + syncCalled = true; + suggestions = (suggestions || []).slice(0, that.limit); + rendered = suggestions.length; + that._overwrite(query, suggestions); + if (rendered < that.limit && that.async) { + that.trigger("asyncRequested", query, that.name); + } + } + function async(suggestions) { + suggestions = suggestions || []; + if (!canceled && rendered < that.limit) { + that.cancel = $.noop; + var idx = Math.abs(rendered - that.limit); + rendered += idx; + that._append(query, suggestions.slice(0, idx)); + that.async && that.trigger("asyncReceived", query, that.name); + } + } + }, + cancel: $.noop, + clear: function clear() { + this._empty(); + this.cancel(); + this.trigger("cleared"); + }, + isEmpty: function isEmpty() { + return this.$el.is(":empty"); + }, + destroy: function destroy() { + this.$el = $("
                      "); + } + }); + return Dataset; + function getDisplayFn(display) { + display = display || _.stringify; + return _.isFunction(display) ? display : displayFn; + function displayFn(obj) { + return obj[display]; + } + } + function getTemplates(templates, displayFn) { + return { + notFound: templates.notFound && _.templatify(templates.notFound), + pending: templates.pending && _.templatify(templates.pending), + header: templates.header && _.templatify(templates.header), + footer: templates.footer && _.templatify(templates.footer), + suggestion: templates.suggestion || suggestionTemplate + }; + function suggestionTemplate(context) { + return $('
                      ').attr("id", _.guid()).text(displayFn(context)); + } + } + function isValidName(str) { + return /^[_a-zA-Z0-9-]+$/.test(str); + } + }(); + var Menu = function() { + "use strict"; + function Menu(o, www) { + var that = this; + o = o || {}; + if (!o.node) { + $.error("node is required"); + } + www.mixin(this); + this.$node = $(o.node); + this.query = null; + this.datasets = _.map(o.datasets, initializeDataset); + function initializeDataset(oDataset) { + var node = that.$node.find(oDataset.node).first(); + oDataset.node = node.length ? node : $("
                      ").appendTo(that.$node); + return new Dataset(oDataset, www); + } + } + _.mixin(Menu.prototype, EventEmitter, { + _onSelectableClick: function onSelectableClick($e) { + this.trigger("selectableClicked", $($e.currentTarget)); + }, + _onRendered: function onRendered(type, dataset, suggestions, async) { + this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); + this.trigger("datasetRendered", dataset, suggestions, async); + }, + _onCleared: function onCleared() { + this.$node.toggleClass(this.classes.empty, this._allDatasetsEmpty()); + this.trigger("datasetCleared"); + }, + _propagate: function propagate() { + this.trigger.apply(this, arguments); + }, + _allDatasetsEmpty: function allDatasetsEmpty() { + return _.every(this.datasets, _.bind(function isDatasetEmpty(dataset) { + var isEmpty = dataset.isEmpty(); + this.$node.attr("aria-expanded", !isEmpty); + return isEmpty; + }, this)); + }, + _getSelectables: function getSelectables() { + return this.$node.find(this.selectors.selectable); + }, + _removeCursor: function _removeCursor() { + var $selectable = this.getActiveSelectable(); + $selectable && $selectable.removeClass(this.classes.cursor); + }, + _ensureVisible: function ensureVisible($el) { + var elTop, elBottom, nodeScrollTop, nodeHeight; + elTop = $el.position().top; + elBottom = elTop + $el.outerHeight(true); + nodeScrollTop = this.$node.scrollTop(); + nodeHeight = this.$node.height() + parseInt(this.$node.css("paddingTop"), 10) + parseInt(this.$node.css("paddingBottom"), 10); + if (elTop < 0) { + this.$node.scrollTop(nodeScrollTop + elTop); + } else if (nodeHeight < elBottom) { + this.$node.scrollTop(nodeScrollTop + (elBottom - nodeHeight)); + } + }, + bind: function() { + var that = this, onSelectableClick; + onSelectableClick = _.bind(this._onSelectableClick, this); + this.$node.on("click.tt", this.selectors.selectable, onSelectableClick); + this.$node.on("mouseover", this.selectors.selectable, function() { + that.setCursor($(this)); + }); + this.$node.on("mouseleave", function() { + that._removeCursor(); + }); + _.each(this.datasets, function(dataset) { + dataset.onSync("asyncRequested", that._propagate, that).onSync("asyncCanceled", that._propagate, that).onSync("asyncReceived", that._propagate, that).onSync("rendered", that._onRendered, that).onSync("cleared", that._onCleared, that); + }); + return this; + }, + isOpen: function isOpen() { + return this.$node.hasClass(this.classes.open); + }, + open: function open() { + this.$node.scrollTop(0); + this.$node.addClass(this.classes.open); + }, + close: function close() { + this.$node.attr("aria-expanded", false); + this.$node.removeClass(this.classes.open); + this._removeCursor(); + }, + setLanguageDirection: function setLanguageDirection(dir) { + this.$node.attr("dir", dir); + }, + selectableRelativeToCursor: function selectableRelativeToCursor(delta) { + var $selectables, $oldCursor, oldIndex, newIndex; + $oldCursor = this.getActiveSelectable(); + $selectables = this._getSelectables(); + oldIndex = $oldCursor ? $selectables.index($oldCursor) : -1; + newIndex = oldIndex + delta; + newIndex = (newIndex + 1) % ($selectables.length + 1) - 1; + newIndex = newIndex < -1 ? $selectables.length - 1 : newIndex; + return newIndex === -1 ? null : $selectables.eq(newIndex); + }, + setCursor: function setCursor($selectable) { + this._removeCursor(); + if ($selectable = $selectable && $selectable.first()) { + $selectable.addClass(this.classes.cursor); + this._ensureVisible($selectable); + } + }, + getSelectableData: function getSelectableData($el) { + return $el && $el.length ? Dataset.extractData($el) : null; + }, + getActiveSelectable: function getActiveSelectable() { + var $selectable = this._getSelectables().filter(this.selectors.cursor).first(); + return $selectable.length ? $selectable : null; + }, + getTopSelectable: function getTopSelectable() { + var $selectable = this._getSelectables().first(); + return $selectable.length ? $selectable : null; + }, + update: function update(query) { + var isValidUpdate = query !== this.query; + if (isValidUpdate) { + this.query = query; + _.each(this.datasets, updateDataset); + } + return isValidUpdate; + function updateDataset(dataset) { + dataset.update(query); + } + }, + empty: function empty() { + _.each(this.datasets, clearDataset); + this.query = null; + this.$node.addClass(this.classes.empty); + function clearDataset(dataset) { + dataset.clear(); + } + }, + destroy: function destroy() { + this.$node.off(".tt"); + this.$node = $("
                      "); + _.each(this.datasets, destroyDataset); + function destroyDataset(dataset) { + dataset.destroy(); + } + } + }); + return Menu; + }(); + var Status = function() { + "use strict"; + function Status(options) { + this.$el = $("", { + role: "status", + "aria-live": "polite" + }).css({ + position: "absolute", + padding: "0", + border: "0", + height: "1px", + width: "1px", + "margin-bottom": "-1px", + "margin-right": "-1px", + overflow: "hidden", + clip: "rect(0 0 0 0)", + "white-space": "nowrap" + }); + options.$input.after(this.$el); + _.each(options.menu.datasets, _.bind(function(dataset) { + if (dataset.onSync) { + dataset.onSync("rendered", _.bind(this.update, this)); + dataset.onSync("cleared", _.bind(this.cleared, this)); + } + }, this)); + } + _.mixin(Status.prototype, { + update: function update(event, suggestions) { + var length = suggestions.length; + var words; + if (length === 1) { + words = { + result: "result", + is: "is" + }; + } else { + words = { + result: "results", + is: "are" + }; + } + this.$el.text(length + " " + words.result + " " + words.is + " available, use up and down arrow keys to navigate."); + }, + cleared: function() { + this.$el.text(""); + } + }); + return Status; + }(); + var DefaultMenu = function() { + "use strict"; + var s = Menu.prototype; + function DefaultMenu() { + Menu.apply(this, [].slice.call(arguments, 0)); + } + _.mixin(DefaultMenu.prototype, Menu.prototype, { + open: function open() { + !this._allDatasetsEmpty() && this._show(); + return s.open.apply(this, [].slice.call(arguments, 0)); + }, + close: function close() { + this._hide(); + return s.close.apply(this, [].slice.call(arguments, 0)); + }, + _onRendered: function onRendered() { + if (this._allDatasetsEmpty()) { + this._hide(); + } else { + this.isOpen() && this._show(); + } + return s._onRendered.apply(this, [].slice.call(arguments, 0)); + }, + _onCleared: function onCleared() { + if (this._allDatasetsEmpty()) { + this._hide(); + } else { + this.isOpen() && this._show(); + } + return s._onCleared.apply(this, [].slice.call(arguments, 0)); + }, + setLanguageDirection: function setLanguageDirection(dir) { + this.$node.css(dir === "ltr" ? this.css.ltr : this.css.rtl); + return s.setLanguageDirection.apply(this, [].slice.call(arguments, 0)); + }, + _hide: function hide() { + this.$node.hide(); + }, + _show: function show() { + this.$node.css("display", "block"); + } + }); + return DefaultMenu; + }(); + var Typeahead = function() { + "use strict"; + function Typeahead(o, www) { + var onFocused, onBlurred, onEnterKeyed, onTabKeyed, onEscKeyed, onUpKeyed, onDownKeyed, onLeftKeyed, onRightKeyed, onQueryChanged, onWhitespaceChanged; + o = o || {}; + if (!o.input) { + $.error("missing input"); + } + if (!o.menu) { + $.error("missing menu"); + } + if (!o.eventBus) { + $.error("missing event bus"); + } + www.mixin(this); + this.eventBus = o.eventBus; + this.minLength = _.isNumber(o.minLength) ? o.minLength : 1; + this.input = o.input; + this.menu = o.menu; + this.enabled = true; + this.autoselect = !!o.autoselect; + this.active = false; + this.input.hasFocus() && this.activate(); + this.dir = this.input.getLangDir(); + this._hacks(); + this.menu.bind().onSync("selectableClicked", this._onSelectableClicked, this).onSync("asyncRequested", this._onAsyncRequested, this).onSync("asyncCanceled", this._onAsyncCanceled, this).onSync("asyncReceived", this._onAsyncReceived, this).onSync("datasetRendered", this._onDatasetRendered, this).onSync("datasetCleared", this._onDatasetCleared, this); + onFocused = c(this, "activate", "open", "_onFocused"); + onBlurred = c(this, "deactivate", "_onBlurred"); + onEnterKeyed = c(this, "isActive", "isOpen", "_onEnterKeyed"); + onTabKeyed = c(this, "isActive", "isOpen", "_onTabKeyed"); + onEscKeyed = c(this, "isActive", "_onEscKeyed"); + onUpKeyed = c(this, "isActive", "open", "_onUpKeyed"); + onDownKeyed = c(this, "isActive", "open", "_onDownKeyed"); + onLeftKeyed = c(this, "isActive", "isOpen", "_onLeftKeyed"); + onRightKeyed = c(this, "isActive", "isOpen", "_onRightKeyed"); + onQueryChanged = c(this, "_openIfActive", "_onQueryChanged"); + onWhitespaceChanged = c(this, "_openIfActive", "_onWhitespaceChanged"); + this.input.bind().onSync("focused", onFocused, this).onSync("blurred", onBlurred, this).onSync("enterKeyed", onEnterKeyed, this).onSync("tabKeyed", onTabKeyed, this).onSync("escKeyed", onEscKeyed, this).onSync("upKeyed", onUpKeyed, this).onSync("downKeyed", onDownKeyed, this).onSync("leftKeyed", onLeftKeyed, this).onSync("rightKeyed", onRightKeyed, this).onSync("queryChanged", onQueryChanged, this).onSync("whitespaceChanged", onWhitespaceChanged, this).onSync("langDirChanged", this._onLangDirChanged, this); + } + _.mixin(Typeahead.prototype, { + _hacks: function hacks() { + var $input, $menu; + $input = this.input.$input || $("
                      "); + $menu = this.menu.$node || $("
                      "); + $input.on("blur.tt", function($e) { + var active, isActive, hasActive; + active = document.activeElement; + isActive = $menu.is(active); + hasActive = $menu.has(active).length > 0; + if (_.isMsie() && (isActive || hasActive)) { + $e.preventDefault(); + $e.stopImmediatePropagation(); + _.defer(function() { + $input.focus(); + }); + } + }); + $menu.on("mousedown.tt", function($e) { + $e.preventDefault(); + }); + }, + _onSelectableClicked: function onSelectableClicked(type, $el) { + this.select($el); + }, + _onDatasetCleared: function onDatasetCleared() { + this._updateHint(); + }, + _onDatasetRendered: function onDatasetRendered(type, suggestions, async, dataset) { + this._updateHint(); + if (this.autoselect) { + var cursorClass = this.selectors.cursor.substr(1); + this.menu.$node.find(this.selectors.suggestion).first().addClass(cursorClass); + } + this.eventBus.trigger("render", suggestions, async, dataset); + }, + _onAsyncRequested: function onAsyncRequested(type, dataset, query) { + this.eventBus.trigger("asyncrequest", query, dataset); + }, + _onAsyncCanceled: function onAsyncCanceled(type, dataset, query) { + this.eventBus.trigger("asynccancel", query, dataset); + }, + _onAsyncReceived: function onAsyncReceived(type, dataset, query) { + this.eventBus.trigger("asyncreceive", query, dataset); + }, + _onFocused: function onFocused() { + this._minLengthMet() && this.menu.update(this.input.getQuery()); + }, + _onBlurred: function onBlurred() { + if (this.input.hasQueryChangedSinceLastFocus()) { + this.eventBus.trigger("change", this.input.getQuery()); + } + }, + _onEnterKeyed: function onEnterKeyed(type, $e) { + var $selectable; + if ($selectable = this.menu.getActiveSelectable()) { + if (this.select($selectable)) { + $e.preventDefault(); + $e.stopPropagation(); + } + } else if (this.autoselect) { + if (this.select(this.menu.getTopSelectable())) { + $e.preventDefault(); + $e.stopPropagation(); + } + } + }, + _onTabKeyed: function onTabKeyed(type, $e) { + var $selectable; + if ($selectable = this.menu.getActiveSelectable()) { + this.select($selectable) && $e.preventDefault(); + } else if ($selectable = this.menu.getTopSelectable()) { + this.autocomplete($selectable) && $e.preventDefault(); + } + }, + _onEscKeyed: function onEscKeyed() { + this.close(); + }, + _onUpKeyed: function onUpKeyed() { + this.moveCursor(-1); + }, + _onDownKeyed: function onDownKeyed() { + this.moveCursor(+1); + }, + _onLeftKeyed: function onLeftKeyed() { + if (this.dir === "rtl" && this.input.isCursorAtEnd()) { + this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); + } + }, + _onRightKeyed: function onRightKeyed() { + if (this.dir === "ltr" && this.input.isCursorAtEnd()) { + this.autocomplete(this.menu.getActiveSelectable() || this.menu.getTopSelectable()); + } + }, + _onQueryChanged: function onQueryChanged(e, query) { + this._minLengthMet(query) ? this.menu.update(query) : this.menu.empty(); + }, + _onWhitespaceChanged: function onWhitespaceChanged() { + this._updateHint(); + }, + _onLangDirChanged: function onLangDirChanged(e, dir) { + if (this.dir !== dir) { + this.dir = dir; + this.menu.setLanguageDirection(dir); + } + }, + _openIfActive: function openIfActive() { + this.isActive() && this.open(); + }, + _minLengthMet: function minLengthMet(query) { + query = _.isString(query) ? query : this.input.getQuery() || ""; + return query.length >= this.minLength; + }, + _updateHint: function updateHint() { + var $selectable, data, val, query, escapedQuery, frontMatchRegEx, match; + $selectable = this.menu.getTopSelectable(); + data = this.menu.getSelectableData($selectable); + val = this.input.getInputValue(); + if (data && !_.isBlankString(val) && !this.input.hasOverflow()) { + query = Input.normalizeQuery(val); + escapedQuery = _.escapeRegExChars(query); + frontMatchRegEx = new RegExp("^(?:" + escapedQuery + ")(.+$)", "i"); + match = frontMatchRegEx.exec(data.val); + match && this.input.setHint(val + match[1]); + } else { + this.input.clearHint(); + } + }, + isEnabled: function isEnabled() { + return this.enabled; + }, + enable: function enable() { + this.enabled = true; + }, + disable: function disable() { + this.enabled = false; + }, + isActive: function isActive() { + return this.active; + }, + activate: function activate() { + if (this.isActive()) { + return true; + } else if (!this.isEnabled() || this.eventBus.before("active")) { + return false; + } else { + this.active = true; + this.eventBus.trigger("active"); + return true; + } + }, + deactivate: function deactivate() { + if (!this.isActive()) { + return true; + } else if (this.eventBus.before("idle")) { + return false; + } else { + this.active = false; + this.close(); + this.eventBus.trigger("idle"); + return true; + } + }, + isOpen: function isOpen() { + return this.menu.isOpen(); + }, + open: function open() { + if (!this.isOpen() && !this.eventBus.before("open")) { + this.menu.open(); + this._updateHint(); + this.eventBus.trigger("open"); + } + return this.isOpen(); + }, + close: function close() { + if (this.isOpen() && !this.eventBus.before("close")) { + this.menu.close(); + this.input.clearHint(); + this.input.resetInputValue(); + this.eventBus.trigger("close"); + } + return !this.isOpen(); + }, + setVal: function setVal(val) { + this.input.setQuery(_.toStr(val)); + }, + getVal: function getVal() { + return this.input.getQuery(); + }, + select: function select($selectable) { + var data = this.menu.getSelectableData($selectable); + if (data && !this.eventBus.before("select", data.obj, data.dataset)) { + this.input.setQuery(data.val, true); + this.eventBus.trigger("select", data.obj, data.dataset); + this.close(); + return true; + } + return false; + }, + autocomplete: function autocomplete($selectable) { + var query, data, isValid; + query = this.input.getQuery(); + data = this.menu.getSelectableData($selectable); + isValid = data && query !== data.val; + if (isValid && !this.eventBus.before("autocomplete", data.obj, data.dataset)) { + this.input.setQuery(data.val); + this.eventBus.trigger("autocomplete", data.obj, data.dataset); + return true; + } + return false; + }, + moveCursor: function moveCursor(delta) { + var query, $candidate, data, suggestion, datasetName, cancelMove, id; + query = this.input.getQuery(); + $candidate = this.menu.selectableRelativeToCursor(delta); + data = this.menu.getSelectableData($candidate); + suggestion = data ? data.obj : null; + datasetName = data ? data.dataset : null; + id = $candidate ? $candidate.attr("id") : null; + this.input.trigger("cursorchange", id); + cancelMove = this._minLengthMet() && this.menu.update(query); + if (!cancelMove && !this.eventBus.before("cursorchange", suggestion, datasetName)) { + this.menu.setCursor($candidate); + if (data) { + this.input.setInputValue(data.val); + } else { + this.input.resetInputValue(); + this._updateHint(); + } + this.eventBus.trigger("cursorchange", suggestion, datasetName); + return true; + } + return false; + }, + destroy: function destroy() { + this.input.destroy(); + this.menu.destroy(); + } + }); + return Typeahead; + function c(ctx) { + var methods = [].slice.call(arguments, 1); + return function() { + var args = [].slice.call(arguments); + _.each(methods, function(method) { + return ctx[method].apply(ctx, args); + }); + }; + } + }(); + (function() { + "use strict"; + var old, keys, methods; + old = $.fn.typeahead; + keys = { + www: "tt-www", + attrs: "tt-attrs", + typeahead: "tt-typeahead" + }; + methods = { + initialize: function initialize(o, datasets) { + var www; + datasets = _.isArray(datasets) ? datasets : [].slice.call(arguments, 1); + o = o || {}; + www = WWW(o.classNames); + return this.each(attach); + function attach() { + var $input, $wrapper, $hint, $menu, defaultHint, defaultMenu, eventBus, input, menu, status, typeahead, MenuConstructor; + _.each(datasets, function(d) { + d.highlight = !!o.highlight; + }); + $input = $(this); + $wrapper = $(www.html.wrapper); + $hint = $elOrNull(o.hint); + $menu = $elOrNull(o.menu); + defaultHint = o.hint !== false && !$hint; + defaultMenu = o.menu !== false && !$menu; + defaultHint && ($hint = buildHintFromInput($input, www)); + defaultMenu && ($menu = $(www.html.menu).css(www.css.menu)); + $hint && $hint.val(""); + $input = prepInput($input, www); + if (defaultHint || defaultMenu) { + $wrapper.css(www.css.wrapper); + $input.css(defaultHint ? www.css.input : www.css.inputWithNoHint); + $input.wrap($wrapper).parent().prepend(defaultHint ? $hint : null).append(defaultMenu ? $menu : null); + } + MenuConstructor = defaultMenu ? DefaultMenu : Menu; + eventBus = new EventBus({ + el: $input + }); + input = new Input({ + hint: $hint, + input: $input + }, www); + menu = new MenuConstructor({ + node: $menu, + datasets: datasets + }, www); + status = new Status({ + $input: $input, + menu: menu + }); + typeahead = new Typeahead({ + input: input, + menu: menu, + eventBus: eventBus, + minLength: o.minLength, + autoselect: o.autoselect + }, www); + $input.data(keys.www, www); + $input.data(keys.typeahead, typeahead); + } + }, + isEnabled: function isEnabled() { + var enabled; + ttEach(this.first(), function(t) { + enabled = t.isEnabled(); + }); + return enabled; + }, + enable: function enable() { + ttEach(this, function(t) { + t.enable(); + }); + return this; + }, + disable: function disable() { + ttEach(this, function(t) { + t.disable(); + }); + return this; + }, + isActive: function isActive() { + var active; + ttEach(this.first(), function(t) { + active = t.isActive(); + }); + return active; + }, + activate: function activate() { + ttEach(this, function(t) { + t.activate(); + }); + return this; + }, + deactivate: function deactivate() { + ttEach(this, function(t) { + t.deactivate(); + }); + return this; + }, + isOpen: function isOpen() { + var open; + ttEach(this.first(), function(t) { + open = t.isOpen(); + }); + return open; + }, + open: function open() { + ttEach(this, function(t) { + t.open(); + }); + return this; + }, + close: function close() { + ttEach(this, function(t) { + t.close(); + }); + return this; + }, + select: function select(el) { + var success = false, $el = $(el); + ttEach(this.first(), function(t) { + success = t.select($el); + }); + return success; + }, + autocomplete: function autocomplete(el) { + var success = false, $el = $(el); + ttEach(this.first(), function(t) { + success = t.autocomplete($el); + }); + return success; + }, + moveCursor: function moveCursoe(delta) { + var success = false; + ttEach(this.first(), function(t) { + success = t.moveCursor(delta); + }); + return success; + }, + val: function val(newVal) { + var query; + if (!arguments.length) { + ttEach(this.first(), function(t) { + query = t.getVal(); + }); + return query; + } else { + ttEach(this, function(t) { + t.setVal(_.toStr(newVal)); + }); + return this; + } + }, + destroy: function destroy() { + ttEach(this, function(typeahead, $input) { + revert($input); + typeahead.destroy(); + }); + return this; + } + }; + $.fn.typeahead = function(method) { + if (methods[method]) { + return methods[method].apply(this, [].slice.call(arguments, 1)); + } else { + return methods.initialize.apply(this, arguments); + } + }; + $.fn.typeahead.noConflict = function noConflict() { + $.fn.typeahead = old; + return this; + }; + function ttEach($els, fn) { + $els.each(function() { + var $input = $(this), typeahead; + (typeahead = $input.data(keys.typeahead)) && fn(typeahead, $input); + }); + } + function buildHintFromInput($input, www) { + return $input.clone().addClass(www.classes.hint).removeData().css(www.css.hint).css(getBackgroundStyles($input)).prop({ + readonly: true, + required: false + }).removeAttr("id name placeholder").removeClass("required").attr({ + spellcheck: "false", + tabindex: -1 + }); + } + function prepInput($input, www) { + $input.data(keys.attrs, { + dir: $input.attr("dir"), + autocomplete: $input.attr("autocomplete"), + spellcheck: $input.attr("spellcheck"), + style: $input.attr("style") + }); + $input.addClass(www.classes.input).attr({ + spellcheck: false + }); + try { + !$input.attr("dir") && $input.attr("dir", "auto"); + } catch (e) {} + return $input; + } + function getBackgroundStyles($el) { + return { + backgroundAttachment: $el.css("background-attachment"), + backgroundClip: $el.css("background-clip"), + backgroundColor: $el.css("background-color"), + backgroundImage: $el.css("background-image"), + backgroundOrigin: $el.css("background-origin"), + backgroundPosition: $el.css("background-position"), + backgroundRepeat: $el.css("background-repeat"), + backgroundSize: $el.css("background-size") + }; + } + function revert($input) { + var www, $wrapper; + www = $input.data(keys.www); + $wrapper = $input.parent().filter(www.selectors.wrapper); + _.each($input.data(keys.attrs), function(val, key) { + _.isUndefined(val) ? $input.removeAttr(key) : $input.attr(key, val); + }); + $input.removeData(keys.typeahead).removeData(keys.www).removeData(keys.attr).removeClass(www.classes.input); + if ($wrapper.length) { + $input.detach().insertAfter($wrapper); + $wrapper.remove(); + } + } + function $elOrNull(obj) { + var isValid, $el; + isValid = _.isJQuery(obj) || _.isElement(obj); + $el = isValid ? $(obj).first() : []; + return $el.length ? $el : null; + } + })(); +}); \ No newline at end of file diff --git a/docs/micro-example.html b/docs/micro-example.html new file mode 100644 index 0000000..3ae38ac --- /dev/null +++ b/docs/micro-example.html @@ -0,0 +1,262 @@ + + + + Micro Example Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Micro Example

                      +
                      /** AppDelegate.swift */
                      +import UIKit
                      +import InAppPurchaseLib
                      +
                      +@UIApplicationMain
                      +class AppDelegate: UIResponder, UIApplicationDelegate {
                      +  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
                      +    // Initialize the library
                      +    InAppPurchase.initialize(
                      +      iapProducts: [
                      +        IAPProduct(productIdentifier: "my_product", productType: .nonConsumable)
                      +      ],
                      +      validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678"
                      +    )
                      +    return true
                      +  }
                      +
                      +  func applicationWillTerminate(_ application: UIApplication) {
                      +    // Clean
                      +    InAppPurchase.stop()
                      +  }
                      +}
                      +
                      +
                      /** ViewController.swift */
                      +import UIKit
                      +import StoreKit
                      +import InAppPurchaseLib
                      +
                      +class ViewController: UIViewController {
                      +  private var loaderView = LoaderView()
                      +  @IBOutlet weak var statusLabel: UILabel!
                      +  @IBOutlet weak var productTitleLabel: UILabel!
                      +  @IBOutlet weak var productDescriptionLabel: UILabel!
                      +  @IBOutlet weak var purchaseButton: UIButton!
                      +  @IBOutlet weak var restorePurchasesButton: UIButton!
                      +
                      +  override func viewDidLoad() {
                      +    super.viewDidLoad()
                      +    // Add action for purchases and restore butons.
                      +    purchaseButton.addTarget(self, action: #selector(self.purchase), for: .touchUpInside)
                      +    restorePurchasesButton.addTarget(self, action: #selector(self.restorePurchases), for: .touchUpInside)
                      +  }
                      +
                      +  override func viewWillAppear(_ animated: Bool) {
                      +    self.refreshView()
                      +    InAppPurchase.refresh(callback: { _ in
                      +      self.refreshView()
                      +    })
                      +  }
                      +
                      +  func refreshView() {
                      +    guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product") else {
                      +      self.productTitleLabel.text = "Product unavailable"
                      +      return
                      +    }
                      +    // Display product information.
                      +    productTitleLabel.text = product.localizedTitle
                      +    productDescriptionLabel.text = product.localizedDescription
                      +    purchaseButton.setTitle(product.localizedPrice, for: .normal)
                      +
                      +    // Disable the button if the product has already been purchased.
                      +    if InAppPurchase.hasActivePurchase(for: "my_product") {
                      +      statusLabel.text = "OWNED"
                      +      purchaseButton.isPointerInteractionEnabled = false
                      +    }
                      +  }
                      +
                      +  @IBAction func purchase(_ sender: Any) {
                      +    self.loaderView.show()
                      +    InAppPurchase.purchase(
                      +      productIdentifier: "my_product",
                      +      callback: { result in
                      +        self.loaderView.hide()
                      +      })
                      +  }
                      +
                      +  @IBAction func restorePurchases(_ sender: Any) {
                      +    self.loaderView.show()
                      +    InAppPurchase.restorePurchases(callback: { result in
                      +      self.loaderView.hide()
                      +    })
                      +  }
                      +}
                      +
                      + +
                      +
                      + + +
                      +
                      + + +
                      + diff --git a/docs/purchasing.html b/docs/purchasing.html new file mode 100644 index 0000000..7a6996c --- /dev/null +++ b/docs/purchasing.html @@ -0,0 +1,245 @@ + + + + Purchasing Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Purchasing

                      + +

                      The purchase process is generally a little bit more involving than most people would expect. Why is it not just: purchase → on success unlock the feature?

                      + +

                      Several reasons:

                      + +
                        +
                      • In-app purchases can be initiated outside the app
                      • +
                      • In-app purchases can be deferred, pending parental approval
                      • +
                      • Apple wants to be sure you delivered the product before charging the user
                      • +
                      + +

                      That is why the process looks like so:

                      + +
                        +
                      • being ready to handle purchase events from app startup
                      • +
                      • finalizing transactions when product delivery is complete
                      • +
                      • sending purchase request, for which successful doesn’t always mean complete
                      • +
                      +

                      Initiating a purchase

                      + +

                      To initiate a purchase, use the InAppPurchase.purchase() function. It takes the productIdentifier and a callback function, called when the purchase has been processed.

                      + +

                      Important: Do not process the purchase here, we’ll handle that later!

                      + +

                      From this callback, you can for example unlock the UI by hiding your loading indicator and display a message to the user.

                      + +

                      Example:

                      +
                      self.loaderView.show()
                      +InAppPurchase.purchase(
                      +  productIdentifier: "my_product_id",
                      +  callback: { _ in
                      +    self.loaderView.hide()
                      +})
                      +
                      + +

                      This simple example locks the UI with a loader when the purchase is in progress. We’ll see later how the purchase has to be processed by your applicaiton.

                      + +

                      The callback also gives more information about the outcome of the purchase, you might want to use it to update your UI as well. Note that some events are useful for analytics. So here’s a more complete example.

                      +
                      self.loaderView.show()
                      +InAppPurchase.purchase(
                      +  productIdentifier: "my_product_id",
                      +  callback: { result in
                      +    self.loaderView.hide()
                      +
                      +    switch result.state {
                      +    case .purchased:
                      +      // Product successfully purchased
                      +      // Reminder: Do not process the purchase here, only update your UI.
                      +      //           that's why we do not send data to analytics.
                      +      openThankYouScreen()
                      +    case .failed:
                      +      // Purchase failed
                      +      // - Human formated reason can be found in result.localizedDescription
                      +      // - More details in either result.skError or result.iapError
                      +      showError(result.localizedDescription)
                      +    case .deferred:
                      +      // The purchase is deferred, waiting for the parent's approval
                      +      openWaitingParentApprovalScreen()
                      +    case .cancelled:
                      +      // The user canceled the request, generally only useful for analytics.
                      +  }
                      +})
                      +
                      + +

                      If the purchase fails, result will contain either .skError, a SKError from StoreKit, or .iapError, an IAPError.

                      + +

                      Tip: After a successful purchase, you should see a new transaction in Fovea’s dashboard.

                      + +
                      +
                      + + +
                      +
                      + + +
                      + diff --git a/docs/refreshing.html b/docs/refreshing.html new file mode 100644 index 0000000..56e094a --- /dev/null +++ b/docs/refreshing.html @@ -0,0 +1,189 @@ + + + + Refreshing Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Refreshing

                      + +

                      Data might change or not be yet available when your “product” view is presented. In order to properly handle those cases, you should refresh your view after refreshing in-app products metadata. You want to be sure you’re displaying up-to-date information.

                      + +

                      To achieve this, call InAppPurchase.refresh() when your view is presented.

                      +
                      override func viewWillAppear(_ animated: Bool) {
                      +  self.refreshView()
                      +  InAppPurchase.refresh(callback: { _ in
                      +      self.refreshView()
                      +  })
                      +}
                      +
                      + +
                      +
                      + + +
                      +
                      + + +
                      + diff --git a/docs/restoring-purchases.html b/docs/restoring-purchases.html new file mode 100644 index 0000000..ab44024 --- /dev/null +++ b/docs/restoring-purchases.html @@ -0,0 +1,201 @@ + + + + Restoring purchases Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Restoring purchases

                      + +

                      Except if you only sell consumable products, Apple requires that you provide a “Restore Purchases” button to your users. In general, it is found in your application settings.

                      + +

                      Call this method when this button is pressed.

                      +
                      @IBAction func restorePurchases(_ sender: Any) {
                      +  self.loaderView.show()
                      +  InAppPurchase.restorePurchases(callback: { result in
                      +      self.loaderView.hide()
                      +      switch result.state {
                      +      case .succeeded:
                      +          if result.addedPurchases > 0 {
                      +              print("Restore purchases successful.")
                      +          } else {
                      +              print("No purchase to restore.")
                      +          }
                      +      case .failed:
                      +          print("Restore purchases failed.")
                      +      }
                      +  })
                      +}
                      +
                      + +

                      The callback method is called once the operation is complete. You can use it to unlock the UI, by hiding your loader for example, and display the adapted message to the user.

                      + +
                      +
                      + + +
                      +
                      + + +
                      + diff --git a/docs/search.json b/docs/search.json new file mode 100644 index 0000000..ca5875b --- /dev/null +++ b/docs/search.json @@ -0,0 +1 @@ +{"Protocols/IAPErrorProtocol.html#/s:16InAppPurchaseLib16IAPErrorProtocolP4codeAA0E4CodeOvp":{"name":"code","abstract":"

                      Undocumented

                      ","parent_name":"IAPErrorProtocol"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO21libraryNotInitializedyA2CmF":{"name":"libraryNotInitialized","abstract":"

                      You must call the initialize fuction before using the library.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO23bundleIdentifierInvalidyA2CmF":{"name":"bundleIdentifierInvalid","abstract":"

                      The Bundle Identifier is invalid.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO19validatorUrlInvalidyA2CmF":{"name":"validatorUrlInvalid","abstract":"

                      The Validator URL String is invalid.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO20refreshReceiptFailedyA2CmF":{"name":"refreshReceiptFailed","abstract":"

                      Failed to refresh the App Store receipt.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO21validateReceiptFailedyA2CmF":{"name":"validateReceiptFailed","abstract":"

                      Failed to validate the App Store receipt with Fovea.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO17readReceiptFailedyA2CmF":{"name":"readReceiptFailed","abstract":"

                      Failed to read the receipt validation.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO21refreshProductsFailedyA2CmF":{"name":"refreshProductsFailed","abstract":"

                      Failed to refresh products from the App Store.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO15productNotFoundyA2CmF":{"name":"productNotFound","abstract":"

                      The product was not found on the App Store and cannot be purchased.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO010cannotMakeC0yA2CmF":{"name":"cannotMakePurchase","abstract":"

                      The user is not allowed to authorize payments.

                      ","parent_name":"IAPErrorCode"},"Enums/IAPErrorCode.html#/s:16InAppPurchaseLib12IAPErrorCodeO17alreadyPurchasingyA2CmF":{"name":"alreadyPurchasing","abstract":"

                      A purchase is already in progress.

                      ","parent_name":"IAPErrorCode"},"Structs/IAPError.html#/s:16InAppPurchaseLib8IAPErrorV4codeAA0E4CodeOvp":{"name":"code","abstract":"

                      The error code.

                      ","parent_name":"IAPError"},"Structs/IAPError.html#/s:16InAppPurchaseLib8IAPErrorV20localizedDescriptionSSvp":{"name":"localizedDescription","abstract":"

                      The error description.

                      ","parent_name":"IAPError"},"Enums/IAPRefreshResultState.html#/s:16InAppPurchaseLib21IAPRefreshResultStateO9succeededyA2CmF":{"name":"succeeded","abstract":"

                      Refresh was successful.

                      ","parent_name":"IAPRefreshResultState"},"Enums/IAPRefreshResultState.html#/s:16InAppPurchaseLib21IAPRefreshResultStateO6failedyA2CmF":{"name":"failed","abstract":"

                      Refresh failed.

                      ","parent_name":"IAPRefreshResultState"},"Enums/IAPRefreshResultState.html#/s:16InAppPurchaseLib21IAPRefreshResultStateO7skippedyA2CmF":{"name":"skipped","abstract":"

                      Refresh has been skipped because it is not necessary.

                      ","parent_name":"IAPRefreshResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO9purchasedyA2CmF":{"name":"purchased","abstract":"

                      The purchase was successful.

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO6failedyA2CmF":{"name":"failed","abstract":"

                      Puchase failed.

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO9cancelledyA2CmF":{"name":"cancelled","abstract":"

                      The purchase was cancelled by the user.

                      ","parent_name":"IAPPurchaseResultState"},"Enums/IAPPurchaseResultState.html#/s:16InAppPurchaseLib22IAPPurchaseResultStateO8deferredyA2CmF":{"name":"deferred","abstract":"

                      The purchase is deferred.

                      ","parent_name":"IAPPurchaseResultState"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV5stateAA0eF5StateOvp":{"name":"state","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV8iapErrorAA8IAPErrorVSgvp":{"name":"iapError","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV14addedPurchasesSivp":{"name":"addedPurchases","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPRefreshResult.html#/s:16InAppPurchaseLib16IAPRefreshResultV16updatedPurchasesSivp":{"name":"updatedPurchases","abstract":"

                      Undocumented

                      ","parent_name":"IAPRefreshResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV5stateAA0eF5StateOvp":{"name":"state","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV8iapErrorAA8IAPErrorVSgvp":{"name":"iapError","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV7skErrorSC11SKErrorCodeLeVSgvp":{"name":"skError","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Structs/IAPPurchaseResult.html#/s:16InAppPurchaseLib17IAPPurchaseResultV20localizedDescriptionSSSgvp":{"name":"localizedDescription","abstract":"

                      Undocumented

                      ","parent_name":"IAPPurchaseResult"},"Enums/IAPPeriodFormat.html#/s:16InAppPurchaseLib15IAPPeriodFormatO5shortyA2CmF":{"name":"short","abstract":"

                      Undocumented

                      ","parent_name":"IAPPeriodFormat"},"Enums/IAPPeriodFormat.html#/s:16InAppPurchaseLib15IAPPeriodFormatO4longyA2CmF":{"name":"long","abstract":"

                      Undocumented

                      ","parent_name":"IAPPeriodFormat"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE21localizedPeriodFormatAC09IAPPeriodH0OvpZ":{"name":"localizedPeriodFormat","abstract":"

                      Undocumented

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE28hasIntroductoryPriceEligibleSbyF":{"name":"hasIntroductoryPriceEligible()","abstract":"

                      Checks if the product has an introductory price the user is eligible to.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE14localizedPriceSSvp":{"name":"localizedPrice","abstract":"

                      Returns a localized string with the cost of the product in the local currency.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE27localizedSubscriptionPeriodSSSgvp":{"name":"localizedSubscriptionPeriod","abstract":"

                      Returns a localized string with the period of the subscription product.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE26localizedIntroductoryPriceSSSgvp":{"name":"localizedIntroductoryPrice","abstract":"

                      Returns a localized string with the introductory price if available, in the local currency.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE27localizedIntroductoryPeriodSSSgvp":{"name":"localizedIntroductoryPeriod","abstract":"

                      Returns a localized string with the introductory price period of the subscription product.

                      ","parent_name":"SKProduct"},"Extensions/SKProduct.html#/s:So9SKProductC16InAppPurchaseLibE29localizedIntroductoryDurationSSSgvp":{"name":"localizedIntroductoryDuration","abstract":"

                      Returns a localized string with the duration of the introductory price.

                      ","parent_name":"SKProduct"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO10consumableyA2CmF":{"name":"consumable","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO13nonConsumableyA2CmF":{"name":"nonConsumable","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO23nonRenewingSubscriptionyA2CmF":{"name":"nonRenewingSubscription","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Enums/IAPProductType.html#/s:16InAppPurchaseLib14IAPProductTypeO25autoRenewableSubscriptionyA2CmF":{"name":"autoRenewableSubscription","abstract":"

                      Undocumented

                      ","parent_name":"IAPProductType"},"Structs/IAPProduct.html#/s:16InAppPurchaseLib10IAPProductV17productIdentifierSSvp":{"name":"productIdentifier","abstract":"

                      The identifier of the product.

                      ","parent_name":"IAPProduct"},"Structs/IAPProduct.html#/s:16InAppPurchaseLib10IAPProductV11productTypeAA0eG0Ovp":{"name":"productType","abstract":"

                      The type of the product.

                      ","parent_name":"IAPProduct"},"Structs/IAPProduct.html#/s:16InAppPurchaseLib10IAPProductV17productIdentifier0F4TypeACSS_AA0eH0Otcfc":{"name":"init(productIdentifier:productType:)","abstract":"

                      Initializes an IAPProduct with its identifier and type.

                      ","parent_name":"IAPProduct"},"Protocols/IAPPurchaseDelegate.html#/s:16InAppPurchaseLib19IAPPurchaseDelegateP16productPurchased0G10IdentifierySS_tF":{"name":"productPurchased(productIdentifier:)","abstract":"

                      Called when a product is newly purchased, updated or restored.

                      ","parent_name":"IAPPurchaseDelegate"},"Classes/DefaultPurchaseDelegate.html#/s:16InAppPurchaseLib07DefaultC8DelegateCACycfc":{"name":"init()","abstract":"

                      Undocumented

                      ","parent_name":"DefaultPurchaseDelegate"},"Classes/DefaultPurchaseDelegate.html#/s:16InAppPurchaseLib07DefaultC8DelegateC16productPurchased0G10IdentifierySS_tF":{"name":"productPurchased(productIdentifier:)","abstract":"

                      Finish the product transactions when a product is newly purchased, updated or restored.

                      ","parent_name":"DefaultPurchaseDelegate"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP11iapProductsSayAA10IAPProductVGvpZ":{"name":"iapProducts","abstract":"

                      The array of IAPProduct.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP18validatorUrlStringSSSgvpZ":{"name":"validatorUrlString","abstract":"

                      The validator url retrieved from Fovea.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP03iapC8DelegateAA011IAPPurchaseF0_pSgvpZ":{"name":"iapPurchaseDelegate","abstract":"

                      The instance of class that adopts the IAPPurchaseDelegate protocol.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP19applicationUsernameSSSgvpZ":{"name":"applicationUsername","abstract":"

                      The user name, if your app implements user login.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP10initialize11iapProducts18validatorUrlString0fC8Delegate19applicationUsernameySayAA10IAPProductVG_SSAA011IAPPurchaseK0_pSSSgtFZ":{"name":"initialize(iapProducts:validatorUrlString:iapPurchaseDelegate:applicationUsername:)","abstract":"

                      Start observing the payment queue, as soon as possible, and refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP4stopyyFZ":{"name":"stop()","abstract":"

                      Stop observing the payment queue, when the application will terminate, for proper cleanup.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP7refresh8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"refresh(callback:)","abstract":"

                      Refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP11getProductsSaySo9SKProductCGyFZ":{"name":"getProducts()","abstract":"

                      Gets all products retrieved from the App Store

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP12getProductBy10identifierSo9SKProductCSgSS_tFZ":{"name":"getProductBy(identifier:)","abstract":"

                      Gets the product by its identifier from the list of products retrieved from the App Store.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP15canMakePaymentsSbyFZ":{"name":"canMakePayments()","abstract":"

                      Checks if the user is allowed to authorize payments.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP8purchase17productIdentifier8quantity8callbackySS_SiyAA17IAPPurchaseResultVctFZ":{"name":"purchase(productIdentifier:quantity:callback:)","abstract":"

                      Request a Payment from the App Store.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP16restorePurchases8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"restorePurchases(callback:)","abstract":"

                      Restore purchased products.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP18finishTransactions3forySS_tFZ":{"name":"finishTransactions(for:)","abstract":"

                      Finish all transactions for the product.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP22hasDeferredTransaction3forSbSS_tFZ":{"name":"hasDeferredTransaction(for:)","abstract":"

                      Checks if the last transaction state for a given product was deferred.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP19hasAlreadyPurchasedSbyFZ":{"name":"hasAlreadyPurchased()","abstract":"

                      Checks if the user has already purchased at least one product.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP09hasActiveC03forSbSS_tFZ":{"name":"hasActivePurchase(for:)","abstract":"

                      Checks if the user currently own (or is subscribed to) a given product (nonConsumable or autoRenewableSubscription).

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP21hasActiveSubscriptionSbyFZ":{"name":"hasActiveSubscription()","abstract":"

                      Checks if the user has an active auto renewable subscription regardless of the product identifier.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP03getC4Date3for10Foundation0F0VSgSS_tFZ":{"name":"getPurchaseDate(for:)","abstract":"

                      Returns the latest purchased date for a given product.

                      ","parent_name":"InAppPurchaseLib"},"Protocols/InAppPurchaseLib.html#/s:16InAppPurchaseLibAAP13getExpiryDate3for10Foundation0G0VSgSS_tFZ":{"name":"getExpiryDate(for:)","abstract":"

                      Returns the expiry date for a subcription. May be past or future.

                      ","parent_name":"InAppPurchaseLib"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C11iapProductsSayAA10IAPProductVGvpZ":{"name":"iapProducts","abstract":"

                      The array of IAPProduct.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C18validatorUrlStringSSSgvpZ":{"name":"validatorUrlString","abstract":"

                      The validator url retrieved from Fovea.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C03iapC8DelegateAA011IAPPurchaseF0_pSgvpZ":{"name":"iapPurchaseDelegate","abstract":"

                      The instance of class that adopts the IAPPurchaseDelegate protocol.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C19applicationUsernameSSSgvpZ":{"name":"applicationUsername","abstract":"

                      The user name, if your app implements user login.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C10initialize11iapProducts18validatorUrlString0fC8Delegate19applicationUsernameySayAA10IAPProductVG_SSAA011IAPPurchaseK0_pSSSgtFZ":{"name":"initialize(iapProducts:validatorUrlString:iapPurchaseDelegate:applicationUsername:)","abstract":"

                      Start observing the payment queue, as soon as possible, and refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C4stopyyFZ":{"name":"stop()","abstract":"

                      Stop observing the payment queue, when the application will terminate, for proper cleanup.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C7refresh8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"refresh(callback:)","abstract":"

                      Refresh Product list and user Receipt.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C11getProductsSaySo9SKProductCGyFZ":{"name":"getProducts()","abstract":"

                      Gets all products retrieved from the App Store

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C12getProductBy10identifierSo9SKProductCSgSS_tFZ":{"name":"getProductBy(identifier:)","abstract":"

                      Gets the product by its identifier from the list of products retrieved from the App Store.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C15canMakePaymentsSbyFZ":{"name":"canMakePayments()","abstract":"

                      Checks if the user is allowed to authorize payments.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C8purchase17productIdentifier8quantity8callbackySS_SiyAA17IAPPurchaseResultVctFZ":{"name":"purchase(productIdentifier:quantity:callback:)","abstract":"

                      Request a Payment from the App Store.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C16restorePurchases8callbackyyAA16IAPRefreshResultVc_tFZ":{"name":"restorePurchases(callback:)","abstract":"

                      Restore purchased products.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C18finishTransactions3forySS_tFZ":{"name":"finishTransactions(for:)","abstract":"

                      Finish all transactions for the product.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C22hasDeferredTransaction3forSbSS_tFZ":{"name":"hasDeferredTransaction(for:)","abstract":"

                      Checks if the last transaction state for a given product was deferred.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C19hasAlreadyPurchasedSbyFZ":{"name":"hasAlreadyPurchased()","abstract":"

                      Checks if the user has already purchased at least one product.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C09hasActiveC03forSbSS_tFZ":{"name":"hasActivePurchase(for:)","abstract":"

                      Checks if the user currently own (or is subscribed to) a given product (nonConsumable or autoRenewableSubscription).

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C21hasActiveSubscriptionSbyFZ":{"name":"hasActiveSubscription()","abstract":"

                      Checks if the user has an active auto renewable subscription regardless of the product identifier.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C03getC4Date3for10Foundation0F0VSgSS_tFZ":{"name":"getPurchaseDate(for:)","abstract":"

                      Returns the latest purchased date for a given product.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html#/s:16InAppPurchaseLib0abC0C13getExpiryDate3for10Foundation0G0VSgSS_tFZ":{"name":"getExpiryDate(for:)","abstract":"

                      Returns the expiry date for a subcription. May be past or future.

                      ","parent_name":"InAppPurchase"},"Classes/InAppPurchase.html":{"name":"InAppPurchase"},"Protocols/InAppPurchaseLib.html":{"name":"InAppPurchaseLib","abstract":"

                      The protocol that InAppPurchase adopts.

                      "},"Classes/DefaultPurchaseDelegate.html":{"name":"DefaultPurchaseDelegate","abstract":"

                      The default implementation of IAPPurchaseDelegate if no other is provided. It is enough if you only have non-consumable and/or auto-renewable subscription products.

                      "},"Protocols/IAPPurchaseDelegate.html":{"name":"IAPPurchaseDelegate","abstract":"

                      The protocol that you must adopt if you have consumable and/or non-renewing subscription products.

                      "},"Structs/IAPProduct.html":{"name":"IAPProduct","abstract":"

                      Undocumented

                      "},"Enums/IAPProductType.html":{"name":"IAPProductType","abstract":"

                      Undocumented

                      "},"Extensions/SKProduct.html":{"name":"SKProduct"},"Enums/IAPPeriodFormat.html":{"name":"IAPPeriodFormat","abstract":"

                      Undocumented

                      "},"API%20documentation.html#/s:16InAppPurchaseLib19IAPPurchaseCallbacka":{"name":"IAPPurchaseCallback","abstract":"

                      Undocumented

                      "},"API%20documentation.html#/s:16InAppPurchaseLib18IAPRefreshCallbacka":{"name":"IAPRefreshCallback","abstract":"

                      Undocumented

                      "},"Structs/IAPPurchaseResult.html":{"name":"IAPPurchaseResult","abstract":"

                      The result returned in the purchase() callback.

                      "},"Structs/IAPRefreshResult.html":{"name":"IAPRefreshResult","abstract":"

                      The result returned in the refresh() or restorePurchases() callback.

                      "},"Enums/IAPPurchaseResultState.html":{"name":"IAPPurchaseResultState","abstract":"

                      The list of the different states of the IAPPurchaseResult.

                      "},"Enums/IAPRefreshResultState.html":{"name":"IAPRefreshResultState","abstract":"

                      The list of the different states of the IAPRefreshResult.

                      "},"Structs/IAPError.html":{"name":"IAPError","abstract":"

                      When calling refresh(), purchase() or restorePurchases(), the callback can return an IAPError if the state is failed.

                      "},"Enums/IAPErrorCode.html":{"name":"IAPErrorCode","abstract":"

                      The list of error codes that can be returned by the library.

                      "},"Protocols/IAPErrorProtocol.html":{"name":"IAPErrorProtocol","abstract":"

                      Undocumented

                      "},"initialization.html":{"name":"Initialization"},"displaying-products.html":{"name":"Displaying products"},"displaying-subscriptions.html":{"name":"Displaying subscriptions"},"refreshing.html":{"name":"Refreshing"},"purchasing.html":{"name":"Purchasing"},"handling-purchases.html":{"name":"Handling purchases"},"restoring-purchases.html":{"name":"Restoring purchases"},"displaying-products-with-purchases.html":{"name":"Displaying products with purchases"},"errors.html":{"name":"Errors"},"analytics.html":{"name":"Analytics"},"server-integration.html":{"name":"Server integration"},"installation.html":{"name":"Installation"},"micro-example.html":{"name":"Micro Example"},"Getting%20Started.html":{"name":"Getting Started"},"Usage.html":{"name":"Usage"},"API%20documentation.html":{"name":"API documentation"}} \ No newline at end of file diff --git a/docs/server-integration.html b/docs/server-integration.html new file mode 100644 index 0000000..ab51e7d --- /dev/null +++ b/docs/server-integration.html @@ -0,0 +1,198 @@ + + + + Server integration Reference + + + + + + + + + + + + + + + +
                      +

                      + + InAppPurchaseLib documentation + + (77% documented) +

                      + +

                      +

                      + +
                      +

                      + +

                      + + + View on GitHub + +

                      + +
                      + + + +
                      + +
                      + +
                      +
                      + +

                      Server integration

                      + +

                      In more advanced use cases, you have a server component. Users are logged in and you’ll like to unlock the content for this user on your server. The safest approach is to setup a Webhook on Fovea. You’ll receive notifications from Fovea that transaction have been processed and/or subscriptions updated.

                      + +

                      The information sent from Fovea has been verified from Apple’s server, which makes it way more trustable than information sent from your app itself.

                      + +

                      To take advantage of this, you have to inform the library of your application username. This applicationUsername can be provided as a parameter of the InAppPurchase.initialize method and updated later by changing the associated property.

                      + +

                      Example:

                      +
                      InAppPurchase.initialize(
                      +  iapProducts: [...],
                      +  validatorUrlString: "..."),
                      +  applicationUsername: UserSession.getUserId())
                      +
                      +// later ...
                      +InAppPurchase.applicationUsername = UserSession.getUserId()
                      +
                      + +

                      If a user account is mandatory in your app, you will want to delay calls to InAppPurchase.initialize() to when your user’s session is ready.

                      + +

                      Do not hesitate to contact Fovea for help.

                      + +
                      +
                      + + +
                      +
                      + + +
                      + diff --git a/docs/swift-doc/DefaultPurchaseDelegate/index.html b/docs/swift-doc/DefaultPurchaseDelegate/index.html deleted file mode 100755 index 60ef6bd..0000000 --- a/docs/swift-doc/DefaultPurchaseDelegate/index.html +++ /dev/null @@ -1,151 +0,0 @@ - - - - - - InAppPurchase - DefaultPurchaseDelegate - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Class - Default​Purchase​Delegate -

                      - -
                      public class DefaultPurchaseDelegate: IAPPurchaseDelegate
                      -
                      -

                      The default implementation of IAPPurchaseDelegate if no other is provided.

                      - -
                      -
                      - -
                      - - - - - - - - - -DefaultPurchaseDelegate - - -DefaultPurchaseDelegate - - - - - -IAPPurchaseDelegate - - -IAPPurchaseDelegate - - - - - -DefaultPurchaseDelegate->IAPPurchaseDelegate - - - - - - - - -
                      -

                      Conforms To

                      -
                      -
                      IAPPurchaseDelegate
                      -

                      The protocol that you must adopt if you have consumable and/or nonRenewingSubscription products.

                      -
                      -
                      -
                      -
                      -

                      Initializers

                      - -
                      -

                      - init() -

                      -
                      public init()
                      -
                      -
                      -
                      -

                      Methods

                      - -
                      -

                      - product​Purchased(product​Identifier:​) -

                      -
                      public func productPurchased(productIdentifier: String)
                      -
                      -

                      Finish the product transactions when a product is newly purchased, updated or restored.

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      -
                      -
                      - - - -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPError/index.html b/docs/swift-doc/IAPError/index.html deleted file mode 100755 index 948cd13..0000000 --- a/docs/swift-doc/IAPError/index.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - InAppPurchase - IAPError - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Structure - IAPError -

                      - -
                      public struct IAPError: IAPErrorProtocol
                      -
                      - -
                      - - - - - - - - - -IAPError - - -IAPError - - - - - -IAPErrorProtocol - - -IAPErrorProtocol - - - - - -IAPError->IAPErrorProtocol - - - - - - - - -
                      -

                      Conforms To

                      -
                      -
                      IAPErrorProtocol
                      -
                      -
                      -
                      -
                      -

                      Properties

                      - -
                      -

                      - code -

                      -
                      var code: IAPErrorCode
                      -
                      -
                      -

                      - localized​Description -

                      -
                      var localizedDescription: String
                      -
                      -
                      - - - -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPErrorCode/index.html b/docs/swift-doc/IAPErrorCode/index.html deleted file mode 100755 index aa4e9ad..0000000 --- a/docs/swift-doc/IAPErrorCode/index.html +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - InAppPurchase - IAPErrorCode - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Enumeration - IAPError​Code -

                      - -
                      public enum IAPErrorCode
                      - -
                      -

                      Enumeration Cases

                      - -
                      -

                      - library​Not​Initialized -

                      -
                      case libraryNotInitialized
                      -
                      -
                      -

                      - product​Not​Found -

                      -
                      case productNotFound
                      -
                      -
                      -

                      - cannot​Make​Purchase -

                      -
                      case cannotMakePurchase
                      -
                      -
                      -

                      - already​Purchasing -

                      -
                      case alreadyPurchasing
                      -
                      -
                      -

                      - bundle​Identifier​Invalid -

                      -
                      case bundleIdentifierInvalid
                      -
                      -
                      -

                      - validator​Url​Invalid -

                      -
                      case validatorUrlInvalid
                      -
                      -
                      -

                      - refresh​Receipt​Failed -

                      -
                      case refreshReceiptFailed
                      -
                      -
                      -

                      - validate​Receipt​Failed -

                      -
                      case validateReceiptFailed
                      -
                      -
                      -

                      - read​Receipt​Failed -

                      -
                      case readReceiptFailed
                      -
                      -
                      -

                      - refresh​Products​Failed -

                      -
                      case refreshProductsFailed
                      -
                      -
                      - - - -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPErrorProtocol/index.html b/docs/swift-doc/IAPErrorProtocol/index.html deleted file mode 100755 index b4490ac..0000000 --- a/docs/swift-doc/IAPErrorProtocol/index.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - - - InAppPurchase - IAPErrorProtocol - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Protocol - IAPError​Protocol -

                      - -
                      public protocol IAPErrorProtocol: LocalizedError
                      -
                      - -
                      - - - - - - - - - -IAPErrorProtocol - - -IAPErrorProtocol - - - - - -LocalizedError - -LocalizedError - - - -IAPErrorProtocol->LocalizedError - - - - - -IAPError - - -IAPError - - - - - -IAPError->IAPErrorProtocol - - - - - - - - -
                      -

                      Conforms To

                      -
                      -
                      LocalizedError
                      -
                      -

                      Types Conforming to IAPError​Protocol

                      -
                      -
                      IAPError
                      -
                      -
                      -
                      - - - -
                      -

                      Requirements

                      - -
                      -

                      - code -

                      -
                      var code: IAPErrorCode
                      -
                      -
                      -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPPeriodFormat/index.html b/docs/swift-doc/IAPPeriodFormat/index.html deleted file mode 100755 index 551b536..0000000 --- a/docs/swift-doc/IAPPeriodFormat/index.html +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - InAppPurchase - IAPPeriodFormat - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Enumeration - IAPPeriod​Format -

                      - -
                      public enum IAPPeriodFormat
                      - -
                      -

                      Enumeration Cases

                      - -
                      -

                      - short -

                      -
                      case short
                      -
                      -
                      -

                      - long -

                      -
                      case long
                      -
                      -
                      - - - -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPProduct/index.html b/docs/swift-doc/IAPProduct/index.html deleted file mode 100755 index db7e392..0000000 --- a/docs/swift-doc/IAPProduct/index.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - - - InAppPurchase - IAPProduct - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Structure - IAPProduct -

                      - -
                      public struct IAPProduct
                      - -
                      -

                      Initializers

                      - -
                      -

                      - init(product​Identifier:​product​Type:​) -

                      -
                      public init(productIdentifier: String, productType: IAPProductType)
                      -
                      -

                      Initializes an IAPProduct with its identifier and type.

                      - -
                      -
                      - - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      product​TypeIAPProduct​Type

                      The type of the product.

                      -
                      -
                      -
                      -
                      -

                      Properties

                      - -
                      -

                      - product​Identifier -

                      -
                      var productIdentifier: String
                      -
                      -

                      The identifier of the product.

                      - -
                      -
                      -
                      -

                      - product​Type -

                      -
                      var productType: IAPProductType
                      -
                      -

                      The type of the product.

                      - -
                      -
                      - - -
                      -
                      -
                      - - - -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPProductType/index.html b/docs/swift-doc/IAPProductType/index.html deleted file mode 100755 index 3f641db..0000000 --- a/docs/swift-doc/IAPProductType/index.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - InAppPurchase - IAPProductType - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Enumeration - IAPProduct​Type -

                      - -
                      public enum IAPProductType
                      - -
                      -

                      Enumeration Cases

                      - -
                      -

                      - consumable -

                      -
                      case consumable
                      -
                      -
                      -

                      - non​Consumable -

                      -
                      case nonConsumable
                      -
                      -
                      -

                      - non​Renewing​Subscription -

                      -
                      case nonRenewingSubscription
                      -
                      -
                      -

                      - auto​Renewable​Subscription -

                      -
                      case autoRenewableSubscription
                      -
                      -
                      - - - -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPPurchaseCallback/index.html b/docs/swift-doc/IAPPurchaseCallback/index.html deleted file mode 100755 index 7b663d9..0000000 --- a/docs/swift-doc/IAPPurchaseCallback/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - InAppPurchase - IAPPurchaseCallback - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Typealias - IAPPurchase​Callback -

                      - -
                      public typealias IAPPurchaseCallback = (IAPPurchaseResult) -> Void
                      -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPPurchaseDelegate/index.html b/docs/swift-doc/IAPPurchaseDelegate/index.html deleted file mode 100755 index 58bda97..0000000 --- a/docs/swift-doc/IAPPurchaseDelegate/index.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - InAppPurchase - IAPPurchaseDelegate - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Protocol - IAPPurchase​Delegate -

                      - -
                      public protocol IAPPurchaseDelegate
                      -
                      -

                      The protocol that you must adopt if you have consumable and/or nonRenewingSubscription products.

                      - -
                      -
                      - -
                      - - - - - - - - - -IAPPurchaseDelegate - - -IAPPurchaseDelegate - - - - - -DefaultPurchaseDelegate - - -DefaultPurchaseDelegate - - - - - -DefaultPurchaseDelegate->IAPPurchaseDelegate - - - - - - - - -
                      -

                      Types Conforming to IAPPurchase​Delegate

                      -
                      -
                      DefaultPurchaseDelegate
                      -

                      The default implementation of IAPPurchaseDelegate if no other is provided.

                      -
                      -
                      -
                      - - - -
                      -

                      Requirements

                      - -
                      -

                      - product​Purchased(product​Identifier:​) -

                      -
                      func productPurchased(productIdentifier: String) -> Void
                      -
                      -

                      Called when a product is newly purchased, updated or restored.

                      - -
                      -
                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      -
                      -
                      -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPPurchaseResult/index.html b/docs/swift-doc/IAPPurchaseResult/index.html deleted file mode 100755 index 19f0064..0000000 --- a/docs/swift-doc/IAPPurchaseResult/index.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - InAppPurchase - IAPPurchaseResult - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Structure - IAPPurchase​Result -

                      - -
                      public struct IAPPurchaseResult
                      - -
                      -

                      Properties

                      - -
                      -

                      - state -

                      -
                      var state: IAPPurchaseResultState
                      -
                      -
                      -

                      - iap​Error -

                      -
                      var iapError: IAPError?
                      -
                      -
                      -

                      - sk​Error -

                      -
                      var skError: SKError?
                      -
                      -
                      -

                      - localized​Description -

                      -
                      var localizedDescription: String?
                      -
                      -
                      - - - -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPPurchaseResultState/index.html b/docs/swift-doc/IAPPurchaseResultState/index.html deleted file mode 100755 index 9722438..0000000 --- a/docs/swift-doc/IAPPurchaseResultState/index.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - InAppPurchase - IAPPurchaseResultState - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Enumeration - IAPPurchase​Result​State -

                      - -
                      public enum IAPPurchaseResultState
                      - -
                      -

                      Enumeration Cases

                      - -
                      -

                      - purchased -

                      -
                      case purchased
                      -
                      -
                      -

                      - failed -

                      -
                      case failed
                      -
                      -
                      -

                      - cancelled -

                      -
                      case cancelled
                      -
                      -
                      -

                      - deferred -

                      -
                      case deferred
                      -
                      -
                      - - - -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPRefreshCallback/index.html b/docs/swift-doc/IAPRefreshCallback/index.html deleted file mode 100755 index 5184db2..0000000 --- a/docs/swift-doc/IAPRefreshCallback/index.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - InAppPurchase - IAPRefreshCallback - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Typealias - IAPRefresh​Callback -

                      - -
                      public typealias IAPRefreshCallback = (IAPRefreshResult) -> Void
                      -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPRefreshResult/index.html b/docs/swift-doc/IAPRefreshResult/index.html deleted file mode 100755 index 7d40928..0000000 --- a/docs/swift-doc/IAPRefreshResult/index.html +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - InAppPurchase - IAPRefreshResult - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Structure - IAPRefresh​Result -

                      - -
                      public struct IAPRefreshResult
                      - -
                      -

                      Properties

                      - -
                      -

                      - state -

                      -
                      var state: IAPRefreshResultState
                      -
                      -
                      -

                      - iap​Error -

                      -
                      var iapError: IAPError?
                      -
                      -
                      -

                      - added​Purchases -

                      -
                      var addedPurchases: Int
                      -
                      -
                      -

                      - updated​Purchases -

                      -
                      var updatedPurchases: Int
                      -
                      -
                      - - - -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/IAPRefreshResultState/index.html b/docs/swift-doc/IAPRefreshResultState/index.html deleted file mode 100755 index 34365cd..0000000 --- a/docs/swift-doc/IAPRefreshResultState/index.html +++ /dev/null @@ -1,77 +0,0 @@ - - - - - - InAppPurchase - IAPRefreshResultState - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Enumeration - IAPRefresh​Result​State -

                      - -
                      public enum IAPRefreshResultState
                      - -
                      -

                      Enumeration Cases

                      - -
                      -

                      - succeeded -

                      -
                      case succeeded
                      -
                      -
                      -

                      - failed -

                      -
                      case failed
                      -
                      -
                      -

                      - skipped -

                      -
                      case skipped
                      -
                      -
                      - - - -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/InAppPurchase/index.html b/docs/swift-doc/InAppPurchase/index.html deleted file mode 100755 index 559e980..0000000 --- a/docs/swift-doc/InAppPurchase/index.html +++ /dev/null @@ -1,592 +0,0 @@ - - - - - - InAppPurchase - InAppPurchase - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Class - InApp​Purchase -

                      - -
                      public class InAppPurchase: NSObject, InAppPurchaseLib
                      -
                      - -
                      - - - - - - - - - -InAppPurchase - - -InAppPurchase - - - - - -NSObject - -NSObject - - - -InAppPurchase->NSObject - - - - - -InAppPurchaseLib - - -InAppPurchaseLib - - - - - -InAppPurchase->InAppPurchaseLib - - - - - - - - -
                      -

                      Conforms To

                      -
                      -
                      InAppPurchaseLib
                      -

                      The protocol that `InAppPurchase`` adopts.

                      -
                      -
                      NSObject
                      -
                      -
                      -
                      -

                      Properties

                      - -
                      -

                      - iap​Products -

                      -
                      var iapProducts: Array<IAPProduct>
                      -
                      -

                      The array of IAPProduct.

                      - -
                      -
                      -
                      -

                      - validator​Url​String -

                      -
                      var validatorUrlString: String?
                      -
                      -

                      The validator url retrieved from Fovea.

                      - -
                      -
                      -
                      -

                      - iap​Purchase​Delegate -

                      -
                      var iapPurchaseDelegate: IAPPurchaseDelegate?
                      -
                      -

                      The instance of class that adopts the IAPPurchaseDelegate protocol.

                      - -
                      -
                      -
                      -

                      - application​Username -

                      -
                      var applicationUsername: String?
                      -
                      -

                      The user name, if your app implements user login.

                      - -
                      -
                      -
                      -
                      -

                      Methods

                      - -
                      -

                      - initialize(iap​Products:​validator​Url​String:​iap​Purchase​Delegate:​application​Username:​) -

                      -
                      public static func initialize(iapProducts: Array<IAPProduct>, validatorUrlString: String, iapPurchaseDelegate: IAPPurchaseDelegate, applicationUsername: String?)
                      -
                      -

                      Start observing the payment queue, as soon as possible, and refresh Product list and user Receipt.

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      iap​ProductsArray<IAPProduct>

                      An array of IAPProduct.

                      -
                      validator​Url​StringString

                      The validator url retrieved from Fovea.

                      -
                      iap​Purchase​DelegateIAPPurchase​Delegate

                      An instance of class that adopts the IAPPurchaseDelegate protocol (default value = DefaultPurchaseDelegate).

                      -
                      application​UsernameString?

                      The user name, if your app implements user login.

                      -
                      -
                      -
                      -

                      - stop() -

                      -
                      public static func stop()
                      -
                      -

                      Stop observing the payment queue, when the application will terminate, for proper cleanup.

                      - -
                      -
                      -
                      -

                      - refresh(callback:​) -

                      -
                      public static func refresh(callback: @escaping IAPRefreshCallback)
                      -
                      -

                      Refresh Product list and user Receipt.

                      - -
                      -
                      - - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      callback@escaping IAPRefresh​Callback

                      The function that will be called after processing.

                      -
                      -
                      -
                      -

                      - get​Products() -

                      -
                      public static func getProducts() -> Array<SKProduct>
                      -
                      -

                      Gets all products retrieved from the App Store

                      - -
                      -
                      -
                        -
                      • See also: SKProduct.
                      • -
                      - -
                      -

                      Returns

                      -

                      An array of products.

                      - -
                      -
                      -

                      - get​Product​By(identifier:​) -

                      -
                      public static func getProductBy(identifier: String) -> SKProduct?
                      -
                      -

                      Gets the product by its identifier from the list of products retrieved from the App Store.

                      - -
                      -
                      -
                        -
                      • See also: SKProduct.
                      • -
                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      identifierString

                      The identifier of the product.

                      -
                      -

                      Returns

                      -

                      The product if it was retrieved from the App Store.

                      - -
                      -
                      -

                      - can​Make​Payments() -

                      -
                      public static func canMakePayments() -> Bool
                      -
                      -

                      Checks if the user is allowed to authorize payments.

                      - -
                      -

                      Returns

                      -

                      A boolean indicates if the user is allowed.

                      - -
                      -
                      -

                      - purchase(product​Identifier:​quantity:​callback:​) -

                      -
                      public static func purchase(productIdentifier: String, quantity: Int, callback: @escaping IAPPurchaseCallback)
                      -
                      -

                      Request a Payment from the App Store.

                      - -
                      -
                      - - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product to purchase.

                      -
                      quantityInt

                      The quantity to purchase (default value = 1).

                      -
                      callback@escaping IAPPurchase​Callback

                      The function that will be called after processing.

                      -
                      -
                      -
                      -

                      - restore​Purchases(callback:​) -

                      -
                      public static func restorePurchases(callback: @escaping IAPRefreshCallback)
                      -
                      -

                      Restore purchased products.

                      - -
                      -
                      - - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      callback@escaping IAPRefresh​Callback

                      The function that will be called after processing.

                      -
                      -
                      -
                      -

                      - finish​Transactions(for:​) -

                      -
                      public static func finishTransactions(for productIdentifier: String)
                      -
                      -

                      Finish all transactions for the product.

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      -
                      -
                      -

                      - has​Deferred​Transaction(for:​) -

                      -
                      public static func hasDeferredTransaction(for productIdentifier: String) -> Bool
                      -
                      -

                      Checks if the last transaction state for a given product was deferred.

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      -

                      Returns

                      -

                      A boolean indicates if the last transaction state was deferred.

                      - -
                      -
                      -

                      - has​Already​Purchased() -

                      -
                      public static func hasAlreadyPurchased() -> Bool
                      -
                      -

                      Checks if the user has already purchased at least one product.

                      - -
                      -

                      Returns

                      -

                      A boolean indicates if the .

                      - -
                      -
                      -

                      - has​Active​Purchase(for:​) -

                      -
                      public static func hasActivePurchase(for productIdentifier: String) -> Bool
                      -
                      -

                      Checks if the user currently own (or is subscribed to) a given product (nonConsumable or autoRenewableSubscription).

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      -

                      Returns

                      -

                      A boolean indicates if the user currently own (or is subscribed to) a given product.

                      - -
                      -
                      -

                      - has​Active​Subscription() -

                      -
                      public static func hasActiveSubscription() -> Bool
                      -
                      -

                      Checks if the user has an active auto renewable subscription regardless of the product identifier.

                      - -
                      -

                      Returns

                      -

                      A boolean indicates if the user has an active auto renewable subscription.

                      - -
                      -
                      -

                      - get​Purchase​Date(for:​) -

                      -
                      public static func getPurchaseDate(for productIdentifier: String) -> Date?
                      -
                      -

                      Returns the latest purchased date for a given product.

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      -

                      Returns

                      -

                      The latest purchase Date if set or nil.

                      - -
                      -
                      -

                      - get​Expiry​Date(for:​) -

                      -
                      public static func getExpiryDate(for productIdentifier: String) -> Date?
                      -
                      -

                      Returns the expiry date for a subcription. May be past or future.

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      -

                      Returns

                      -

                      The expiry Date is set or nil.

                      - -
                      -
                      - - - -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/InAppPurchaseLib/index.html b/docs/swift-doc/InAppPurchaseLib/index.html deleted file mode 100755 index 5f0d7ed..0000000 --- a/docs/swift-doc/InAppPurchaseLib/index.html +++ /dev/null @@ -1,578 +0,0 @@ - - - - - - InAppPurchase - InAppPurchaseLib - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -

                      - Protocol - InApp​Purchase​Lib -

                      - -
                      public protocol InAppPurchaseLib
                      -
                      -

                      The protocol that `InAppPurchase`` adopts.

                      - -
                      -
                      - -
                      - - - - - - - - - -InAppPurchaseLib - - -InAppPurchaseLib - - - - - -InAppPurchase - - -InAppPurchase - - - - - -InAppPurchase->InAppPurchaseLib - - - - - - - - -
                      -

                      Types Conforming to InApp​Purchase​Lib

                      -
                      -
                      InAppPurchase
                      -
                      -
                      -
                      - - - -
                      -

                      Requirements

                      - -
                      -

                      - iap​Products -

                      -
                      var iapProducts: Array<IAPProduct>
                      -
                      -

                      The array of IAPProduct.

                      - -
                      -
                      -
                      -

                      - validator​Url​String -

                      -
                      var validatorUrlString: String?
                      -
                      -

                      The validator url retrieved from Fovea.

                      - -
                      -
                      -
                      -

                      - iap​Purchase​Delegate -

                      -
                      var iapPurchaseDelegate: IAPPurchaseDelegate?
                      -
                      -

                      The instance of class that adopts the IAPPurchaseDelegate protocol.

                      - -
                      -
                      -
                      -

                      - application​Username -

                      -
                      var applicationUsername: String?
                      -
                      -

                      The user name, if your app implements user login.

                      - -
                      -
                      -
                      -

                      - initialize(iap​Products:​validator​Url​String:​iap​Purchase​Delegate:​application​Username:​) -

                      -
                      static func initialize(iapProducts: Array<IAPProduct>, validatorUrlString: String, iapPurchaseDelegate: IAPPurchaseDelegate, applicationUsername: String?) -> Void
                      -
                      -

                      Start observing the payment queue, as soon as possible, and refresh Product list and user Receipt.

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      iap​ProductsArray<IAPProduct>

                      An array of IAPProduct.

                      -
                      validator​Url​StringString

                      The validator url retrieved from Fovea.

                      -
                      iap​Purchase​DelegateIAPPurchase​Delegate

                      An instance of class that adopts the IAPPurchaseDelegate protocol (default value = DefaultPurchaseDelegate).

                      -
                      application​UsernameString?

                      The user name, if your app implements user login.

                      -
                      -
                      -
                      -

                      - stop() -

                      -
                      static func stop() -> Void
                      -
                      -

                      Stop observing the payment queue, when the application will terminate, for proper cleanup.

                      - -
                      -
                      -
                      -

                      - refresh(callback:​) -

                      -
                      static func refresh(callback: @escaping IAPRefreshCallback) -> Void
                      -
                      -

                      Refresh Product list and user Receipt.

                      - -
                      -
                      - - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      callback@escaping IAPRefresh​Callback

                      The function that will be called after processing.

                      -
                      -
                      -
                      -

                      - get​Products() -

                      -
                      static func getProducts() -> Array<SKProduct>
                      -
                      -

                      Gets all products retrieved from the App Store

                      - -
                      -
                      -
                        -
                      • See also: SKProduct.
                      • -
                      - -
                      -

                      Returns

                      -

                      An array of products.

                      - -
                      -
                      -

                      - get​Product​By(identifier:​) -

                      -
                      static func getProductBy(identifier: String) -> SKProduct?
                      -
                      -

                      Gets the product by its identifier from the list of products retrieved from the App Store.

                      - -
                      -
                      -
                        -
                      • See also: SKProduct.
                      • -
                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      identifierString

                      The identifier of the product.

                      -
                      -

                      Returns

                      -

                      The product if it was retrieved from the App Store.

                      - -
                      -
                      -

                      - can​Make​Payments() -

                      -
                      static func canMakePayments() -> Bool
                      -
                      -

                      Checks if the user is allowed to authorize payments.

                      - -
                      -

                      Returns

                      -

                      A boolean indicates if the user is allowed.

                      - -
                      -
                      -

                      - purchase(product​Identifier:​quantity:​callback:​) -

                      -
                      static func purchase(productIdentifier: String, quantity: Int, callback: @escaping IAPPurchaseCallback) -> Void
                      -
                      -

                      Request a Payment from the App Store.

                      - -
                      -
                      - - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product to purchase.

                      -
                      quantityInt

                      The quantity to purchase (default value = 1).

                      -
                      callback@escaping IAPPurchase​Callback

                      The function that will be called after processing.

                      -
                      -
                      -
                      -

                      - restore​Purchases(callback:​) -

                      -
                      static func restorePurchases(callback: @escaping IAPRefreshCallback) -> Void
                      -
                      -

                      Restore purchased products.

                      - -
                      -
                      - - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      callback@escaping IAPRefresh​Callback

                      The function that will be called after processing.

                      -
                      -
                      -
                      -

                      - finish​Transactions(for:​) -

                      -
                      static func finishTransactions(for productIdentifier: String) -> Void
                      -
                      -

                      Finish all transactions for the product.

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      -
                      -
                      -

                      - has​Deferred​Transaction(for:​) -

                      -
                      static func hasDeferredTransaction(for productIdentifier: String) -> Bool
                      -
                      -

                      Checks if the last transaction state for a given product was deferred.

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      -

                      Returns

                      -

                      A boolean indicates if the last transaction state was deferred.

                      - -
                      -
                      -

                      - has​Already​Purchased() -

                      -
                      static func hasAlreadyPurchased() -> Bool
                      -
                      -

                      Checks if the user has already purchased at least one product.

                      - -
                      -

                      Returns

                      -

                      A boolean indicates if the .

                      - -
                      -
                      -

                      - has​Active​Purchase(for:​) -

                      -
                      static func hasActivePurchase(for productIdentifier: String) -> Bool
                      -
                      -

                      Checks if the user currently own (or is subscribed to) a given product (nonConsumable or autoRenewableSubscription).

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      -

                      Returns

                      -

                      A boolean indicates if the user currently own (or is subscribed to) a given product.

                      - -
                      -
                      -

                      - has​Active​Subscription() -

                      -
                      static func hasActiveSubscription() -> Bool
                      -
                      -

                      Checks if the user has an active auto renewable subscription regardless of the product identifier.

                      - -
                      -

                      Returns

                      -

                      A boolean indicates if the user has an active auto renewable subscription.

                      - -
                      -
                      -

                      - get​Purchase​Date(for:​) -

                      -
                      static func getPurchaseDate(for productIdentifier: String) -> Date?
                      -
                      -

                      Returns the latest purchased date for a given product.

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      -

                      Returns

                      -

                      The latest purchase Date if set or nil.

                      - -
                      -
                      -

                      - get​Expiry​Date(for:​) -

                      -
                      static func getExpiryDate(for productIdentifier: String) -> Date?
                      -
                      -

                      Returns the expiry date for a subcription. May be past or future.

                      - -
                      -

                      Parameters

                      - - - - - - - - - - - - - - - - -
                      product​IdentifierString

                      The identifier of the product.

                      -
                      -

                      Returns

                      -

                      The expiry Date is set or nil.

                      - -
                      -
                      -
                      -
                      - -
                      -

                      - Generated on using swift-doc. -

                      -
                      - - diff --git a/docs/swift-doc/all.css b/docs/swift-doc/all.css deleted file mode 100755 index 4e9b4a7..0000000 --- a/docs/swift-doc/all.css +++ /dev/null @@ -1 +0,0 @@ -:root{--system-red:#ff3b30;--system-orange:#ff9500;--system-yellow:#fc0;--system-green:#34c759;--system-teal:#5ac8fa;--system-blue:#007aff;--system-indigo:#5856d6;--system-purple:#af52de;--system-pink:#ff2d55;--system-gray:#8e8e93;--system-gray2:#aeaeb2;--system-gray3:#c7c7cc;--system-gray4:#d1d1d6;--system-gray5:#e5e5ea;--system-gray6:#f2f2f7;--label:#000;--secondary-label:#3c3c43;--tertiary-label:#48484a;--quaternary-label:#636366;--placeholder-text:#8e8e93;--link:#007aff;--separator:#e5e5ea;--opaque-separator:#c6c6c8;--system-fill:#787880;--secondary-system-fill:#787880;--tertiary-system-fill:#767680;--quaternary-system-fill:#747480;--system-background:#fff;--secondary-system-background:#f2f2f7;--tertiary-system-background:#fff;--system-grouped-background:#f2f2f7;--secondary-system-grouped-background:#fff;--tertiary-system-grouped-background:#f2f2f7}@supports (color:color(display-p3 1 1 1)){:root{--system-red:color(display-p3 1 0.2314 0.1882);--system-orange:color(display-p3 1 0.5843 0);--system-yellow:color(display-p3 1 0.8 0);--system-green:color(display-p3 0.2039 0.7804 0.349);--system-teal:color(display-p3 0.3529 0.7843 0.9804);--system-blue:color(display-p3 0 0.4784 1);--system-indigo:color(display-p3 0.3451 0.3373 0.8392);--system-purple:color(display-p3 0.6863 0.3216 0.8706);--system-pink:color(display-p3 1 0.1765 0.3333);--system-gray:color(display-p3 0.5569 0.5569 0.5765);--system-gray2:color(display-p3 0.6824 0.6824 0.698);--system-gray3:color(display-p3 0.7804 0.7804 0.8);--system-gray4:color(display-p3 0.8196 0.8196 0.8392);--system-gray5:color(display-p3 0.898 0.898 0.9176);--system-gray6:color(display-p3 0.949 0.949 0.9686);--label:color(display-p3 0 0 0);--secondary-label:color(display-p3 0.2353 0.2353 0.2627);--tertiary-label:color(display-p3 0.2823 0.2823 0.2901);--quaternary-label:color(display-p3 0.4627 0.4627 0.5019);--placeholder-text:color(display-p3 0.5568 0.5568 0.5764);--link:color(display-p3 0 0.4784 1);--separator:color(display-p3 0.898 0.898 0.9176);--opaque-separator:color(display-p3 0.7765 0.7765 0.7843);--system-fill:color(display-p3 0.4706 0.4706 0.502);--secondary-system-fill:color(display-p3 0.4706 0.4706 0.502);--tertiary-system-fill:color(display-p3 0.4627 0.4627 0.502);--quaternary-system-fill:color(display-p3 0.4549 0.4549 0.502);--system-background:color(display-p3 1 1 1);--secondary-system-background:color(display-p3 0.949 0.949 0.9686);--tertiary-system-background:color(display-p3 1 1 1);--system-grouped-background:color(display-p3 0.949 0.949 0.9686);--secondary-system-grouped-background:color(display-p3 1 1 1);--tertiary-system-grouped-background:color(display-p3 0.949 0.949 0.9686)}}:root{--large-title:600 32pt/39pt sans-serif;--title-1:600 26pt/32pt sans-serif;--title-2:600 20pt/25pt sans-serif;--title-3:500 18pt/23pt sans-serif;--headline:500 15pt/20pt sans-serif;--body:300 15pt/20pt sans-serif;--callout:300 14pt/19pt sans-serif;--subhead:300 13pt/18pt sans-serif;--footnote:300 12pt/16pt sans-serif;--caption-1:300 11pt/13pt sans-serif;--caption-2:300 11pt/13pt sans-serif;--icon-case:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32H64.19C63.4 35 58.09 30.11 51 30.11c-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25C32 82.81 20.21 70.72 20.21 50z' fill='%23fff'/%3E%3C/svg%3E");--icon-class:url("data:image/svg+xml;utf8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%239b98e6' height='90' rx='8' stroke='%235856d6' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='m20.21 50c0-20.7 11.9-32.79 30.8-32.79 16 0 28.21 10.33 28.7 25.32h-15.52c-.79-7.53-6.1-12.42-13.19-12.42-8.79 0-14.37 7.52-14.37 19.82s5.54 20 14.41 20c7.08 0 12.22-4.66 13.23-12.09h15.52c-.74 15.07-12.43 25-28.78 25-19.01-.03-30.8-12.12-30.8-32.84z' fill='%23fff'/%3E%3C/svg%3E");--icon-enumeration:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5.17' y='5'/%3E%3Cpath d='M71.9 81.71H28.43V18.29H71.9v13H44.56v12.62h25.71v11.87H44.56V68.7H71.9z' fill='%23fff'/%3E%3C/svg%3E");--icon-extension:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23eca95b' height='90' rx='8' stroke='%23e89234' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M54.43 81.93H20.51V18.07h33.92v12.26H32.61v13.8h20.45v11.32H32.61v14.22h21.82zM68.74 74.58h-.27l-2.78 7.35h-7.28L64 69.32l-6-12.54h8l2.74 7.3h.27l2.76-7.3h7.64l-6.14 12.54 5.89 12.61h-7.64z'/%3E%3C/g%3E%3C/svg%3E");--icon-function:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M24.25 75.66A5.47 5.47 0 0130 69.93c1.55 0 3.55.41 6.46.41 3.19 0 4.78-1.55 5.46-6.65l1.5-10.14h-9.34a6 6 0 110-12h11.1l1.09-7.27C47.82 23.39 54.28 17.7 64 17.7c6.69 0 11.74 1.77 11.74 6.64A5.47 5.47 0 0170 30.07c-1.55 0-3.55-.41-6.46-.41-3.14 0-4.73 1.51-5.46 6.65l-.78 5.27h11.44a6 6 0 11.05 12H55.6l-1.78 12.11C52.23 76.61 45.72 82.3 36 82.3c-6.7 0-11.75-1.77-11.75-6.64z' fill='%23fff'/%3E%3C/svg%3E");--icon-method:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%235a98f8' height='90' rx='8' stroke='%232974ed' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M70.61 81.71v-39.6h-.31l-15.69 39.6h-9.22l-15.65-39.6h-.35v39.6H15.2V18.29h18.63l16 41.44h.36l16-41.44H84.8v63.42z' fill='%23fff'/%3E%3C/svg%3E");--icon-property:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%2389c5e6' height='90' rx='8' stroke='%236bb7e1' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M52.31 18.29c13.62 0 22.85 8.84 22.85 22.46s-9.71 22.37-23.82 22.37H41v18.59H24.84V18.29zM41 51h7c6.85 0 10.89-3.56 10.89-10.2S54.81 30.64 48 30.64h-7z' fill='%23fff'/%3E%3C/svg%3E");--icon-protocol:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23ff6682' height='90' rx='8' stroke='%23ff2d55' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cg fill='%23fff'%3E%3Cpath d='M46.28 18.29c11.84 0 20 8.66 20 21.71s-8.44 21.71-20.6 21.71H34.87v20H22.78V18.29zM34.87 51.34H43c6.93 0 11-4 11-11.29S50 28.8 43.07 28.8h-8.2zM62 57.45h8v4.77h.16c.84-3.45 2.54-5.12 5.17-5.12a5.06 5.06 0 011.92.35V65a5.69 5.69 0 00-2.39-.51c-3.08 0-4.66 1.74-4.66 5.12v12.1H62z'/%3E%3C/g%3E%3C/svg%3E");--icon-structure:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%23b57edf' height='90' rx='8' stroke='%239454c2' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M38.38 63c.74 4.53 5.62 7.16 11.82 7.16s10.37-2.81 10.37-6.68c0-3.51-2.73-5.31-10.24-6.76l-6.5-1.23C31.17 53.14 24.62 47 24.62 37.28c0-12.22 10.59-20.09 25.18-20.09 16 0 25.36 7.83 25.53 19.91h-15c-.26-4.57-4.57-7.29-10.42-7.29s-9.31 2.63-9.31 6.37c0 3.34 2.9 5.18 9.8 6.5l6.5 1.23C70.46 46.51 76.61 52 76.61 62c0 12.74-10 20.83-26.72 20.83-15.82 0-26.28-7.3-26.5-19.78z' fill='%23fff'/%3E%3C/svg%3E");--icon-typealias:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M42 81.71V31.3H24.47v-13h51.06v13H58v50.41z' fill='%23fff'/%3E%3C/svg%3E");--icon-variable:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Crect fill='%237ac673' height='90' rx='8' stroke='%235bb74f' stroke-miterlimit='10' stroke-width='4' width='90' x='5' y='5'/%3E%3Cpath d='M39.85 81.71L19.63 18.29H38l12.18 47.64h.35L62.7 18.29h17.67L60.15 81.71z' fill='%23fff'/%3E%3C/svg%3E")}body,button,input,select,textarea{-moz-font-feature-settings:"kern";-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;direction:ltr;font-synthesis:none;text-align:left}h1:first-of-type,h2:first-of-type,h3:first-of-type,h4:first-of-type,h5:first-of-type,h6:first-of-type{margin-top:0}h1 code,h2 code,h3 code,h4 code,h5 code,h6 code{font-family:inherit;font-weight:inherit}h1 img,h2 img,h3 img,h4 img,h5 img,h6 img{margin:0 .5em .2em 0;vertical-align:middle;display:inline-block}h1+*,h2+*,h3+*,h4+*,h5+*,h6+*{margin-top:.8em}img+h1{margin-top:.5em}img+h1,img+h2,img+h3,img+h4,img+h5,img+h6{margin-top:.3em}:is(h1,h2,h3,h4,h5,h6)+:is(h1,h2,h3,h4,h5,h6){margin-top:.4em}:matches(h1,h2,h3,h4,h5,h6)+:matches(h1,h2,h3,h4,h5,h6){margin-top:.4em}:is(p,ul,ol)+:is(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:matches(p,ul,ol)+:matches(h1,h2,h3,h4,h5,h6){margin-top:1.6em}:is(p,ul,ol)+*{margin-top:.8em}:matches(p,ul,ol)+*{margin-top:.8em}ol,ul{margin-left:1.17647em}:matches(ul,ol) :matches(ul,ol){margin-bottom:0;margin-top:0}nav h2{color:#3c3c43;color:var(--secondary-label);font-size:1rem;font-feature-settings:"c2sc";font-variant:small-caps;font-weight:600;text-transform:uppercase}nav ol,nav ul{margin:0;list-style:none}nav li li{font-size:smaller}a:link,a:visited{text-decoration:none}a:hover{text-decoration:underline}a:active{text-decoration:none}a+a{display:inline-block}b,strong{font-weight:600}.discussion,.summary{font:300 14pt/19pt sans-serif;font:var(--callout)}article>.discussion{margin-bottom:2em}.discussion .highlight{background:transparent;border:1px solid #e5e5ea;border:1px solid var(--separator);font:300 11pt/13pt sans-serif;font:var(--caption-1);padding:1em;text-indent:0}cite,dfn,em,i{font-style:italic}:matches(h1,h2,h3) sup{font-size:.4em}sup a{color:inherit;vertical-align:inherit}sup a:hover{color:#007aff;color:var(--link);text-decoration:none}sub{line-height:1}abbr{border:0}:lang(ja),:lang(ko),:lang(th),:lang(zh){font-style:normal}:lang(ko){word-break:keep-all}form fieldset{margin:1em auto;max-width:450px;width:95%}form label{display:block;font-size:1em;font-weight:400;line-height:1.5em;margin-bottom:14px;position:relative;width:100%}input[type=email],input[type=number],input[type=password],input[type=tel],input[type=text],input[type=url],textarea{border-radius:4px;border:1px solid #e5e5ea;border:1px solid var(--separator);color:#333;font-family:inherit;font-size:100%;font-weight:400;height:34px;margin:0;padding:0 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=email],input [type=email]:focus,input[type=number],input [type=number]:focus,input[type=password],input [type=password]:focus,input[type=tel],input [type=tel]:focus,input[type=text],input [type=text]:focus,input[type=url],input [type=url]:focus,textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}input[type=email]:focus,input[type=number]:focus,input[type=password]:focus,input[type=tel]:focus,input[type=text]:focus,input[type=url]:focus,textarea:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=email]:-moz-read-only,input[type=number]:-moz-read-only,input[type=password]:-moz-read-only,input[type=tel]:-moz-read-only,input[type=text]:-moz-read-only,input[type=url]:-moz-read-only,textarea:-moz-read-only{background:none;border:none;box-shadow:none;padding-left:0}input[type=email]:read-only,input[type=number]:read-only,input[type=password]:read-only,input[type=tel]:read-only,input[type=text]:read-only,input[type=url]:read-only,textarea:read-only{background:none;border:none;box-shadow:none;padding-left:0}::-webkit-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-moz-placeholder{color:#8e8e93;color:var(--placeholder-text)}:-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::-ms-input-placeholder{color:#8e8e93;color:var(--placeholder-text)}::placeholder{color:#8e8e93;color:var(--placeholder-text)}textarea{-webkit-overflow-scrolling:touch;line-height:1.4737;min-height:134px;overflow-y:auto;resize:vertical;transform:translateZ(0)}textarea,textarea:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select{background:transparent;border-radius:4px;border:none;cursor:pointer;font-family:inherit;font-size:1em;height:34px;margin:0;padding:0 1em;width:100%}select,select:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}select:focus{border-color:#08c;box-shadow:0 0 0 3px rgba(0,136,204,.3);outline:0;z-index:9}input[type=file]{background:#fafafa;border-radius:4px;color:#333;cursor:pointer;font-family:inherit;font-size:100%;height:34px;margin:0;padding:6px 1em;position:relative;vertical-align:top;width:100%;z-index:1}input[type=file]:focus{border-color:#08c;outline:0;box-shadow:0 0 0 3px rgba(0,136,204,.3);z-index:9}button,button:focus,input[type=file]:focus,input[type=file]:focus:focus,input[type=reset],input[type=reset]:focus,input[type=submit],input[type=submit]:focus{-webkit-appearance:none;-moz-appearance:none;appearance:none}:matches(button,input[type=reset],input[type=submit]){background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}:matches(button,input[type=reset],input[type=submit]):hover{background-color:#eee;background:linear-gradient(#fff,#eee);border-color:#d9d9d9}:matches(button,input[type=reset],input[type=submit]):active{background-color:#dcdcdc;background:linear-gradient(#f7f7f7,#dcdcdc);border-color:#d0d0d0}:matches(button,input[type=reset],input[type=submit]):disabled{background-color:#e3e3e3;background:linear-gradient(#fff,#e3e3e3);border-color:#d6d6d6;color:#0070c9}body{background:#f2f2f7;background:var(--system-grouped-background);color:#000;color:var(--label);font-family:ui-system,-apple-system,BlinkMacSystemFont,sans-serif;font:300 15pt/20pt sans-serif;font:var(--body)}h1{font:600 32pt/39pt sans-serif;font:var(--large-title)}h2{font:600 20pt/25pt sans-serif;font:var(--title-2)}h3{font:500 18pt/23pt sans-serif;font:var(--title-3)}h4,h5,h6{font:500 15pt/20pt sans-serif;font:var(--headline)}a{color:#007aff;color:var(--link)}label{font:300 14pt/19pt sans-serif;font:var(--callout)}input,label{display:block}input{margin-bottom:1em}hr{border:none;border-top:1px solid #e5e5ea;border-top:1px solid var(--separator);margin:1em 0}table{width:100%;font:300 11pt/13pt sans-serif;font:var(--caption-1);caption-side:bottom;margin-bottom:2em}td,th{padding:0 1em}th{font-weight:600;text-align:left}thead th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator)}tr:last-of-type td,tr:last-of-type th{border-bottom:none}td,th{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);color:#3c3c43;color:var(--secondary-label)}caption{color:#48484a;color:var(--tertiary-label);font:300 11pt/13pt sans-serif;font:var(--caption-2);margin-top:2em;text-align:left}.graph text,code{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-weight:300}.graph>polygon{display:none}.graph text{fill:currentColor!important}.graph ellipse,.graph path,.graph polygon,.graph rect{stroke:currentColor!important}body{width:90vw;max-width:1280px;margin:1em auto}body>header{font:600 26pt/32pt sans-serif;font:var(--title-1);padding:.5em 0}body>header a{color:#000;color:var(--label)}body>header span{font-weight:400}body>header sup{text-transform:uppercase;font-size:small;font-weight:300;letter-spacing:.1ch}body>footer,body>header sup{color:#3c3c43;color:var(--secondary-label)}body>footer{clear:both;padding:1em 0;font:300 11pt/13pt sans-serif;font:var(--caption-1)}@media screen and (max-width:768px){body{width:96vw;max-width:100%}body>header{font:500 18pt/23pt sans-serif;font:var(--title-3);text-align:left;padding:1em 0}body>nav{display:none}body>main{padding:0 1em}}@media screen and (max-width:768px){#relationships figure{display:none}section>[role=article][class] pre{margin-left:-2.5em}section>[role=article][class] div{margin-left:-2em}}main,nav{overflow-x:scroll}main{background:#fff;background:var(--system-background);border-radius:8px;padding:0 2em}main section{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}main section:last-of-type{border-bottom:none;margin-bottom:0}nav{float:right;margin-left:1em;max-height:100vh;overflow:scroll;padding:0 1em 3em;position:-webkit-sticky;position:sticky;top:1em;width:20vw}nav a{color:#3c3c43;color:var(--secondary-label)}nav ul a{color:#48484a;color:var(--tertiary-label)}nav ol,nav ul{padding:0}nav ul{font:300 14pt/19pt sans-serif;font:var(--callout);margin-bottom:1em}nav ol>li>a{display:block;font-size:smaller;font:500 15pt/20pt sans-serif;font:var(--headline);margin:.5em 0}nav li{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}blockquote{--link:var(--secondary-label);border-left:4px solid #e5e5ea;border-left:4px solid var(--separator);color:#3c3c43;color:var(--secondary-label);font-size:smaller;margin-left:0;padding-left:2em}blockquote a{text-decoration:underline}article{padding:2em 0 1em}article>.summary{border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);margin-bottom:2em;padding-bottom:1em}article>.summary:last-child{border-bottom:none}.parameters th{text-align:right}.parameters td{color:#3c3c43;color:var(--secondary-label)}.parameters th+td{text-align:center}dl{padding-top:1em}dt{font:500 15pt/20pt sans-serif;font:var(--headline)}dd{margin-left:2em;margin-bottom:1em}dd p{margin-top:0}.highlight{background:#f2f2f7;background:var(--secondary-system-background);border-radius:8px;font-size:smaller;margin-bottom:2em;overflow-x:scroll;padding:1em 1em 1em 3em;text-indent:-2em;white-space:pre-line}.highlight .p{white-space:nowrap}.highlight .placeholder{color:#000;color:var(--label)}.highlight a{text-decoration:underline;color:#8e8e93;color:var(--placeholder-text)}.highlight .attribute,.highlight .keyword,.highlight .literal{color:#af52de;color:var(--system-purple)}.highlight .number{color:#007aff;color:var(--system-blue)}.highlight .declaration{color:#5ac8fa;color:var(--system-teal)}.highlight .type{color:#5856d6;color:var(--system-indigo)}.highlight .directive{color:#ff9500;color:var(--system-orange)}.highlight .comment{color:#8e8e93;color:var(--system-gray)}main summary:hover{text-decoration:underline}figure{margin:2em 0;padding:1em 0}figure svg{max-width:100%;height:auto!important;margin:0 auto;display:block}h1 small{font-size:.5em;line-height:1.5;display:block;font-weight:400;color:#636366;color:var(--quaternary-label)}dd code,li code,p code{font-size:smaller;color:#3c3c43;color:var(--secondary-label)}a code{text-decoration:underline}dl dt[class],nav li[class],section>[role=article][class]{background-image:var(--background-image);background-size:1em;background-repeat:no-repeat;background-position:left .25em;padding-left:3em}dl dt[class]{background-position-y:.125em}section>[role=article]{margin-bottom:1em;padding-bottom:1em;border-bottom:1px solid #e5e5ea;border-bottom:1px solid var(--separator);padding-left:2em!important}section>[role=article]:last-of-type{margin-bottom:0;padding-bottom:0;border-bottom:none}dl dt[class],nav li[class]{list-style:none;text-indent:-1em;margin-bottom:.5em}nav li[class]{padding-left:2.5em}.case,.enumeration_case{--background-image:var(--icon-case);--link:var(--system-teal)}.class{--background-image:var(--icon-class);--link:var(--system-indigo)}.enumeration{--background-image:var(--icon-enumeration)}.enumeration,.extension{--link:var(--system-orange)}.extension{--background-image:var(--icon-extension)}.function{--background-image:var(--icon-function);--link:var(--system-green)}.initializer,.method{--background-image:var(--icon-method);--link:var(--system-blue)}.property{--background-image:var(--icon-property);--link:var(--system-teal)}.protocol{--background-image:var(--icon-protocol);--link:var(--system-pink)}.structure{--background-image:var(--icon-structure);--link:var(--system-purple)}.typealias{--background-image:var(--icon-typealias)}.typealias,.variable{--link:var(--system-green)}.variable{--background-image:var(--icon-variable)}.unknown{--link:var(--quaternary-label);color:#007aff;color:var(--link)} \ No newline at end of file diff --git a/docs/swift-doc/index.html b/docs/swift-doc/index.html deleted file mode 100755 index 666ea3b..0000000 --- a/docs/swift-doc/index.html +++ /dev/null @@ -1,204 +0,0 @@ - - - - - - InAppPurchase - InAppPurchase - - - - -
                      - - - InAppPurchase - - Documentation - - Beta -
                      - - - - - -
                      -
                      -
                      -

                      Classes

                      -
                      -
                      - - InApp​Purchase - -
                      -
                      - -
                      -
                      - - Default​Purchase​Delegate - -
                      -
                      -

                      The default implementation of IAPPurchaseDelegate if no other is provided.

                      - -
                      -
                      -
                      -
                      -

                      Structures

                      -
                      -
                      - - IAPPurchase​Result - -
                      -
                      - -
                      -
                      - - IAPRefresh​Result - -
                      -
                      - -
                      -
                      - - IAPError - -
                      -
                      - -
                      -
                      - - IAPProduct - -
                      -
                      - -
                      -
                      -
                      -
                      -

                      Enumerations

                      -
                      -
                      - - IAPPurchase​Result​State - -
                      -
                      - -
                      -
                      - - IAPRefresh​Result​State - -
                      -
                      - -
                      -
                      - - IAPError​Code - -
                      -
                      - -
                      -
                      - - IAPProduct​Type - -
                      -
                      - -
                      -
                      - - IAPPeriod​Format - -
                      -
                      - -
                      -
                      -
                      -
                      -

                      Protocols

                      -
                      -
                      - - IAPError​Protocol - -
                      -
                      - -
                      -
                      - - InApp​Purchase​Lib - -
                      -
                      -

                      The protocol that `InAppPurchase`` adopts.

                      - -
                      -
                      - - IAPPurchase​Delegate - -
                      -
                      -

                      The protocol that you must adopt if you have consumable and/or nonRenewingSubscription products.

                      - -
                      -
                      -
                      -
                      -

                      Globals

                      -
                      -

                      Typealiases

                      -
                      -
                      - - IAPPurchase​Callback - -
                      -
                      - -
                      -
                      - - IAPRefresh​Callback - -
                      -
                      - -
                      -
                      -
                      -
                      -
                      -
                      - - - - diff --git a/docs/undocumented.json b/docs/undocumented.json new file mode 100644 index 0000000..f5e8bed --- /dev/null +++ b/docs/undocumented.json @@ -0,0 +1,166 @@ +{ + "warnings": [ + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", + "line": 12, + "symbol": "IAPPurchaseCallback", + "symbol_kind": "source.lang.swift.decl.typealias", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", + "line": 16, + "symbol": "IAPPurchaseResult.state", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", + "line": 17, + "symbol": "IAPPurchaseResult.iapError", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", + "line": 18, + "symbol": "IAPPurchaseResult.skError", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", + "line": 20, + "symbol": "IAPPurchaseResult.localizedDescription", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", + "line": 40, + "symbol": "IAPRefreshCallback", + "symbol_kind": "source.lang.swift.decl.typealias", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", + "line": 44, + "symbol": "IAPRefreshResult.state", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", + "line": 45, + "symbol": "IAPRefreshResult.iapError", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", + "line": 46, + "symbol": "IAPRefreshResult.addedPurchases", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPCallback.swift", + "line": 47, + "symbol": "IAPRefreshResult.updatedPurchases", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", + "line": 11, + "symbol": "IAPErrorProtocol", + "symbol_kind": "source.lang.swift.decl.protocol", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Common/IAPError.swift", + "line": 12, + "symbol": "IAPErrorProtocol.code", + "symbol_kind": "source.lang.swift.decl.var.instance", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/InAppPurchaseLib.swift", + "line": 131, + "symbol": "DefaultPurchaseDelegate.init()", + "symbol_kind": "source.lang.swift.decl.function.method.instance", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/IAPProduct.swift", + "line": 10, + "symbol": "IAPProduct", + "symbol_kind": "source.lang.swift.decl.struct", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/IAPProduct.swift", + "line": 30, + "symbol": "IAPProductType", + "symbol_kind": "source.lang.swift.decl.enum", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/IAPProduct.swift", + "line": 31, + "symbol": "IAPProductType.consumable", + "symbol_kind": "source.lang.swift.decl.enumelement", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/IAPProduct.swift", + "line": 32, + "symbol": "IAPProductType.nonConsumable", + "symbol_kind": "source.lang.swift.decl.enumelement", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/IAPProduct.swift", + "line": 33, + "symbol": "IAPProductType.nonRenewingSubscription", + "symbol_kind": "source.lang.swift.decl.enumelement", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/IAPProduct.swift", + "line": 34, + "symbol": "IAPProductType.autoRenewableSubscription", + "symbol_kind": "source.lang.swift.decl.enumelement", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/SKProductExtension.swift", + "line": 12, + "symbol": "IAPPeriodFormat", + "symbol_kind": "source.lang.swift.decl.enum", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/SKProductExtension.swift", + "line": 13, + "symbol": "IAPPeriodFormat.short", + "symbol_kind": "source.lang.swift.decl.enumelement", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/SKProductExtension.swift", + "line": 14, + "symbol": "IAPPeriodFormat.long", + "symbol_kind": "source.lang.swift.decl.enumelement", + "warning": "undocumented" + }, + { + "file": "/Users/veronique/Documents/iap-swift-lib/Sources/InAppPurchaseLib/Product/SKProductExtension.swift", + "line": 20, + "symbol": "SKProduct.localizedPeriodFormat", + "symbol_kind": "source.lang.swift.decl.var.static", + "warning": "undocumented" + } + ], + "source_directory": "/Users/veronique/Documents/iap-swift-lib" +} \ No newline at end of file