Przeglądaj źródła

Improve documentation

Andrea Bizzotto 8 lat temu
rodzic
commit
f72f6af98f

+ 22 - 8
README.md

@@ -210,11 +210,19 @@ As the local receipt is always encrypted, a verification step is needed to get a
 This is done with a `verifyReceipt` method which does two things:
 
 - If the receipt is missing, refresh it
-- If the receipt is available, validate it
+- If the receipt is available or is refreshed, validate it
 
 Receipt validation can be done remotely with Apple via the `AppleReceiptValidator` class, or with a client-supplied validator conforming to the `ReceiptValidator` protocol. 
 
-**Note**: As of version 0.10.0, _clients no longer need to refresh the receipt explicitly_.
+**Notes**
+
+* If the local receipt is missing when calling `verifyReceipt`, a network call is made to refresh it.
+* If the user is not logged to the App Store, StoreKit will present a popup asking to **Sign In to the iTunes Store**.
+* If the user enters valid credentials, the receipt will be refreshed and verified.
+* If the user cancels, receipt refresh will fail with a **Cannot connect to iTunes Store** error.
+* Using `AppleReceiptValidator` (see below) does remote receipt validation and also results in a network call.
+* Local receipt validation is not implemented (see [issue #101](https://github.com/bizz84/SwiftyStoreKit/issues/101) for details).
+
 
 ### Retrieve local receipt
 
@@ -238,13 +246,16 @@ SwiftyStoreKit.verifyReceipt(using: appleValidator, password: "your-shared-secre
 }
 ```
 
-#### Notes
+## Verifying purchases and subscriptions
 
-* If the user is not logged to iTunes when `verifyReceipt` is called, StoreKit will present a popup asking to **Sign In to the iTunes Store**.
-* If the user enters valid credentials, the receipt will be refreshed and verified.
-* If the user cancels, receipt refresh will fail with a **Cannot connect to iTunes Store** error.
-* The receipt is only refreshed if it's not already stored in `Bundle.main.appStoreReceiptURL`.
+Once you have retrieved the receipt using the `verifyReceipt` method, you can verify your purchases and subscriptions by product identifier.
+
+Verifying multiple purchases and subscriptions in one call is not yet supported (see [issue #194](https://github.com/bizz84/SwiftyStoreKit/issues/194) for more details).
 
+If you need to verify multiple purchases / subscriptions, you can either:
+
+* manually parse the receipt dictionary returned by `verifyReceipt`
+* call `verifyPurchase` or `verifySubscription` multiple times with different product identifiers
 
 ### Verify Purchase
 
@@ -325,7 +336,10 @@ let purchaseResult = SwiftyStoreKit.verifySubscription(
             inReceipt: receipt)
 ```
 
-**Note**: When purchasing subscriptions in sandbox mode, the expiry dates are set just minutes after the purchase date for testing purposes.
+**Notes**
+
+* The expiration dates are calculated against the receipt date. This is the date of the last successful call to `verifyReceipt`.
+* When purchasing subscriptions in sandbox mode, the expiry dates are set just minutes after the purchase date for testing purposes.
 
 #### Purchasing and verifying a subscription 
 

+ 2 - 0
SwiftyStoreKit/AppleReceiptValidator.swift

@@ -25,6 +25,8 @@
 
 import Foundation
 
+// https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
+
 public struct AppleReceiptValidator: ReceiptValidator {
 
 	public enum VerifyReceiptURLType: String {

+ 8 - 7
SwiftyStoreKit/InAppReceiptVerificator.swift

@@ -43,9 +43,12 @@ class InAppReceiptVerificator: NSObject {
     private var receiptRefreshRequest: InAppReceiptRefreshRequest?
 
     /**
-     *  Verify application receipt
-     *  - Parameter password: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).
-     *  - Parameter session: the session used to make remote call.
+     *  Verify application receipt. This method does two things:
+     *  * If the receipt is missing, refresh it
+     *  * If the receipt is available or is refreshed, validate it
+     *  - Parameter validator: Validator to check the encrypted receipt and return the receipt in readable format
+     *  - Parameter password: Your app’s shared secret (a hexadecimal string). Only used for receipts that contain auto-renewable subscriptions.
+     *  - Parameter refresh: closure to perform receipt refresh (this is made explicit for testability)
      *  - Parameter completion: handler for result
      */
     public func verifyReceipt(using validator: ReceiptValidator,
@@ -76,12 +79,10 @@ class InAppReceiptVerificator: NSObject {
         }
     }
     
-    // https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ValidateRemotely.html
-    
     /**
      *  - Parameter receiptData: encrypted receipt data
-     *  - Parameter validator: the validator to use
-     *  - Parameter password: Only used for receipts that contain auto-renewable subscriptions. Your app’s shared secret (a hexadecimal string).
+     *  - Parameter validator: Validator to check the encrypted receipt and return the receipt in readable format
+     *  - Parameter password: Your app’s shared secret (a hexadecimal string). Only used for receipts that contain auto-renewable subscriptions.
      *  - Parameter completion: handler for result
      */
     private func verify(receiptData: Data, using validator: ReceiptValidator, password: String? = nil, completion: @escaping (VerifyReceiptResult) -> Void) {

+ 27 - 4
SwiftyStoreKit/SwiftyStoreKit.swift

@@ -33,11 +33,12 @@ public class SwiftyStoreKit {
     fileprivate let receiptVerificator: InAppReceiptVerificator
 
     init(productsInfoController: ProductsInfoController = ProductsInfoController(),
-         paymentQueueController: PaymentQueueController = PaymentQueueController(paymentQueue: SKPaymentQueue.default())) {
+         paymentQueueController: PaymentQueueController = PaymentQueueController(paymentQueue: SKPaymentQueue.default()),
+         receiptVerificator: InAppReceiptVerificator = InAppReceiptVerificator()) {
 
         self.productsInfoController = productsInfoController
         self.paymentQueueController = paymentQueueController
-        self.receiptVerificator = InAppReceiptVerificator()
+        self.receiptVerificator = receiptVerificator
     }
 
     // MARK: Internal methods
@@ -138,10 +139,16 @@ extension SwiftyStoreKit {
     fileprivate static let sharedInstance = SwiftyStoreKit()
 
     // MARK: Public methods - Purchases
+    
     public class var canMakePayments: Bool {
         return SKPaymentQueue.canMakePayments()
     }
 
+    /**
+     *  Retrieve products information
+     *  - Parameter productIds: The set of product identifiers to retrieve corresponding products for
+     *  - Parameter completion: handler for result
+     */
     public class func retrieveProductsInfo(_ productIds: Set<String>, completion: @escaping (RetrieveResults) -> Void) {
 
         return sharedInstance.retrieveProductsInfo(productIds, completion: completion)
@@ -160,16 +167,32 @@ extension SwiftyStoreKit {
         sharedInstance.purchaseProduct(productId, quantity: quantity, atomically: atomically, applicationUsername: applicationUsername, completion: completion)
     }
 
+    /**
+     *  Restore purchases
+     *  - Parameter atomically: whether the product is purchased atomically (e.g. finishTransaction is called immediately)
+     *  - Parameter applicationUsername: an opaque identifier for the user’s account on your system
+     *  - Parameter completion: handler for result
+     */
     public class func restorePurchases(atomically: Bool = true, applicationUsername: String = "", completion: @escaping (RestoreResults) -> Void) {
 
         sharedInstance.restorePurchases(atomically: atomically, applicationUsername: applicationUsername, completion: completion)
     }
 
+    /**
+     *  Complete transactions
+     *  - Parameter atomically: whether the product is purchased atomically (e.g. finishTransaction is called immediately)
+     *  - Parameter completion: handler for result
+     */
     public class func completeTransactions(atomically: Bool = true, completion: @escaping ([Purchase]) -> Void) {
 
         sharedInstance.completeTransactions(atomically: atomically, completion: completion)
     }
 
+    /**
+     *  Finish a transaction
+     *  Once the content has been delivered, call this method to finish a transaction that was performed non-atomically
+     *  - Parameter transaction: transaction to finish
+     */
     public class func finishTransaction(_ transaction: PaymentTransaction) {
 
         sharedInstance.finishTransaction(transaction)
@@ -211,11 +234,11 @@ extension SwiftyStoreKit {
 
     /**
      *  Verify the purchase of a subscription (auto-renewable, free or non-renewing) in a receipt. This method extracts all transactions mathing the given productId and sorts them by date in descending order, then compares the first transaction expiry date against the validUntil value.
+     *  - Parameter type: autoRenewable or nonRenewing
      *  - Parameter productId: the product id of the purchase to verify
      *  - Parameter inReceipt: the receipt to use for looking up the subscription
      *  - Parameter validUntil: date to check against the expiry date of the subscription. If nil, no verification
-     *  - Parameter validDuration: the duration of the subscription. Only required for non-renewable subscription.
-     *  - return: either NotPurchased or Purchased / Expired with the expiry date found in the receipt
+     *  - return: either .notPurchased or .purchased / .expired with the expiry date found in the receipt
      */
     public class func verifySubscription(type: SubscriptionType, productId: String, inReceipt receipt: ReceiptInfo, validUntil date: Date = Date()) -> VerifySubscriptionResult {