Skip to content

Commit

Permalink
Update comments and documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
iridescent-dev committed May 22, 2020
1 parent 2cf152f commit 1b5e18d
Show file tree
Hide file tree
Showing 89 changed files with 491 additions and 712 deletions.
1 change: 0 additions & 1 deletion .jazzy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ custom_categories:
children:
- "Installation"
- "Micro Example"
- "License"
- name: "Usage"
children:
- "Initialization"
Expand Down
2 changes: 1 addition & 1 deletion Documentation/Getting Started.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
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
# 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:
Expand Down
19 changes: 13 additions & 6 deletions Documentation/Getting Started/Installation.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
# Installation
<p align="center">
<img src="img/ScreenshotInstallation.png" title="Installation">
</p>

* Select your project in Xcode
* Go to the section *Swift Package*
* Click on *(+) Add Package Dependency*

<p align="center">
<img src="img/ScreenshotInstallation.png" title="ScreenshotInstallation">
</p>

* Copy the Git URL: *https://github.com/iridescent-dev/iap-swift-lib.git*
* Click on *Next* > *Next*
* Click on *Next*
* In *Rules* select *Version: Up to Next Major ...*
* Click on *Next*

<p align="center">
<img src="img/ScreenshotInstallation2.png" title="ScreenshotInstallation2">
</p>

* Make sure your project is selected in *Add to target*
* Click on *Finish*

*Note:* You have to `import InAppPurchaseLib` wherever you use the library.
4 changes: 3 additions & 1 deletion Documentation/Getting Started/Micro Example.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}

func applicationWillTerminate(_ application: UIApplication) {
// Clean
// Stop library when the application will terminate
InAppPurchase.stop()
}
}
Expand Down Expand Up @@ -71,6 +71,7 @@ class ViewController: UIViewController {
}
}

// Initiating a purchase
@IBAction func purchase(_ sender: Any) {
self.loaderView.show()
InAppPurchase.purchase(
Expand All @@ -80,6 +81,7 @@ class ViewController: UIViewController {
})
}

// Restoring purchases
@IBAction func restorePurchases(_ sender: Any) {
self.loaderView.show()
InAppPurchase.restorePurchases(callback: { result in
Expand Down
21 changes: 0 additions & 21 deletions Documentation/License.md

This file was deleted.

8 changes: 4 additions & 4 deletions Documentation/Usage/Displaying products with purchases.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# 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.
## 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 the example later in this section.

### Deferred purchases
## 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:
Expand All @@ -28,7 +28,7 @@ We will use the `hasDeferredTransaction` method:
InAppPurchase.hasDeferredTransaction(for productIdentifier: String) -> Bool
```

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

``` swift
Expand Down
4 changes: 2 additions & 2 deletions Documentation/Usage/Displaying products.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# 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.
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](Extensions/SKProduct.html).

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_).
- `localizedPrice: String` - The cost of the product in the local currency (_read-only property added by this library, available for OSX >= 10.13.2 and iOS >= 11.2_).

*Example*:

Expand Down
10 changes: 9 additions & 1 deletion Documentation/Usage/Displaying subscriptions.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Displaying subscriptions
For subscription products, you also have some data about subscription periods and introductory offers.
You can retrieve all information about a 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](Extensions/SKProduct.html).

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, available for OSX >= 10.13.2 and iOS >= 11.2_).

For subscription products, you also have some data about subscription periods and introductory offers. (_read-only property added by this library, available for OSX >= 10.13.2 and iOS >= 11.2_)

- `func hasIntroductoryPriceEligible() -> Bool` - The product has an introductory price the user is eligible to.
- `localizedSubscriptionPeriod: String?` - The period of the subscription.
Expand Down
2 changes: 1 addition & 1 deletion Documentation/Usage/Purchasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ That is why the process looks like so:
- finalizing transactions when product delivery is complete
- sending purchase request, for which successful doesn't always mean complete

### Initiating a purchase
## 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!
Expand Down
140 changes: 57 additions & 83 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,104 +19,78 @@
# 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)

## 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*
* Click on *Next*
* In *Rules* select *Version: Up to Next Major ...*
* Click on *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

```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()
}
## Basic Usage

* Initialize the library
``` swift
InAppPurchase.initialize(
iapProducts: [ IAPProduct(productIdentifier: "my_product", productType: .nonConsumable) ],
validatorUrlString: "https://validator.fovea.cc/v1/validate?appName=demo&apiKey=12345678"
)
```

* Stop library when the application will terminate
``` swift
func applicationWillTerminate(_ application: UIApplication) {
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
* Display product information
``` swift
guard let product: SKProduct = InAppPurchase.getProductBy(identifier: "my_product") else { return }
productTitleLabel.text = product.localizedTitle
productDescriptionLabel.text = product.localizedDescription
productPriceLabel.text = product.localizedPrice
```

* Initialize a purchase
``` swift
@IBAction func purchase(_ sender: Any) {
self.loaderView.show()
InAppPurchase.purchase(
productIdentifier: "my_product",
callback: { result in
self.loaderView.hide()
})
}
}
```

* Unlock purchased content
``` swift
if InAppPurchase.hasActivePurchase(for: "my_product") {
// display content related to the product
}
```

* Restore purchases
``` swift
@IBAction func restorePurchases(_ sender: Any) {
self.loaderView.show()
InAppPurchase.restorePurchases(callback: { result in
self.loaderView.hide()
})
}
```

Expand Down
22 changes: 22 additions & 0 deletions Sources/InAppPurchaseLib/Common/IAPCallback.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,19 @@ public typealias IAPPurchaseCallback = (IAPPurchaseResult) -> Void

/// The result returned in the `purchase()` callback.
public struct IAPPurchaseResult {
/// The result state.
public internal(set) var state: IAPPurchaseResultState

/// If the state is `failed`, the result can return an `IAPError`.
/// The error occurred during the processing of the purchase by the library.
public internal(set) var iapError: IAPError? = nil

/// If the state is `failed`, the result can return an `SKError`.
/// The error occurred during the processing of the purchase by the App Store.
public internal(set) var skError: SKError? = nil

/// If there is an error, return the localized description.
/// - See also: `IAPError` and `SKError`.
public var localizedDescription: String? {
if skError != nil { return skError!.localizedDescription }
if iapError != nil { return iapError!.localizedDescription }
Expand All @@ -28,10 +37,13 @@ public struct 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
}
Expand All @@ -41,18 +53,28 @@ public typealias IAPRefreshCallback = (IAPRefreshResult) -> Void

/// The result returned in the `refresh()` or `restorePurchases()` callback.
public struct IAPRefreshResult {
/// The result state.
public internal(set) var state: IAPRefreshResultState

/// If the state is `failed`, the result can return an `IAPError`.
/// The error occurred during the processing of the purchase by the library.
public internal(set) var iapError: IAPError? = nil

/// If the state is `succeeded`, returns the number of purchases that have been added.
public internal(set) var addedPurchases: Int = 0

/// If the state is `succeeded`, returns the number of purchases that have been updated.
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
}
Loading

0 comments on commit 1b5e18d

Please sign in to comment.