123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- //
- // KMInAppPurchaseManager.swift
- // PDF Master
- //
- // Created by lizhe on 2023/6/8.
- //
- import Cocoa
- import StoreKit
- import AuthenticationServices
- import Security
- #if VERSION_FREE
- let PRODUCT_1 = "com.pdfreaderpro.free.member.all_access_pack_permanent_license.001"
- let PRODUCT_2 = "com.pdfreaderpro.member.pdf_to_office_pack_permanent_license.001"
- let kPRODUCTS: Set<String> = [PRODUCT_1, PRODUCT_2]
- let kSandboxServer = "https://sandbox.itunes.apple.com/verifyReceipt";
- let kItunesServer = "https://buy.itunes.apple.com/verifyReceipt";
- let kStoreLiteKitSecret = "905532d3f55449a9b7a96161e7a2d538";
- let kStoreKitSecret = "20f0129197a34439a2130358172984bb";
- #endif
- let keychainAccessGroup = "your.keychain.access.group"
- let receiptDataLabel = "receiptData"
- class KMInAppPurchaseManager: NSObject {
- public static let manager = KMInAppPurchaseManager()
-
- var fetchProductCompletion: KMPurchaseFetchProductCompletion?
- var availableProducts: [SKProduct] = []
- var request: SKProductsRequest?
- override init() {
- super.init()
-
- // if let receiptURL = Bundle.main.appStoreReceiptURL,
- // let receiptData = try? Data(contentsOf: receiptURL) {
- // // 定义 Keychain 查询字典
- // var query: [String: Any] = [
- // kSecClass as String: kSecClassGenericPassword,
- // kSecAttrLabel as String: receiptDataLabel,
- // kSecAttrAccessGroup as String: keychainAccessGroup,
- // kSecValueData as String: receiptData
- // ]
- //
- // // 删除已存在的同名数据
- // SecItemDelete(query as CFDictionary)
- //
- // // 将数据存储到 Keychain
- // let status = SecItemAdd(query as CFDictionary, nil)
- // if status != errSecSuccess {
- // // 存储失败处理
- // // ...
- // }
- // }
-
- // // 定义 Keychain 查询字典
- // var query: [String: Any] = [
- // kSecClass as String: kSecClassGenericPassword,
- // kSecAttrLabel as String: receiptDataLabel,
- // kSecAttrAccessGroup as String: keychainAccessGroup,
- // kSecReturnData as String: true,
- // kSecMatchLimit as String: kSecMatchLimitOne
- // ]
- //
- // // 检索数据
- // var result: AnyObject?
- // let status = SecItemCopyMatching(query as CFDictionary, &result)
- // if status == errSecSuccess, let receiptData = result as? Data {
- // // 使用检索到的应用收据进行相应的操作
- // // ...
- // }
- //
- // 注册购买交易观察者
- SKPaymentQueue.default().add(self)
- }
-
- func fetchProducts(completion: @escaping KMPurchaseFetchProductCompletion) {
- self.fetchProductCompletion = completion
-
- let productIdentifiers: Set<String> = kPRODUCTS
- self.request = SKProductsRequest(productIdentifiers: productIdentifiers)
- self.request?.delegate = self
- self.request?.start()
- }
-
- func purchaseProduct(productIdentifier: String, completion: @escaping KMPurchaseCompletion) {
- if SKPaymentQueue.canMakePayments() {
- if let product = availableProducts.first(where: { $0.productIdentifier == productIdentifier }) {
- print("\("购买产品") + \(productIdentifier)")
- let payment = SKPayment(product: product)
- SKPaymentQueue.default().add(payment)
- } else {
- // 未找到匹配的产品
- print("未找到匹配的产品")
- let tempProductIdentifier = productIdentifier
- self.fetchProducts(completion: { [unowned self] isSuccess, products, error in
- if isSuccess {
- print("获取产品成功")
- self.purchaseProduct(productIdentifier: tempProductIdentifier, completion: completion)
- } else {
- print("获取产品失败")
- }
- })
- }
- } else {
- print("用户无法进行内购")
- }
- }
- }
- extension KMInAppPurchaseManager: SKProductsRequestDelegate {
- func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
- availableProducts = response.products
- self.request?.cancel()
- self.request = nil
- // 处理产品信息
- guard let callBack = self.fetchProductCompletion else { return }
-
- callBack(true, availableProducts, "")
- }
-
- func request(_ request: SKRequest, didFailWithError error: Error) {
- // 处理请求错误
- print("\("用户无法进行内购") + \(error)")
- }
- }
- extension KMInAppPurchaseManager: SKPaymentTransactionObserver {
- func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool {
- // Handle the purchase intent here
- // Return true to allow the purchase or false to deny it
-
- return true
- }
-
- func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
- for transaction in transactions {
- switch transaction.transactionState {
- case .purchased:
- // 购买成功,进行本地二次验证
- print("购买成功,进行本地二次验证")
- validatePurchase(transaction: transaction)
- case .failed:
- // 购买失败,处理错误
- print("购买失败,处理错误")
- handleError(transaction: transaction)
- case .restored:
- // 恢复购买,进行本地二次验证
- print("恢复购买,进行本地二次验证")
- validatePurchase(transaction: transaction)
- default:
- break
- }
- }
- }
-
- // func validatePurchase(transaction: SKPaymentTransaction) {
- // // 获取购买凭证
- // if let receiptURL = Bundle.main.appStoreReceiptURL,
- // let receiptData = try? Data(contentsOf: receiptURL) {
- // // 进行本地二次验证
- // if let parsedReceipt = parseReceipt(receiptData: receiptData),
- // let purchase = parsedReceipt["in_app"] as? [[String: Any]],
- // let matchingPurchase = purchase.first(where: { $0["transaction_id"] as? String == transaction.transactionIdentifier }) {
- // // 验证购买凭证,进行相应的处理
- // if verifyPurchase(purchase: matchingPurchase) {
- // // 购买凭证验证成功,进行购买成功的逻辑
- // SKPaymentQueue.default().finishTransaction(transaction)
- // // ...
- // } else {
- // // 购买凭证验证失败,进行购买失败的逻辑
- // SKPaymentQueue.default().finishTransaction(transaction)
- // // ...
- // }
- // }
- // }
- // }
-
- //https://sandbox.itunes.apple.com/verifyReceipt
- //"https://buy.itunes.apple.com/verifyReceipt"
-
- func validatePurchase(transaction: SKPaymentTransaction) {
- // 获取购买凭证
- if let receiptURL = Bundle.main.appStoreReceiptURL,
- let receiptData = try? Data(contentsOf: receiptURL) {
- // 将购买凭证发送到服务器进行验证
- sendReceiptToServer(receiptData: receiptData, transaction: transaction)
- }
- }
- //
- func sendReceiptToServer(receiptData: Data, transaction: SKPaymentTransaction) {
- // 构建请求
- // let url = URL(string: "https://your-server.com/verify-receipt")!
- // let requestContents = ["receipt-data" : receipt.base64EncodedString()]
- let receiptString = receiptData.base64EncodedString(options: [])
- let requestContents: [String: Any] = ["receipt-data": receiptString,
- "password": kStoreLiteKitSecret]
- guard let requestData = try? JSONSerialization.data(withJSONObject: requestContents, options: []) else {
- // 交易凭证为空验证失败
- return
- }
-
- let url = URL(string: "https://sandbox.itunes.apple.com/verifyReceipt")!
- var request = URLRequest(url: url)
- request.httpMethod = "POST"
- request.httpBody = requestData
- // 发送请求
- let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
- if let data = data {
- // 处理服务器返回的验证结果
- let verificationResult = self.parseVerificationResult(data: data)
- if verificationResult {
- let receipt = try? JSONSerialization.jsonObject(with: data, options: [])
- print(receipt)
- // 购买凭证验证成功,进行购买成功的逻辑
- SKPaymentQueue.default().finishTransaction(transaction)
- // ...
- } else {
- // 购买凭证验证失败,进行购买失败的逻辑
- SKPaymentQueue.default().finishTransaction(transaction)
- // ...
- }
- } else if let error = error {
- // 处理网络请求错误
- // ...
- }
- }
- task.resume()
- }
-
- func parseVerificationResult(data: Data) -> Bool {
- // 解析服务器返回的验证结果
- // 如果验证成功返回 true,否则返回 false
- // ...
- return true
- }
-
- func handleError(transaction: SKPaymentTransaction) {
- // 处理购买失败的逻辑
- SKPaymentQueue.default().finishTransaction(transaction)
- // ...
- }
-
- func verifyPurchase(purchase: [String: Any]) -> Bool {
- // 执行购买凭证验证的逻辑,例如验证产品标识符、购买日期等
- // 如果验证成功返回 true,否则返回 false
- // ...
- return true
- }
-
- func parseReceipt(receiptData: Data) -> [String: Any]? {
- guard let receipt = try? JSONSerialization.jsonObject(with: receiptData, options: []) as? [String: Any] else {
- return nil
- }
-
- return receipt
- }
- }
|