Read features from app store receipt

- Use Kvitto to parse App Store receipt
- Infer feature/provider eligibility from features
- Assume full version in beta
- Read receipt even if no products were purchased
This commit is contained in:
Davide De Rosa 2019-10-27 01:31:30 +02:00
parent e62aae16fc
commit 026a94065c
3 changed files with 107 additions and 5 deletions

View File

@ -26,14 +26,33 @@
import Foundation
import StoreKit
import Convenience
import SwiftyBeaver
import Kvitto
import PassepartoutCore
private let log = SwiftyBeaver.self
class ProductManager: NSObject {
private static let lastFullVersionNumber = "1.8.1"
private static let lastFullVersionBuild = "2016"
struct ProductManager {
static let shared = ProductManager()
private let inApp: InApp<Product>
private init() {
private var purchasedAppVersion: String?
private var purchasedFeatures: Set<Product>
private override init() {
inApp = InApp()
purchasedAppVersion = nil
purchasedFeatures = []
super.init()
reloadReceipt()
}
func listProducts(completionHandler: (([SKProduct]) -> Void)?) {
@ -47,6 +66,75 @@ struct ProductManager {
}
func purchase(_ product: SKProduct, completionHandler: @escaping (InAppPurchaseResult, Error?) -> Void) {
inApp.purchase(product: product, completionHandler: completionHandler)
inApp.purchase(product: product) {
if $0 == .success {
self.reloadReceipt()
}
completionHandler($0, $1)
}
}
// MARK: In-app eligibility
private func reloadReceipt() {
guard let url = Bundle.main.appStoreReceiptURL else {
log.warning("No App Store receipt found!")
return
}
guard let receipt = Receipt(contentsOfURL: url) else {
log.error("Could not parse App Store receipt!")
return
}
purchasedAppVersion = receipt.originalAppVersion
purchasedFeatures.removeAll()
if let version = purchasedAppVersion {
log.debug("Original purchased version: \(version)")
// treat former purchases as full versions
if version <= ProductManager.lastFullVersionNumber {
purchasedFeatures.insert(.fullVersion)
}
}
if let iapReceipts = receipt.inAppPurchaseReceipts {
log.debug("In-app receipts:")
iapReceipts.forEach {
guard let pid = $0.productIdentifier, let date = $0.originalPurchaseDate else {
return
}
log.debug("\t\(pid) [\(date)]")
}
for r in iapReceipts {
guard let pid = r.productIdentifier, let product = Product(rawValue: pid) else {
continue
}
purchasedFeatures.insert(product)
}
}
log.info("Purchased features: \(purchasedFeatures)")
}
func isFullVersion() -> Bool {
guard !AppConstants.Flags.isBeta else {
return true
}
return purchasedFeatures.contains(.fullVersion)
}
func isEligible(forFeature feature: Product) -> Bool {
guard !isFullVersion() else {
return true
}
return purchasedFeatures.contains(feature)
}
func isEligible(forProvider name: Infrastructure.Name) -> Bool {
guard !isFullVersion() else {
return true
}
return purchasedFeatures.contains {
return $0.rawValue.hasSuffix("providers.\(name.rawValue)")
}
}
}

View File

@ -21,6 +21,7 @@ end
target 'PassepartoutCore-iOS' do
shared_pods
pod 'Kvitto'
end
target 'Passepartout-iOS' do

View File

@ -10,6 +10,14 @@ PODS:
- Convenience/Persistence (0.0.1)
- Convenience/Reviewer (0.0.1)
- Convenience/Tables (0.0.1)
- DTFoundation/Core (1.7.14)
- DTFoundation/DTASN1 (1.7.14):
- DTFoundation/Core
- Kvitto (1.0.3):
- DTFoundation/DTASN1 (~> 1.7.13)
- Kvitto/Core (= 1.0.3)
- Kvitto/Core (1.0.3):
- DTFoundation/DTASN1 (~> 1.7.13)
- MBProgressHUD (1.1.0)
- OpenSSL-Apple (1.1.0l.4)
- SSZipArchive (2.2.2)
@ -35,6 +43,7 @@ DEPENDENCIES:
- Convenience/Persistence (from `https://github.com/keeshux/convenience`, commit `b990a8c`)
- Convenience/Reviewer (from `https://github.com/keeshux/convenience`, commit `b990a8c`)
- Convenience/Tables (from `https://github.com/keeshux/convenience`, commit `b990a8c`)
- Kvitto
- MBProgressHUD
- SSZipArchive
- TunnelKit/Extra/LZO (from `https://github.com/passepartoutvpn/tunnelkit`, commit `4d930d3`)
@ -42,6 +51,8 @@ DEPENDENCIES:
SPEC REPOS:
https://github.com/cocoapods/specs.git:
- DTFoundation
- Kvitto
- MBProgressHUD
- OpenSSL-Apple
- SSZipArchive
@ -64,13 +75,15 @@ CHECKOUT OPTIONS:
:git: https://github.com/passepartoutvpn/tunnelkit
SPEC CHECKSUMS:
Convenience: c2bc96be4ca77c7018f85b2c63b95c2a44c05c5a
Convenience: c4240c936b2119752ffa0841d40a4bc6a0ba8a5d
DTFoundation: 25aa19bb7c6e225b1dfae195604fb8cf1da0ab4c
Kvitto: d451f893f84ad669850b7cb7d3f8781363e14232
MBProgressHUD: e7baa36a220447d8aeb12769bf0585582f3866d9
OpenSSL-Apple: f3d1668588ea8f06b076dcfa6177cd90452e3800
SSZipArchive: fa16b8cc4cdeceb698e5e5d9f67e9558532fbf23
SwiftyBeaver: aaf2ebd7dac2e952991f46a82ed24ad642867ae2
TunnelKit: 0743f0306be0869d51118ac33e274e7507a93537
PODFILE CHECKSUM: f45a3fd3744e646a5513e3e25d447d1550c9fefa
PODFILE CHECKSUM: d1e12ff38bc1839dddbbbcaa5e436ea0fad60f70
COCOAPODS: 1.8.4