TSPurchaseManager.swift 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646
  1. //
  2. // TSPurchaseManager.swift
  3. // TSLiveWallpaper
  4. //
  5. // Created by 100Years on 2025/1/13.
  6. //
  7. import Foundation
  8. import StoreKit
  9. public enum PremiumPeriod: String, CaseIterable {
  10. case none = ""
  11. case week = "Week"
  12. case month = "Monthly"
  13. case year = "Yearly"
  14. case lifetime = "Lifetime"
  15. }
  16. public enum VipFreeNumType: String, CaseIterable {
  17. case generatePic = "kGeneratePicFreeNum"
  18. case aichat = "kAIChatFreeNum"
  19. case textGeneratePic = "kTextGeneratePicFreeNum"
  20. case picToPic = "kPicToPicFreeNum"
  21. }
  22. public struct PurchaseProduct {
  23. public let productId: String
  24. public let period: PremiumPeriod
  25. public init(productId: String, period: PremiumPeriod) {
  26. self.productId = productId
  27. self.period = period
  28. }
  29. }
  30. public enum PremiumRequestState {
  31. case none
  32. case loading
  33. case loadSuccess
  34. case loadFail
  35. case paying
  36. case paySuccess
  37. case payFail
  38. case restoreing
  39. case restoreSuccess
  40. case restoreFail
  41. case verifying
  42. case verifySuccess
  43. case verifyFail
  44. }
  45. public extension Notification.Name {
  46. static let kPurchasePrepared = Self.init("kPurchaseProductPrepared")
  47. static let kPurchaseDidChanged = Self.init("kPurchaseDidChanged")
  48. }
  49. private let kFreeNumKey = "kFreeNumKey"
  50. private let kPremiumExpiredInfoKey = "premiumExpiredInfoKey"
  51. typealias PurchaseStateChangeHandler = (_ manager: PurchaseManager, _ state: PremiumRequestState, _ object: Any?) -> Void
  52. let kPurchaseDefault = PurchaseManager.default
  53. public class PurchaseManager: NSObject {
  54. @objc public static let `default` = PurchaseManager()
  55. //苹果共享密钥
  56. private let AppleSharedKey:String = "7fa595ea66a54b16b14ca2e2bf40f276"
  57. //商品信息
  58. public lazy var purchaseProducts:[PurchaseProduct] = {
  59. return [
  60. // PurchaseProduct(productId: "101", period:.month),
  61. PurchaseProduct(productId: "102", period:.year),
  62. PurchaseProduct(productId: "103", period:.week),
  63. //PurchaseProduct(productId: "003", period: .lifetime),
  64. ]
  65. }()
  66. struct Config {
  67. static let verifyUrl = "https://buy.itunes.apple.com/verifyReceipt"
  68. static let sandBoxUrl = "https://sandbox.itunes.apple.com/verifyReceipt"
  69. }
  70. lazy var products: [SKProduct] = []
  71. var onPurchaseStateChanged: PurchaseStateChangeHandler?
  72. // 会员信息
  73. var vipInformation: [String: Any] = [:]
  74. // 免费使用会员的次数
  75. var freeDict:[String:Int] = [:]
  76. //原始订单交易id dict
  77. var originalTransactionIdentifierDict:[String:String] = [:]
  78. override init() {
  79. super.init()
  80. SKPaymentQueue.default().add(self)
  81. if let info = UserDefaults.standard.object(forKey: kPremiumExpiredInfoKey) as? [String: Any] {
  82. vipInformation = info
  83. }
  84. initializeForFree()
  85. }
  86. public var expiredDate: Date? {
  87. guard let time = vipInformation["expireTime"] as? String else {
  88. return nil
  89. }
  90. return convertExpireDate(from: time)
  91. }
  92. public var expiredDateString: String {
  93. if vipType == .lifetime{
  94. return "Life Time"
  95. } else {
  96. if let expDate = expiredDate {
  97. let format = DateFormatter()
  98. format.locale = .current
  99. format.dateFormat = "yyyy-MM-dd"
  100. return format.string(from: expDate)
  101. } else {
  102. return "--"
  103. }
  104. }
  105. }
  106. private func convertExpireDate(from string: String) -> Date? {
  107. if let ts = TimeInterval(string) {
  108. let date = Date(timeIntervalSince1970: ts / 1000)
  109. return date
  110. }
  111. return nil
  112. }
  113. @objc public var isVip: Bool {
  114. // #if DEBUG
  115. // return true
  116. // #endif
  117. guard let expiresDate = expiredDate else {
  118. return false
  119. }
  120. let todayStart = Calendar.current.startOfDay(for: Date())
  121. let todayStartTs = todayStart.timeIntervalSince1970
  122. let expiresTs = expiresDate.timeIntervalSince1970
  123. return expiresTs > todayStartTs
  124. }
  125. public var vipType: PremiumPeriod {
  126. guard isVip, let type = vipInformation["type"] as? String else {
  127. return .none
  128. }
  129. return PremiumPeriod(rawValue: type) ?? .none
  130. }
  131. /// 过期时间: 1683277585000 毫秒
  132. func updateExpireTime(_ timeInterval: String,
  133. for productId: String) {
  134. vipInformation.removeAll()
  135. vipInformation["expireTime"] = timeInterval
  136. vipInformation["productId"] = productId
  137. vipInformation["type"] = period(for: productId).rawValue
  138. UserDefaults.standard.set(vipInformation, forKey: kPremiumExpiredInfoKey)
  139. UserDefaults.standard.synchronize()
  140. NotificationCenter.default.post(name: .kPurchaseDidChanged, object: nil)
  141. }
  142. // 商品id对应的时间周期
  143. func period(for productId: String) -> PremiumPeriod {
  144. return purchaseProducts.first(where: { $0.productId == productId })?.period ?? .none
  145. }
  146. // 时间周期对应的商品id
  147. func productId(for period: PremiumPeriod) -> String? {
  148. return purchaseProducts.first(where: { $0.period == period })?.productId
  149. }
  150. }
  151. // MARK: 商品信息
  152. extension PurchaseManager {
  153. public func product(for period: PremiumPeriod) -> SKProduct? {
  154. return products.first(where: { $0.productIdentifier == productId(for: period) })
  155. }
  156. // 商品价格
  157. public func price(for period: PremiumPeriod) -> String? {
  158. guard let product = product(for: period) else {
  159. return nil
  160. }
  161. let formatter = NumberFormatter()
  162. formatter.formatterBehavior = NumberFormatter.Behavior.behavior10_4
  163. formatter.numberStyle = .currency
  164. formatter.locale = product.priceLocale
  165. return formatter.string(from: product.price)
  166. }
  167. // 平局每周的金额,对于年来说
  168. public func averageWeeklyForYear() -> String? {
  169. guard let product = product(for: .year) else {
  170. return nil
  171. }
  172. let price = product.price.doubleValue
  173. let calculatePrice = price / 52.0
  174. let originStr = String(format: "%.2f", calculatePrice)
  175. let originPrice = NSDecimalNumber(string: originStr, locale: product.priceLocale)
  176. let formatter = NumberFormatter()
  177. formatter.formatterBehavior = NumberFormatter.Behavior.behavior10_4
  178. formatter.numberStyle = .currency
  179. formatter.locale = product.priceLocale
  180. return formatter.string(from: originPrice)
  181. }
  182. // public func originalPrice(for period: PremiumPeriod) -> String? {
  183. // guard let product = product(for: period) else {
  184. // return nil
  185. // }
  186. // switch period {
  187. // case .year, .lifetime:
  188. // // 5折
  189. // let price = product.price.doubleValue
  190. // let calculatePrice = price * 2
  191. // let originStr = String(format: "%.2f", calculatePrice)
  192. // let originPrice = NSDecimalNumber(string: originStr, locale: product.priceLocale)
  193. //
  194. // let formatter = NumberFormatter()
  195. // formatter.formatterBehavior = NumberFormatter.Behavior.behavior10_4
  196. // formatter.numberStyle = .currency
  197. // formatter.locale = product.priceLocale
  198. // return formatter.string(from: originPrice)
  199. // default:
  200. // return nil
  201. // }
  202. // }
  203. }
  204. // MARK: 商品 & 订阅请求
  205. extension PurchaseManager {
  206. ///请求商品
  207. public func requestProducts() {
  208. if !products.isEmpty {
  209. purchase(self, didChaged: .loadSuccess, object: nil)
  210. }
  211. purchase(self, didChaged: .loading, object: nil)
  212. let productIdentifiers = Set(purchaseProducts.map({ $0.productId }))
  213. debugPrint("PurchaseManager requestProducts = \(productIdentifiers)")
  214. let request = SKProductsRequest(productIdentifiers: productIdentifiers)
  215. request.delegate = self
  216. request.start()
  217. }
  218. public func restorePremium() {
  219. purchase(self, didChaged: .restoreing, object: nil)
  220. SKPaymentQueue.default().restoreCompletedTransactions()
  221. debugPrint("PurchaseManager restoreCompletedTransactions")
  222. subscriptionApple(type: .created, jsonString: "Payment restore")
  223. }
  224. /// 购买支付
  225. public func pay(for period: PremiumPeriod) {
  226. guard SKPaymentQueue.canMakePayments() else {
  227. purchase(self, didChaged: .payFail, object: "Payment failed, please check your payment account")
  228. return
  229. }
  230. guard SKPaymentQueue.default().transactions.count <= 0 else {
  231. purchase(self, didChaged: .payFail, object: "You have outstanding orders that must be paid for before a new subscription can be placed.")
  232. restorePremium()
  233. return
  234. }
  235. if let product = product(for: period) {
  236. purchase(self, didChaged: .paying, object: nil)
  237. let payment = SKPayment(product: product)
  238. SKPaymentQueue.default().add(payment)
  239. debugPrint("PurchaseManager pay period = \(period)")
  240. subscriptionApple(type: .created, jsonString: "Payment period = \(product)")
  241. }else{
  242. purchase(self, didChaged: .payFail, object: "Payment failed, no this item")
  243. }
  244. }
  245. }
  246. // MARK: 商品回调
  247. extension PurchaseManager: SKProductsRequestDelegate {
  248. public func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
  249. let products = response.products
  250. self.products = products
  251. purchase(self, didChaged: .loadSuccess, object: nil)
  252. NotificationCenter.default.post(name: .kPurchasePrepared, object: nil)
  253. debugPrint("PurchaseManager productsRequest didReceive = \(products)")
  254. }
  255. public func request(_ request: SKRequest, didFailWithError error: Error) {
  256. debugPrint("PurchaseManager productsRequest error = \(error)")
  257. purchase(self, didChaged: .loadFail, object: error.localizedDescription)
  258. }
  259. }
  260. // MARK: 订阅回调
  261. extension PurchaseManager: SKPaymentTransactionObserver {
  262. public func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
  263. debugPrint("PurchaseManager paymentQueue transactions.count = \(transactions.count)")
  264. // debugPrint("PurchaseManager paymentQueue transactions = \(transactions)")
  265. originalTransactionIdentifierDict.removeAll()
  266. // 因为只有订阅类的购买项
  267. for transaction in transactions {
  268. // debugPrint("PurchaseManager paymentQueue transactions transactionIdentifier original= \(transaction.original?.transactionIdentifier)")
  269. // debugPrint("PurchaseManager paymentQueue transactions transactionIdentifier = \(transaction.transactionIdentifier)")
  270. // debugPrint("PurchaseManager paymentQueue transactions transactionIdentifier productIdentifier = \(transaction.payment.productIdentifier)")
  271. switch transaction.transactionState {
  272. case .purchasing:
  273. // Transaction is being added to the server queue.
  274. purchase(self, didChaged: .paying, object: nil)
  275. case .purchased:
  276. SKPaymentQueue.default().finishTransaction(transaction)
  277. //同样的原始订单,只处理一次.
  278. guard judgeWhether(transaction: transaction) else {
  279. break
  280. }
  281. // Transaction is in queue, user has been charged. Client should complete the transaction.
  282. #if DEBUG
  283. verifyPayResult(transaction: transaction, useSandBox: true)
  284. #else
  285. verifyPayResult(transaction: transaction, useSandBox: false)
  286. #endif
  287. case .failed:
  288. SKPaymentQueue.default().finishTransaction(transaction)
  289. // Transaction was cancelled or failed before being added to the server queue.
  290. var message = "Payment Failed"
  291. if let error = transaction.error as? SKError,
  292. error.code == SKError.paymentCancelled {
  293. message = "The subscription was canceled"
  294. }
  295. purchase(self, didChaged: .payFail, object: message)
  296. subscriptionApple(type: .result, jsonString: message)
  297. case .restored:
  298. SKPaymentQueue.default().finishTransaction(transaction)
  299. //同样的原始订单,只处理一次.
  300. guard judgeWhether(transaction: transaction) else {
  301. break
  302. }
  303. // Transaction was restored from user's purchase history. Client should complete the transaction.
  304. if let original = transaction.original,
  305. original.transactionState == .purchased {
  306. #if DEBUG
  307. verifyPayResult(transaction: transaction, useSandBox: true)
  308. #else
  309. verifyPayResult(transaction: transaction, useSandBox: false)
  310. #endif
  311. } else {
  312. purchase(self, didChaged: .restoreFail, object: "Failed to restore subscribe, please try again")
  313. subscriptionApple(type: .result, jsonString: "Failed to restore subscribe, please try again")
  314. }
  315. case .deferred: // The transaction is in the queue, but its final status is pending external action.
  316. break
  317. @unknown default:
  318. SKPaymentQueue.default().finishTransaction(transaction)
  319. }
  320. }
  321. }
  322. public func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: Error) {
  323. purchase(self, didChaged: .restoreFail, object: nil)
  324. }
  325. public func paymentQueueRestoreCompletedTransactionsFinished(_ queue: SKPaymentQueue) {
  326. if let trans = queue.transactions.first(where: { $0.transactionState == .purchased }) {
  327. verifyPayResult(transaction: trans, useSandBox: false)
  328. } else if queue.transactions.isEmpty {
  329. purchase(self, didChaged: .restoreFail, object: "You don't have an active subscription")
  330. }
  331. }
  332. func judgeWhether(transaction:SKPaymentTransaction) -> Bool {
  333. let id = transaction.original?.transactionIdentifier
  334. if let id = id {
  335. if let value = originalTransactionIdentifierDict[id] {
  336. return false
  337. }
  338. originalTransactionIdentifierDict[id] = "1"
  339. }
  340. return true
  341. }
  342. }
  343. extension PurchaseManager {
  344. func verifyPayResult(transaction: SKPaymentTransaction, useSandBox: Bool) {
  345. purchase(self, didChaged: .verifying, object: nil)
  346. guard let url = Bundle.main.appStoreReceiptURL,
  347. let receiptData = try? Data(contentsOf: url) else {
  348. purchase(self, didChaged: .verifyFail, object: "凭证文件为空")
  349. return
  350. }
  351. let requestContents = [
  352. "receipt-data": receiptData.base64EncodedString(),
  353. "password": AppleSharedKey,
  354. ]
  355. guard let requestData = try? JSONSerialization.data(withJSONObject: requestContents) else {
  356. purchase(self, didChaged: .verifyFail, object: "凭证文件为空")
  357. return
  358. }
  359. let verifyUrlString = useSandBox ? Config.sandBoxUrl : Config.verifyUrl
  360. postRequest(urlString: verifyUrlString, httpBody: requestData) { [weak self] data, error in
  361. guard let self = self else { return }
  362. if let data = data,
  363. let jsonResponse = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
  364. debugPrint("PurchaseManager verifyPayResult = \(jsonResponse)")
  365. let status = jsonResponse["status"]
  366. if let status = status as? String, status == "21007" {
  367. self.verifyPayResult(transaction: transaction, useSandBox: true)
  368. } else if let status = status as? Int, status == 21007 {
  369. self.verifyPayResult(transaction: transaction, useSandBox: true)
  370. } else if let status = status as? String, status == "0" {
  371. self.handlerPayResult(transaction: transaction, resp: jsonResponse)
  372. } else if let status = status as? Int, status == 0 {
  373. self.handlerPayResult(transaction: transaction, resp: jsonResponse)
  374. } else {
  375. self.purchase(self, didChaged: .verifyFail, object: "验证结果状态码错误:\(status.debugDescription)")
  376. }
  377. } else {
  378. self.purchase(self, didChaged: .verifyFail, object: "验证结果为空")
  379. debugPrint("PurchaseManager 验证结果为空")
  380. }
  381. }
  382. /*
  383. 21000 App Store无法读取你提供的JSON数据
  384. 21002 收据数据不符合格式
  385. 21003 收据无法被验证
  386. 21004 你提供的共享密钥和账户的共享密钥不一致
  387. 21005 收据服务器当前不可用
  388. 21006 收据是有效的,但订阅服务已经过期。当收到这个信息时,解码后的收据信息也包含在返回内容中
  389. 21007 收据信息是测试用(sandbox),但却被发送到产品环境中验证
  390. 21008 收据信息是产品环境中使用,但却被发送到测试环境中验证
  391. */
  392. }
  393. func handlerPayResult(transaction: SKPaymentTransaction, resp: [String: Any]) {
  394. var isLifetime = false
  395. // 终生会员
  396. if let receipt = resp["receipt"] as? [String: Any],
  397. let in_app = receipt["in_app"] as? [[String: Any]] {
  398. if let lifetimeProductId = purchaseProducts.first(where: { $0.period == .lifetime })?.productId,
  399. let _ = in_app.filter({ ($0["product_id"] as? String) == lifetimeProductId }).first(where: { item in
  400. if let purchase_date = item["purchase_date"] as? String,
  401. !purchase_date.isEmpty {
  402. return true
  403. } else if let purchase_date_ms = item["purchase_date_ms"] as? String,
  404. !purchase_date_ms.isEmpty {
  405. return true
  406. }
  407. return false
  408. }) {
  409. updateExpireTime(lifetimeExpireTime, for: lifetimeProductId)
  410. isLifetime = true
  411. }
  412. }
  413. if !isLifetime {
  414. let info = resp["latest_receipt_info"] as? [[String: Any]]
  415. if let firstItem = info?.first,
  416. let expires_date_ms = firstItem["expires_date_ms"] as? String,
  417. let productId = firstItem["product_id"] as? String {
  418. updateExpireTime(expires_date_ms, for: productId)
  419. }
  420. }
  421. DispatchQueue.main.async {
  422. if transaction.transactionState == .restored {
  423. self.purchase(self, didChaged: .restoreSuccess, object: nil)
  424. } else {
  425. self.purchase(self, didChaged: .paySuccess, object: nil)
  426. }
  427. }
  428. subscriptionApple(type: .result, jsonString: simplifyVerifyPayResult(resp: resp))
  429. }
  430. // 终生会员过期时间:100年
  431. var lifetimeExpireTime: String {
  432. let date = Date().addingTimeInterval(100 * 365 * 24 * 60 * 60)
  433. return "\(date.timeIntervalSince1970 * 1000)"
  434. }
  435. /// 发送 POST 请求
  436. /// - Parameters:
  437. /// - urlString: 请求的 URL 字符串
  438. /// - parameters: 请求的参数字典(将自动转换为 JSON)
  439. /// - timeout: 超时时间(默认 30 秒)
  440. /// - completion: 请求完成的回调,返回 `Data?` 和 `Error?`
  441. func postRequest(
  442. urlString: String,
  443. httpBody: Data?,
  444. timeout: TimeInterval = 90,
  445. completion: @escaping (Data?, Error?) -> Void
  446. ) {
  447. // 确保 URL 有效
  448. guard let url = URL(string: urlString) else {
  449. completion(nil, NSError(domain: "Invalid URL", code: -1, userInfo: nil))
  450. return
  451. }
  452. dePrint("postRequest urlString=\(urlString)")
  453. // 创建请求
  454. var request = URLRequest(url: url)
  455. request.httpMethod = "POST"
  456. request.timeoutInterval = timeout
  457. request.setValue("application/json", forHTTPHeaderField: "Content-Type")
  458. request.httpBody = httpBody
  459. // 创建数据任务
  460. let task = URLSession.shared.dataTask(with: request) { data, response, error in
  461. completion(data, error)
  462. }
  463. // 启动任务
  464. task.resume()
  465. }
  466. }
  467. public extension PurchaseManager {
  468. func canContinue(_ requireVip: Bool) -> Bool {
  469. guard requireVip else {
  470. return true
  471. }
  472. return isVip
  473. }
  474. func purchase(_ manager: PurchaseManager, didChaged state: PremiumRequestState, object: Any?){
  475. onPurchaseStateChanged?(manager,state,object)
  476. }
  477. }
  478. /// 免费生成图片次数
  479. extension PurchaseManager {
  480. /// 使用一次免费次数
  481. func useOnceForFree(type:VipFreeNumType){
  482. if isVip {
  483. return
  484. }
  485. var freeNum = freeDict[type.rawValue] ?? 0
  486. if freeNum > 0 {
  487. freeNum-=1
  488. }
  489. if freeNum < 0 {
  490. freeNum = 0
  491. }
  492. freeDict[type.rawValue] = freeNum
  493. saveForFree()
  494. }
  495. func freeNum(type:VipFreeNumType) -> Int{
  496. let freeNum = freeDict[type.rawValue] ?? 0
  497. return freeNum
  498. }
  499. func saveForFree(){
  500. UserDefaults.standard.set(freeDict, forKey: kFreeNumKey)
  501. UserDefaults.standard.synchronize()
  502. }
  503. func initializeForFree(){
  504. if let dict = UserDefaults.standard.dictionary(forKey: kFreeNumKey) as? [String:Int]{
  505. freeDict = dict
  506. }else{
  507. freeDict = [
  508. VipFreeNumType.generatePic.rawValue:1,
  509. VipFreeNumType.aichat.rawValue:1,
  510. VipFreeNumType.textGeneratePic.rawValue:1,
  511. VipFreeNumType.picToPic.rawValue:1
  512. ]
  513. saveForFree()
  514. }
  515. }
  516. /// 免费次数是否可用
  517. func freeNumAvailable(type:VipFreeNumType) -> Bool{
  518. if isVip == true {
  519. return true
  520. }else{
  521. if let freeNum = freeDict[type.rawValue],freeNum > 0 {
  522. return true
  523. }
  524. }
  525. return false
  526. }
  527. /// 是否展示生成类的会员图标
  528. func generateVipShow(type:VipFreeNumType) -> Bool{
  529. if isVip == false, freeNum(type: type) > 0 {
  530. return false
  531. }
  532. return true
  533. }
  534. }
  535. /*
  536. 首先,创建SKProductsRequest对象并使用init(productIdentifiers:)初始化,传入要查询的产品标识符。
  537. 然后,调用start()方法开始请求产品信息。
  538. 当请求成功时,productsRequest(_:didReceive:)方法会被调用,在这里可以获取产品详细信息并展示给用户(如在界面上显示产品价格、名称等)。如果请求失败,productsRequest(_:didFailWithError:)方法会被调用来处理错误。
  539. 当用户决定购买某个产品后,根据产品信息(SKProduct对象)创建SKPayment对象,然后使用SKPaymentQueue的add(_:)方法将支付请求添加到支付队列。
  540. 同时,在应用启动等合适的时机,通过SKPaymentQueue的addTransactionObserver(_:)方法添加交易观察者。当支付状态发生变化时,paymentQueue(_:updatedTransactions:)方法会被调用,在这里可以根据交易状态(如购买成功、失败、恢复等)进行相应的处理。
  541. */