All notable changes to this project will be documented in this file.
ProductsInfoController
's retrieveProductsInfo
thread safe ([#405]https://github.com/bizz84/SwiftyStoreKit/pull/495), related issues: #344 and #468canMakePayments
check on purchase methodcanMakePayments
check on purchase method (#434)else
condition in SwiftyStoreKit.purchaseProduct
else
condition in SwiftyStoreKit.purchaseProduct
(#426)isInIntroOfferPeriod
property, update project to Swift 4.2, Xcode 10isInIntroOfferPeriod
to ReceiptItem (#404, #409)simulatesAskToBuyInSandbox
(#349)completeTransactions
was called when the app launches.verifySubscriptions
method for subscription groupsverifySubscriptions
method to check all subscriptions in a group at once (#333, related issue: #194)verifySubscription(type:productId:inReceipt:validUntil:)
to verifySubscription(ofType:productId:inReceipt:validUntil:)
(#333)completeTransactions
finishes failed transactions if atomically: false
originalTransaction
to PurchaseDetails
(#323, fix for #302)completeTransactions
finishes failed transactions if atomically: false
(#322, related issues: #307, #288)SKProduct.localizedIntroductoryPrice
PaymentTransaction.transactionDate
and SKProduct.localizedIntroductoryPrice
transactionDate
to PaymentTransaction
(#316, see #312).localizedIntroductoryPrice
to SKProduct
(#318).fetchReceipt
method + update verifyReceipt
and ReceiptValidator
protocolfetchReceipt
method. Update verifyReceipt
to use it (#278, related issues: #272, #223).fetchReceipt
and ReceiptValidator
to use receipt as Data
rather than String
. This is consistent with localReceiptData
(#284, see #272).password
from ReceiptValidator
protocol as this is specific to AppleReceiptValidator
(#281, see #263). Note: This is an API breaking change.receipt["receipt"]?["in_app"]
in two steps (addresses casting problems) (#283, related issue #256).retrieveProductsInfo
callsProductsInfoController
: Keep track of multiple completion blocks for the same request (#259, fix for #250)SKPaymentTransactionObserver.shouldAddStorePayment
method in iOS 11 (#257, related issue: #240)state == .purchasing
early in purchase flows (related to #169, #188, #179).unknown
errorforceRefresh
option to verifyReceipt
verifyReceipt
now automatically refreshes the receipt if neededrefreshReceipt
This release simplifies the receipt verification flows by removing the refreshReceipt
method from the public API.
Now clients only need to call verifyReceipt
and the receipt is refreshed internally if needed.
Addressed in #213, related issue: #42.
The documentation in the README and various methods has also been considerably improved.
This is a minor release to ensure callbacks are dispatched on the main thread on macOS.
This is a critical fix for #208.
If you're using release 0.9.0, please update.
This is a minor release which includes a fix for #185 (addressed in #206). Summary:
When a purchase succeeds, it is desirable to get access to the purchased SKProduct
in the completion block, so that it's possible to query the price
and other properties.
With this change, this is now possible:
SwiftyStoreKit.purchaseProduct("productId", atomically: true) { result in
if case .success(let purchase) = result {
// Deliver content from server, then:
if purchase.needsFinishTransaction {
SwiftyStoreKit.finishTransaction(purchase.transaction)
}
print("Purchased product with price: \(purchase.product.price)")
}
}
NOTE This release introduces some API breaking changes (see #202). Change-set:
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.
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
}
originalTransaction
from SKPaymentTransaction.original
to Payment
type