KMInAppPurchaseManager.swift 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. //
  2. // KMInAppPurchaseManager.swift
  3. // PDF Master
  4. //
  5. // Created by lizhe on 2023/6/8.
  6. //
  7. import Cocoa
  8. import StoreKit
  9. import AuthenticationServices
  10. import Security
  11. #if VERSION_FREE
  12. let PRODUCT_1 = "com.pdfreaderpro.free.member.all_access_pack_permanent_license.001"
  13. let PRODUCT_2 = "com.pdfreaderpro.member.pdf_to_office_pack_permanent_license.001"
  14. let kPRODUCTS: Set<String> = [PRODUCT_1, PRODUCT_2]
  15. let kSandboxServer = "https://sandbox.itunes.apple.com/verifyReceipt";
  16. let kItunesServer = "https://buy.itunes.apple.com/verifyReceipt";
  17. let kStoreLiteKitSecret = "905532d3f55449a9b7a96161e7a2d538";
  18. let kStoreKitSecret = "20f0129197a34439a2130358172984bb";
  19. #endif
  20. let keychainAccessGroup = "your.keychain.access.group"
  21. let receiptDataLabel = "receiptData"
  22. class KMInAppPurchaseManager: NSObject {
  23. public static let manager = KMInAppPurchaseManager()
  24. var fetchProductCompletion: KMPurchaseFetchProductCompletion?
  25. var availableProducts: [SKProduct] = []
  26. var request: SKProductsRequest?
  27. override init() {
  28. super.init()
  29. // if let receiptURL = Bundle.main.appStoreReceiptURL,
  30. // let receiptData = try? Data(contentsOf: receiptURL) {
  31. // // 定义 Keychain 查询字典
  32. // var query: [String: Any] = [
  33. // kSecClass as String: kSecClassGenericPassword,
  34. // kSecAttrLabel as String: receiptDataLabel,
  35. // kSecAttrAccessGroup as String: keychainAccessGroup,
  36. // kSecValueData as String: receiptData
  37. // ]
  38. //
  39. // // 删除已存在的同名数据
  40. // SecItemDelete(query as CFDictionary)
  41. //
  42. // // 将数据存储到 Keychain
  43. // let status = SecItemAdd(query as CFDictionary, nil)
  44. // if status != errSecSuccess {
  45. // // 存储失败处理
  46. // // ...
  47. // }
  48. // }
  49. // // 定义 Keychain 查询字典
  50. // var query: [String: Any] = [
  51. // kSecClass as String: kSecClassGenericPassword,
  52. // kSecAttrLabel as String: receiptDataLabel,
  53. // kSecAttrAccessGroup as String: keychainAccessGroup,
  54. // kSecReturnData as String: true,
  55. // kSecMatchLimit as String: kSecMatchLimitOne
  56. // ]
  57. //
  58. // // 检索数据
  59. // var result: AnyObject?
  60. // let status = SecItemCopyMatching(query as CFDictionary, &result)
  61. // if status == errSecSuccess, let receiptData = result as? Data {
  62. // // 使用检索到的应用收据进行相应的操作
  63. // // ...
  64. // }
  65. //
  66. // 注册购买交易观察者
  67. SKPaymentQueue.default().add(self)
  68. }
  69. func fetchProducts(completion: @escaping KMPurchaseFetchProductCompletion) {
  70. self.fetchProductCompletion = completion
  71. let productIdentifiers: Set<String> = kPRODUCTS
  72. self.request = SKProductsRequest(productIdentifiers: productIdentifiers)
  73. self.request?.delegate = self
  74. self.request?.start()
  75. }
  76. func purchaseProduct(productIdentifier: String, completion: @escaping KMPurchaseCompletion) {
  77. if SKPaymentQueue.canMakePayments() {
  78. if let product = availableProducts.first(where: { $0.productIdentifier == productIdentifier }) {
  79. print("\("购买产品") + \(productIdentifier)")
  80. let payment = SKPayment(product: product)
  81. SKPaymentQueue.default().add(payment)
  82. } else {
  83. // 未找到匹配的产品
  84. print("未找到匹配的产品")
  85. let tempProductIdentifier = productIdentifier
  86. self.fetchProducts(completion: { [unowned self] isSuccess, products, error in
  87. if isSuccess {
  88. print("获取产品成功")
  89. self.purchaseProduct(productIdentifier: tempProductIdentifier, completion: completion)
  90. } else {
  91. print("获取产品失败")
  92. }
  93. })
  94. }
  95. } else {
  96. print("用户无法进行内购")
  97. }
  98. }
  99. }
  100. extension KMInAppPurchaseManager: SKProductsRequestDelegate {
  101. func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
  102. availableProducts = response.products
  103. self.request?.cancel()
  104. self.request = nil
  105. // 处理产品信息
  106. guard let callBack = self.fetchProductCompletion else { return }
  107. callBack(true, availableProducts, "")
  108. }
  109. func request(_ request: SKRequest, didFailWithError error: Error) {
  110. // 处理请求错误
  111. print("\("用户无法进行内购") + \(error)")
  112. }
  113. }
  114. extension KMInAppPurchaseManager: SKPaymentTransactionObserver {
  115. func paymentQueue(_ queue: SKPaymentQueue, shouldAddStorePayment payment: SKPayment, for product: SKProduct) -> Bool {
  116. // Handle the purchase intent here
  117. // Return true to allow the purchase or false to deny it
  118. return true
  119. }
  120. func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
  121. for transaction in transactions {
  122. switch transaction.transactionState {
  123. case .purchased:
  124. // 购买成功,进行本地二次验证
  125. print("购买成功,进行本地二次验证")
  126. validatePurchase(transaction: transaction)
  127. case .failed:
  128. // 购买失败,处理错误
  129. print("购买失败,处理错误")
  130. handleError(transaction: transaction)
  131. case .restored:
  132. // 恢复购买,进行本地二次验证
  133. print("恢复购买,进行本地二次验证")
  134. validatePurchase(transaction: transaction)
  135. default:
  136. break
  137. }
  138. }
  139. }
  140. // func validatePurchase(transaction: SKPaymentTransaction) {
  141. // // 获取购买凭证
  142. // if let receiptURL = Bundle.main.appStoreReceiptURL,
  143. // let receiptData = try? Data(contentsOf: receiptURL) {
  144. // // 进行本地二次验证
  145. // if let parsedReceipt = parseReceipt(receiptData: receiptData),
  146. // let purchase = parsedReceipt["in_app"] as? [[String: Any]],
  147. // let matchingPurchase = purchase.first(where: { $0["transaction_id"] as? String == transaction.transactionIdentifier }) {
  148. // // 验证购买凭证,进行相应的处理
  149. // if verifyPurchase(purchase: matchingPurchase) {
  150. // // 购买凭证验证成功,进行购买成功的逻辑
  151. // SKPaymentQueue.default().finishTransaction(transaction)
  152. // // ...
  153. // } else {
  154. // // 购买凭证验证失败,进行购买失败的逻辑
  155. // SKPaymentQueue.default().finishTransaction(transaction)
  156. // // ...
  157. // }
  158. // }
  159. // }
  160. // }
  161. //https://sandbox.itunes.apple.com/verifyReceipt
  162. //"https://buy.itunes.apple.com/verifyReceipt"
  163. func validatePurchase(transaction: SKPaymentTransaction) {
  164. // 获取购买凭证
  165. if let receiptURL = Bundle.main.appStoreReceiptURL,
  166. let receiptData = try? Data(contentsOf: receiptURL) {
  167. // 将购买凭证发送到服务器进行验证
  168. sendReceiptToServer(receiptData: receiptData, transaction: transaction)
  169. }
  170. }
  171. //
  172. func sendReceiptToServer(receiptData: Data, transaction: SKPaymentTransaction) {
  173. // 构建请求
  174. // let url = URL(string: "https://your-server.com/verify-receipt")!
  175. // let requestContents = ["receipt-data" : receipt.base64EncodedString()]
  176. let receiptString = receiptData.base64EncodedString(options: [])
  177. let requestContents: [String: Any] = ["receipt-data": receiptString,
  178. "password": kStoreLiteKitSecret]
  179. guard let requestData = try? JSONSerialization.data(withJSONObject: requestContents, options: []) else {
  180. // 交易凭证为空验证失败
  181. return
  182. }
  183. let url = URL(string: "https://sandbox.itunes.apple.com/verifyReceipt")!
  184. var request = URLRequest(url: url)
  185. request.httpMethod = "POST"
  186. request.httpBody = requestData
  187. // 发送请求
  188. let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
  189. if let data = data {
  190. // 处理服务器返回的验证结果
  191. let verificationResult = self.parseVerificationResult(data: data)
  192. if verificationResult {
  193. let receipt = try? JSONSerialization.jsonObject(with: data, options: [])
  194. print(receipt)
  195. // 购买凭证验证成功,进行购买成功的逻辑
  196. SKPaymentQueue.default().finishTransaction(transaction)
  197. // ...
  198. } else {
  199. // 购买凭证验证失败,进行购买失败的逻辑
  200. SKPaymentQueue.default().finishTransaction(transaction)
  201. // ...
  202. }
  203. } else if let error = error {
  204. // 处理网络请求错误
  205. // ...
  206. }
  207. }
  208. task.resume()
  209. }
  210. func parseVerificationResult(data: Data) -> Bool {
  211. // 解析服务器返回的验证结果
  212. // 如果验证成功返回 true,否则返回 false
  213. // ...
  214. return true
  215. }
  216. func handleError(transaction: SKPaymentTransaction) {
  217. // 处理购买失败的逻辑
  218. SKPaymentQueue.default().finishTransaction(transaction)
  219. // ...
  220. }
  221. func verifyPurchase(purchase: [String: Any]) -> Bool {
  222. // 执行购买凭证验证的逻辑,例如验证产品标识符、购买日期等
  223. // 如果验证成功返回 true,否则返回 false
  224. // ...
  225. return true
  226. }
  227. func parseReceipt(receiptData: Data) -> [String: Any]? {
  228. guard let receipt = try? JSONSerialization.jsonObject(with: receiptData, options: []) as? [String: Any] else {
  229. return nil
  230. }
  231. return receipt
  232. }
  233. }