Latest 1.0.0
Homepage https://github.com/Meniny/PurchaseKit
License MIT
Platforms ios 8.0, osx 10.10, tvos 9.0
Authors

PurchaseKit


VersionAuthorBuild PassingSwift
PlatformsMIT
CocoapodsCarthageSPM


Introduction

What’s this?

PurchaseKit is an In-App Purchase Framework written in Swift.

Requirements

  • iOS 8.0+
  • macOS 10.10+
  • tvOS 9.0+
  • Xcode 8+ with Swift 3+

Installation

CocoaPods

pod 'PurchaseKit'

Contribution

You are welcome to fork and submit pull requests.

License

PurchaseKit is open-sourced software, licensed under the MIT license.

Usage

Complete Transactions

Apple recommends to register a transaction observer as soon as the app starts:

Adding your app’s observer at launch ensures that it will persist during all launches of your app, thus allowing your app to receive all the payment queue notifications.

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {

    PurchaseKit.completeTransactions(atomically: true) { purchases in

        for purchase in purchases {

            if purchase.transaction.transactionState == .purchased || purchase.transaction.transactionState == .restored {

               if purchase.needsFinishTransaction {
                   // Deliver content from server, then:
                   PurchaseKit.finishTransaction(purchase.transaction)
               }
               print("purchased: (purchase)")
            }
        }
    }
    return true
}

Purchases

Retrieve products info

PurchaseKit.retrieveProductsInfo(["cn.meniny.PurchaseKit.Purchase1"]) { result in
    if let product = result.retrievedProducts.first {
        let priceString = product.localizedPrice!
        print("Product: (product.localizedDescription), price: (priceString)")
    }
    else if let invalidProductId = result.invalidProductIDs.first {
        return alertWithTitle("Could not retrieve product info", message: "Invalid product identifier: (invalidProductId)")
    }
    else {
         print("Error: (result.error)")
    }
}

Purchase a product

PurchaseKit.purchaseProduct("cn.meniny.PurchaseKit.Purchase1", quantity: 1, atomically: true) { result in
    switch result {
    case .success(let purchase):
        print("Purchase Success: (purchase.productId)")
    case .error(let error):
        switch error.code {
        case .unknown: print("Unknown error. Please contact support")
        case .clientInvalid: print("Not allowed to make the payment")
        case .paymentCancelled: break
        case .paymentInvalid: print("The purchase identifier was invalid")
        case .paymentNotAllowed: print("The device is not allowed to make the payment")
        case .storeProductNotAvailable: print("The product is not available in the current storefront")
        case .cloudServicePermissionDenied: print("Access to cloud service information is not allowed")
        case .cloudServiceNetworkConnectionFailed: print("Could not connect to the network")
        case .cloudServiceRevoked: print("User has revoked permission to use this cloud service")
        }
    }
}
PurchaseKit.purchaseProduct("cn.meniny.PurchaseKit.Purchase1", quantity: 1, atomically: false) { result in
    switch result {
    case .success(let product):
        // fetch content from your server, then:
        if product.needsFinishTransaction {
            PurchaseKit.finishTransaction(product.transaction)
        }
        print("Purchase Success: (product.productId)")
    case .error(let error):
        switch error.code {
        case .unknown: print("Unknown error. Please contact support")
        case .clientInvalid: print("Not allowed to make the payment")
        case .paymentCancelled: break
        case .paymentInvalid: print("The purchase identifier was invalid")
        case .paymentNotAllowed: print("The device is not allowed to make the payment")
        case .storeProductNotAvailable: print("The product is not available in the current storefront")
        case .cloudServicePermissionDenied: print("Access to cloud service information is not allowed")
        case .cloudServiceNetworkConnectionFailed: print("Could not connect to the network")
        case .cloudServiceRevoked: print("User has revoked permission to use this cloud service")
        }
    }
}
PurchaseKit.retrieveProductsInfo(["cn.meniny.PurchaseKit.Purchase1"]) { result in
    if let product = result.retrievedProducts.first {
        PurchaseKit.purchaseProduct(product, quantity: 1, atomically: true) { result in
            // handle result (same as above)
        }
    }
}

Restore previous purchases

PurchaseKit.restorePurchases(atomically: true) { results in
    if results.restoreFailedPurchases.count > 0 {
        print("Restore Failed: (results.restoreFailedPurchases)")
    }
    else if results.restoredPurchases.count > 0 {
        print("Restore Success: (results.restoredPurchases)")
    }
    else {
        print("Nothing to Restore")
    }
}
PurchaseKit.restorePurchases(atomically: false) { results in
    if results.restoreFailedPurchases.count > 0 {
        print("Restore Failed: (results.restoreFailedPurchases)")
    }
    else if results.restoredPurchases.count > 0 {
        for purchase in results.restoredPurchases {
            // fetch content from your server, then:
            if purchase.needsFinishTransaction {
                PurchaseKit.finishTransaction(purchase.transaction)
            }
        }
        print("Restore Success: (results.restoredPurchases)")
    }
    else {
        print("Nothing to Restore")
    }
}

Receipt verification

Retrieve local receipt

let receiptData = PurchaseKit.localReceiptData
let receiptString = receiptData.base64EncodedString(options: [])
// do your receipt validation here

Verify Receipt

let appleValidator = PKAppleReceiptValidator(service: .production)
PurchaseKit.verifyReceipt(using: appleValidator, password: "your-shared-secret", forceRefresh: false) { result in
    switch result {
    case .success(let receipt):
        print("Verify receipt Success: (receipt)")
    case .error(let error):
        print("Verify receipt Failed: (error)")
    }
}

Verifying purchases and subscriptions

Verify Purchase

let appleValidator = PKAppleReceiptValidator(service: .production)
PurchaseKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in
    switch result {
    case .success(let receipt):
        // Verify the purchase of Consumable or NonConsumable
        let purchaseResult = PurchaseKit.verifyPurchase(
            productId: "cn.meniny.PurchaseKit.Purchase1",
            inReceipt: receipt)

        switch purchaseResult {
        case .purchased(let receiptItem):
            print("Product is purchased: (receiptItem)")
        case .notPurchased:
            print("The user has never purchased this product")
        }
    case .error(let error):
        print("Receipt verification failed: (error)")
    }
}

Verify Subscription

let appleValidator = PKAppleReceiptValidator(service: .production)
PurchaseKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in
    switch result {
    case .success(let receipt):
        // Verify the purchase of a Subscription
        let purchaseResult = PurchaseKit.verifySubscription(
            type: .autoRenewable, // or .nonRenewing (see below)
            productId: "cn.meniny.PurchaseKit.Subscription",
            inReceipt: receipt)

        switch purchaseResult {
        case .purchased(let expiryDate, let receiptItems):
            print("Product is valid until (expiryDate)")
        case .expired(let expiryDate, let receiptItems):
            print("Product is expired since (expiryDate)")
        case .notPurchased:
            print("The user has never purchased this product")
        }

    case .error(let error):
        print("Receipt verification failed: (error)")
    }
}

Auto-Renewable

let purchaseResult = PurchaseKit.verifySubscription(
            type: .autoRenewable,
            productId: "cn.meniny.PurchaseKit.Subscription",
            inReceipt: receipt)

Non-Renewing

// validDuration: time interval in seconds
let purchaseResult = PurchaseKit.verifySubscription(
            type: .nonRenewing(validDuration: 3600 * 24 * 30),
            productId: "cn.meniny.PurchaseKit.Subscription",
            inReceipt: receipt)

Purchasing and verifying a subscription

let productId = "your-product-id"
PurchaseKit.purchaseProduct(productId, atomically: true) { result in

    if case .success(let purchase) = result {
        // Deliver content from server, then:
        if purchase.needsFinishTransaction {
            PurchaseKit.finishTransaction(purchase.transaction)
        }

        let appleValidator = PKAppleReceiptValidator(service: .production)
        PurchaseKit.verifyReceipt(using: appleValidator, password: "your-shared-secret") { result in

            if case .success(let receipt) = result {
                let purchaseResult = PurchaseKit.verifySubscription(
                    type: .autoRenewable,
                    productId: productId,
                    inReceipt: receipt)

                switch purchaseResult {
                case .purchased(let expiryDate, let receiptItems):
                    print("Product is valid until (expiryDate)")
                case .expired(let expiryDate, let receiptItems):
                    print("Product is expired since (expiryDate)")
                case .notPurchased:
                    print("This product has never been purchased")
                }

            } else {
                // receipt verification error
            }
        }
    } else {
        // purchase error
    }
}

Latest podspec

{
    "name": "PurchaseKit",
    "version": "1.0.0",
    "summary": "In-App Purchase Framework",
    "authors": {
        "Meniny": "[email protected]"
    },
    "homepage": "https://github.com/Meniny/PurchaseKit",
    "social_media_url": "https://meniny.cn/",
    "license": "MIT",
    "description": "PurchaseKit is an In-App Purchase Framework written in Swift.",
    "platforms": {
        "ios": "8.0",
        "osx": "10.10",
        "tvos": "9.0"
    },
    "source": {
        "git": "https://github.com/Meniny/PurchaseKit.git",
        "tag": "1.0.0"
    },
    "source_files": "PurchaseKit/Source/*",
    "public_header_files": "PurchaseKit/Source/*.h",
    "ios": {
        "frameworks": [
            "Foundation",
            "UIKit",
            "StoreKit"
        ]
    },
    "tvos": {
        "frameworks": [
            "Foundation",
            "UIKit",
            "StoreKit"
        ]
    },
    "osx": {
        "frameworks": [
            "Foundation",
            "AppKit",
            "StoreKit"
        ]
    },
    "pushed_with_swift_version": "3.0"
}

Pin It on Pinterest

Share This