KMInAppPurchaseManager.swift 12 KB

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