Releases: bizz84/SwiftyStoreKit
Verify Subscription improvements + added quantity and originalTransaction to Payment
NOTE This release introduces some API breaking changes (see #202). Change-set:
#198: Subscription verification unit tests
#199 (fixes #192, #190 and #65): Add ReceiptItem
to VerifyPurchaseResult
, VerifySubscriptionResult
This change introduces a new strong-typed ReceiptItem
struct:
public struct ReceiptItem {
// The product identifier of the item that was purchased. This value corresponds to the productIdentifier property of the SKPayment object stored in the transaction’s payment property.
public let productId: String
// The number of items purchased. This value corresponds to the quantity property of the SKPayment object stored in the transaction’s payment property.
public let quantity: Int
// The transaction identifier of the item that was purchased. This value corresponds to the transaction’s transactionIdentifier property.
public let transactionId: String
// For a transaction that restores a previous transaction, the transaction identifier of the original transaction. Otherwise, identical to the transaction identifier. This value corresponds to the original transaction’s transactionIdentifier property. All receipts in a chain of renewals for an auto-renewable subscription have the same value for this field.
public let originalTransactionId: String
// The date and time that the item was purchased. This value corresponds to the transaction’s transactionDate property.
public let purchaseDate: Date
// For a transaction that restores a previous transaction, the date of the original transaction. This value corresponds to the original transaction’s transactionDate property. In an auto-renewable subscription receipt, this indicates the beginning of the subscription period, even if the subscription has been renewed.
public let originalPurchaseDate: Date
// The primary key for identifying subscription purchases.
public let webOrderLineItemId: String
// The expiration date for the subscription, expressed as the number of milliseconds since January 1, 1970, 00:00:00 GMT. This key is only present for auto-renewable subscription receipts.
public let subscriptionExpirationDate: Date?
// For a transaction that was canceled by Apple customer support, the time and date of the cancellation. Treat a canceled receipt the same as if no purchase had ever been made.
public let cancellationDate: Date?
public let isTrialPeriod: Bool
}
This is parsed from the receipt and returned as part of the verifySubscription
and verifyPurchase
methods:
// Result for Consumable and NonConsumable
public enum VerifyPurchaseResult {
case purchased(item: ReceiptItem)
case notPurchased
}
// Verify subscription result
public enum VerifySubscriptionResult {
case purchased(expiryDate: Date, items: [ReceiptItem])
case expired(expiryDate: Date, items: [ReceiptItem])
case notPurchased
}
Note that when one or more subscriptions are found for a given product id, they are returned as a ReceiptItem
array ordered by expiryDate
, with the first one being the newest.
This is useful to get all the valid date ranges for a given subscription.
#202 (fix for #200): It's now possible to specify the quantity when making a purchase. Quantity is also accessible in the callback.
This is an API breaking change. Product
has been renamed to Purchase
:
public struct Purchase {
public let productId: String
public let quantity: Int
public let transaction: PaymentTransaction
public let needsFinishTransaction: Bool
}
PurchaseResult
public enum PurchaseResult {
//case success(product: Product) // old
case success(purchase: Purchase) // new
case error(error: SKError)
}
RestoreResults
public struct RestoreResults {
//public let restoredProducts: [Product] // old
//public let restoreFailedProducts: [(SKError, String?)] // old
public let restoredPurchases: [Purchase] // new
public let restoreFailedPurchases: [(SKError, String?)] // new
}
#203 (fix for #193): Add originalTransaction
from SKPaymentTransaction.original
to Payment
type
Improved Documentation
This release only improves documentation for the project, specifically covering these areas:
It also removes a console log that was being printed when detecting a transaction in .purchasing
state (see #179)
Xcode 8.3 support
Treat cancelled subscriptions as if the product was never purchased
Add SubscriptionType to differentiate between auto-renewable and non-renewing subscriptions
This is a bug-fix release to address #161.
API Changes
Auto-Renewable
The verifySubscription()
method API has changed:
let purchaseResult = SwiftyStoreKit.verifySubscription(
type: .autoRenewable,
productId: "com.musevisions.SwiftyStoreKit.Subscription",
inReceipt: receipt)
Non-Renewing
let purchaseResult = SwiftyStoreKit.verifySubscription(
type: .nonRenewing(validDuration: 3600 * 24 * 30),
productId: "com.musevisions.SwiftyStoreKit.Subscription",
inReceipt: receipt)
See the README file for more details.
Changes
For auto-renewable, receipt["latest_receipt_info"]
is used.
For non-renewing, receipt["receipt"]?["in_app"]
is used.
This fixes a bug where receipt verification fails for non-renewing subscriptions (which were previously using "latest_receipt_info".
Minor fixes for completeTransactions()
Added SwiftLint, minor tweaks
Simplified error checking API
This release makes it easy to check if the user has canceled a purchase.
This is an API breaking change as the PurchaseError
type has been removed in favour of SKError
. Clients can now make purchases and check errors like this:
SwiftyStoreKit.purchaseProduct("com.musevisions.SwiftyStoreKit.Purchase1", atomically: true) { result in
switch result {
case .success(let product):
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")
}
}
}
This is in line with: https://developer.apple.com/reference/storekit/skerror.code
Related PR: #138
Use receipt["latest_receipt_info"] when verifying subscriptions
Reference page:
Quoting:
latest_receipt_info: Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions. The JSON representation of the receipt for the most recent renewal.
The values of the latest_receipt and latest_receipt_info keys are useful when checking whether an auto-renewable subscription is currently active. By providing any transaction receipt for the subscription and checking these values, you can get information about the currently-active subscription period. If the receipt being validated is for the latest renewal, the value for latest_receipt is the same as receipt-data (in the request) and the value for latest_receipt_info is the same as receipt.