Browse Source

【订阅】苹果订阅流程串接(二次验证服务器暂时无法成功)

lizhe 1 year ago
parent
commit
9cfc301fd0

+ 4 - 0
PDF Office/PDF Master.xcodeproj/project.pbxproj

@@ -1144,6 +1144,9 @@
 		AD015FB729AB484400A57062 /* KMLightMemberConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD015FB629AB484400A57062 /* KMLightMemberConfig.swift */; };
 		AD015FB829AB484400A57062 /* KMLightMemberConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD015FB629AB484400A57062 /* KMLightMemberConfig.swift */; };
 		AD015FB929AB484400A57062 /* KMLightMemberConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD015FB629AB484400A57062 /* KMLightMemberConfig.swift */; };
+		AD032CB82A4E6AC100F1D745 /* Starscream.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AD032CB62A4E6A7E00F1D745 /* Starscream.framework */; };
+		AD032CB92A4E6AC100F1D745 /* Starscream.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = AD032CB62A4E6A7E00F1D745 /* Starscream.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+		AD032CBA2A525DAC00F1D745 /* KMInAppPurchaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD0E8AAF2A31B76300DBFD3C /* KMInAppPurchaseManager.swift */; };
 		AD0E8AB02A31B76300DBFD3C /* KMInAppPurchaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD0E8AAF2A31B76300DBFD3C /* KMInAppPurchaseManager.swift */; };
 		AD0E8AB12A31B76300DBFD3C /* KMInAppPurchaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD0E8AAF2A31B76300DBFD3C /* KMInAppPurchaseManager.swift */; };
 		AD0E8AB42A31B78900DBFD3C /* KMDMGPurchaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD0E8AB32A31B78900DBFD3C /* KMDMGPurchaseManager.swift */; };
@@ -12222,6 +12225,7 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				AD032CBA2A525DAC00F1D745 /* KMInAppPurchaseManager.swift in Sources */,
 				BBFBE70B28DD7C21008B2335 /* PDF_ Master_ProUITests.swift in Sources */,
 				BBFBE70D28DD7C21008B2335 /* PDF_ Master_ProUITestsLaunchTests.swift in Sources */,
 			);

+ 3 - 0
PDF Office/PDF Master/Class/Home/ViewController/KMFastToolCollectionViewItem.swift

@@ -32,6 +32,7 @@ public enum DataNavigationViewButtonActionType : Int {
     case OCR            // 批量OCR
     case AutomaticFormRecognition   //表单自动识别
     case FileCompare    // 文件对比
+    case ComparativeTable    // 比较表
 }
 
 
@@ -163,6 +164,8 @@ class KMFastToolMode: NSObject {
             mode.toolSubtitle = NSLocalizedString("Delete/Rotate/Copy/Paste PDF pages", comment: "")
             mode.toolImageName = "icon_pdftools_pageEdit"
             break
+        case .ComparativeTable:
+            break
         }
         return mode
     }

+ 2 - 0
PDF Office/PDF Master/Class/Home/ViewController/KMHomeViewController+Action.swift

@@ -155,6 +155,8 @@ extension KMHomeViewController {
         case .PageEdit:
             fastTool_PageEdit()
             break
+        case .ComparativeTable:
+            break
         }
     }
     

+ 24 - 10
PDF Office/PDF Master/Class/KMLightMember/Controller/ComparativeTable/KMComparativeTableViewController.swift

@@ -98,18 +98,32 @@ class KMComparativeTableViewController: NSWindowController {
         }
         
         controller.subscriptionAction = { controller in
-            KMPurchaseManager.manager.purchaseProduct(productIdentifier: PRODUCT_1) { isSuccess, error in
-                if isSuccess {
-                    print("订阅成功")
-                    comparativeController = nil
-                    comparativeMainWindow?.endSheet(controller.window!)
-                    comparativeMainWindow = nil
-                    controller.close()
-                    
-                    if NSApp.mainWindow != nil {
-                        KMSubscribeSuccessWindowController.show(window: NSApp.mainWindow!)
+            if KMLightMemberManager.manager.isLogin() {
+                KMPurchaseManager.manager.purchaseProduct(productIdentifier: PRODUCT_1) { isSuccess, error in
+                    if isSuccess {
+                        print("订阅成功")
+                        comparativeController = nil
+                        comparativeMainWindow?.endSheet(controller.window!)
+                        comparativeMainWindow = nil
+                        controller.close()
+                        
+                        if NSApp.mainWindow != nil {
+                            KMSubscribeSuccessWindowController.show(window: NSApp.mainWindow!)
+                        }
                     }
                 }
+            } else {
+                comparativeController = nil
+                comparativeMainWindow?.endSheet(controller.window!)
+                comparativeMainWindow = nil
+                controller.close()
+                
+                var email: String = UserDefaults.standard.value(forKey: "kLoginEmail") as? String ?? ""
+                if email.count == 0 {
+                    KMLoginWindowController.show(window: controller.window!, .ComparativeTable, .register)
+                } else {
+                    KMLoginWindowController.show(window: controller.window!, .ComparativeTable)
+                }
             }
         }
         

+ 98 - 4
PDF Office/PDF Master/Class/KMLightMember/InAppPurchase/Appstore/KMInAppPurchaseManager.swift

@@ -66,6 +66,8 @@ class KMInAppPurchaseManager: NSObject {
             return self.updatePurchaseState()
         }
     }
+
+    var orderId: String?
     
     deinit {
         SKPaymentQueue.default().remove(self)
@@ -91,14 +93,14 @@ class KMInAppPurchaseManager: NSObject {
         self.request?.start()
     }
     
-    func purchaseProduct(productIdentifier: String, completion: @escaping KMPurchaseCompletion) {
+    func purchaseProduct(productIdentifier: String, orderId: String = "", completion: @escaping KMPurchaseCompletion) {
         self.purchaseProductCompletion = completion
+        self.orderId = orderId
         if SKPaymentQueue.canMakePayments() {
             if let product = availableProducts.first(where: { $0.productIdentifier == productIdentifier }) {
                 print("\("购买产品") + \(productIdentifier)")
                 let payment = SKMutablePayment(product: product)
-                let uuid: String = GetHardwareUUID() ?? ""
-                payment.applicationUsername = uuid
+                payment.applicationUsername = orderId
                 SKPaymentQueue.default().add(payment)
             } else {
                 // 未找到匹配的产品
@@ -184,7 +186,9 @@ extension KMInAppPurchaseManager: SKPaymentTransactionObserver {
         print("服务器返回数据")
         let hasPurchased = false
         let hasFailed = false
-        for transaction in transactions {
+        if transactions.count > 0 {
+            let transaction = transactions.first!
+    //        for transaction in transactions {
             switch transaction.transactionState {
             case .purchased:
                 // 购买成功,进行本地二次验证
@@ -202,6 +206,7 @@ extension KMInAppPurchaseManager: SKPaymentTransactionObserver {
             default:
                 break
             }
+    //        }
         }
     }
     
@@ -229,6 +234,28 @@ extension KMInAppPurchaseManager: SKPaymentTransactionObserver {
      */
     func sendReceiptToServer(receiptData: Data, transaction: SKPaymentTransaction) {
         // 构建请求
+        let receiptString = receiptData.base64EncodedString(options: [])
+        let tempOrderId = self.orderId
+        print(receiptString)
+        KMRequestServerManager.manager.parseVerification(applePayProductId: PRODUCT_1, orderId: tempOrderId!, receipt: receiptString) { [unowned self] success, result in
+            if success, let data = result?.result {
+                // 处理服务器返回的验证结果
+                //解析数据
+                KMLightMemberUserInfo.parseData(data: data) { tData in
+                    KMLightMemberManager.manager.reloadUserInfo()
+                    self.handleAction(state: .verSuccess)
+                }
+            } else if result?.error != nil {
+                // 处理网络请求错误
+                // ...
+                self.handleAction(state: .failed)
+            }
+            SKPaymentQueue.default().finishTransaction(transaction)
+        }
+    }
+    
+    func sendReceiptToAppleServer(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: [])
@@ -298,6 +325,33 @@ extension KMInAppPurchaseManager: SKPaymentTransactionObserver {
         return true
     }
     
+    func parseAppleVerificationResult(data: Data) -> Bool {
+        // 解析服务器返回的验证结果
+        // 如果验证成功返回 true,否则返回 false
+        // ...
+        let receipt: [String: Any] = self.parseReceipt(receiptData: data) ?? [:]
+        print(receipt)
+        let status: Int = receipt["status"] as! Int
+        if status == 21007 {
+            self.handleAction(state: .verFailed)
+//            [self verifyPurchaseWithPaymentTransaction:transaction isTestServer:YES];
+        } else if status == 0 {
+            //保存票据信息
+            UserDefaults.standard.set(receipt, forKey: "kInAppPurchaseReceipt")
+            UserDefaults.standard.synchronize()
+            
+            let state = self.verifyPurchase(purchase: receipt)
+            if state == .subscription {
+                self.handleAction(state: .verSuccess)
+            } else {
+                self.handleAction(state: .verFailed)
+            }
+        } else {
+            self.handleAction(state: .verFailed)
+        }
+        return true
+    }
+    
     func handleError(transaction: SKPaymentTransaction) {
         // 处理购买失败的逻辑
         SKPaymentQueue.default().finishTransaction(transaction)
@@ -345,6 +399,46 @@ extension KMInAppPurchaseManager: SKPaymentTransactionObserver {
         return .unknow
     }
     
+    func verifyApplePurchase(purchase: [String: Any]) -> KMPurchaseManagerState {
+        // 执行购买凭证验证的逻辑,例如验证产品标识符、购买日期等
+        // 如果验证成功返回 true,否则返回 false
+        // ...
+        /**
+         "expires_date" = "2023-06-27 09:28:20 Etc/GMT";
+         "expires_date_ms" = 1687858100000;
+         "expires_date_pst" = "2023-06-27 02:28:20 America/Los_Angeles";
+         "in_app_ownership_type" = PURCHASED;
+         "is_in_intro_offer_period" = false;
+         "is_trial_period" = false;
+         "original_purchase_date" = "2023-06-27 07:27:22 Etc/GMT";
+         "original_purchase_date_ms" = 1687850842000;
+         "original_purchase_date_pst" = "2023-06-27 00:27:22 America/Los_Angeles";
+         "original_transaction_id" = 2000000357748210;
+         "product_id" = "com.pdftechnologies.pdfreader.mac.yearly.001";
+         "purchase_date" = "2023-06-27 08:28:20 Etc/GMT";
+         "purchase_date_ms" = 1687854500000;
+         "purchase_date_pst" = "2023-06-27 01:28:20 America/Los_Angeles";
+         quantity = 1;
+         "transaction_id" = 2000000357808638;
+         "web_order_line_item_id" = 2000000030580071;
+         */
+        
+        let receipt: [String: Any] = purchase["receipt"] as? [String : Any] ?? [:]
+        let in_app: [NSDictionary] = receipt["in_app"] as? [NSDictionary] ?? []
+        let request_date_ms: Int = Int(receipt["request_date_ms"] as? String ?? "0") ?? 0
+        for item in in_app {
+            let expires_date_ms: Int = Int(item["expires_date_ms"] as? String ?? "-1") ?? -1
+            let product_id: String = item["product_id"] as? String ?? ""
+            let now_date_ms: Int = Int(NSDate().timeIntervalSince1970) * 1000
+            if product_id == PRODUCT_1 &&
+//                expires_date_ms > request_date_ms &&
+                expires_date_ms > now_date_ms {
+                return .subscription
+            }
+        }
+        return .unknow
+    }
+    
     func parseReceipt(receiptData: Data) -> [String: Any]? {
         guard let receipt = try? JSONSerialization.jsonObject(with: receiptData, options: []) as? [String: Any] else {
             return nil

+ 2 - 2
PDF Office/PDF Master/Class/KMLightMember/InAppPurchase/DMG/KMDMGPurchaseManager.swift

@@ -13,8 +13,8 @@ class KMDMGPurchaseManager: NSObject {
     
     var availableProducts: [KMProduct] = []
     
-    func purchaseProduct(productIdentifier: String, completion: KMPurchaseCompletion) {
-        NSWorkspace.shared.open(URL(string: "http://test-pdf-pro.kdan.cn:3021/master/checkout")!)
+    func purchaseProduct(productIdentifier: String, email: String, completion: KMPurchaseCompletion) {
+        NSWorkspace.shared.open(URL(string: "http://test-pdf-pro.kdan.cn:3021/master/checkout?email=\(email)")!)
     }
     
     func fetchProducts(completion: @escaping KMPurchaseFetchProductCompletion) {

+ 16 - 1
PDF Office/PDF Master/Class/KMLightMember/InAppPurchase/KMPurchaseManager.swift

@@ -92,7 +92,22 @@ class KMPurchaseManager: NSObject {
         print("准备订阅中")
 #if VERSION_FREE
         print("正在订阅中AppStore")
-        KMInAppPurchaseManager.manager.purchaseProduct(productIdentifier: productIdentifier, completion: completion)
+        let userId: String = KMLightMemberManager.manager.info.id
+        KMRequestServerManager.manager.createOrder(productId: "21", userId: userId) { success, orderId, result in
+            if success {
+                if orderId?.count != 0 {
+                    KMInAppPurchaseManager.manager.purchaseProduct(productIdentifier: PRODUCT_1, orderId: orderId!) { isSuccess, error in
+                        if isSuccess {
+                            print("购买成功")
+                            completion(true, error)
+                        } else {
+                            print("购买失败")
+                            completion(false, error)
+                        }
+                    }
+                }
+            }
+        }
 #endif
         
 #if VERSION_DMG

+ 77 - 2
PDF Office/PDF Master/Class/KMLightMember/Manager/KMRequestServerManager.swift

@@ -36,6 +36,10 @@ enum KMRequestServerErrorCodeType: Int, CaseIterable {
     case EXCEPTION_MSG_USER_TRAIL_IN_PROGRESS = 325
     case EXCEPTION_TIME_TRANSFER_ERROR = 326
     case EXCEPTION_MSG_PASSWORD_CONTAIN_EMRTY = 327
+    case EXCEPTION_MSG_CREATE_ORDER_PARAMETER = 328//,"支付方式异常"),
+    case EXCEPTION_MSG_EVENT_IS_CURRENTLY_NOT_SUPPORTED = 329 //, "当前事件暂不支持"),
+    case EXCEPTION_MSG_THE_ACCOUNT_IS_ALREADY_LOGGED_IN_ON_OTHER_DEVICES = 330//, "账号已在其他设备登录"),
+    case EXCEPTION_MSG_ABNORMAL_USER_STATUS = 331 //,"当前邮箱已被停用或者处于注销中状态"),
     case EMAIL_VERIFY_CODE_KEY_ERROR2 = 700
     
     static func typeOfMessage(type: KMRequestServerErrorCodeType?) -> String {
@@ -95,6 +99,14 @@ enum KMRequestServerErrorCodeType: Int, CaseIterable {
             result = "Email code error"
         case .EXCEPTION_MSG_PASSWORD_CONTAIN_EMRTY:
             result = "Spaces are not allowed in password" //result = "The password cannot contain Spaces"
+        case .EXCEPTION_MSG_CREATE_ORDER_PARAMETER:
+            result = "Abnormal payment method"
+        case .EXCEPTION_MSG_EVENT_IS_CURRENTLY_NOT_SUPPORTED:
+            result = "The current event is not supported"
+        case .EXCEPTION_MSG_THE_ACCOUNT_IS_ALREADY_LOGGED_IN_ON_OTHER_DEVICES:
+            result = "The account has been logged in to another device"
+        case .EXCEPTION_MSG_ABNORMAL_USER_STATUS:
+            result = "The current mailbox has been disabled or logged out"
         case .unknown:
             result = ""
         case .correct:
@@ -127,9 +139,14 @@ struct Result {
 }
 
 typealias KMRequestServerComplete = (_ success: Bool, _ result: Result?) -> Void
+
+
 class KMRequestServerManager: NSObject {
     static let manager = KMRequestServerManager()
-    
+}
+
+//MARK: - 会员
+extension KMRequestServerManager {
     /**
      @abstract 获取验证码
      @param verifyCodeType 验证入口类型
@@ -425,7 +442,62 @@ class KMRequestServerManager: NSObject {
             }
         }
     }
+}
+
+//MARK: - 订阅
+extension KMRequestServerManager {
+    func createOrder(productId: String, userId: String, complete: @escaping (_ success: Bool, _ orderId: String?, _ result: Result?) -> Void) {
+        let urlString = KMLightMemberManager.manager.config.kServerURL + "/pdf-office-website/pay/appStoreCreateOrder"
+        let params: [String: Any] = ["productId": productId,
+                                     "paymentMethod": "APPLE_PAY",
+                                     "userId": userId,
+                                     "appId": "16"]
+        
+        let token: String = KMLightMemberManager.manager.token.access_token
+        if token == "" {
+            complete(false, "", Result())
+            return
+        }
+        KMRequestServer.requestServer.request(urlString: urlString, method: .post, params: params) { requestSerializer in
+            requestSerializer.setValue("Apifox/1.0.0 (https://www.apifox.cn)", forHTTPHeaderField: "User-Agent")
+            requestSerializer.setValue("Bearer " + token, forHTTPHeaderField: "Authorization")
+        } completion: { [unowned self] (task, responseObject, error) in
+            let result = self.dealData(responseObject: responseObject as? NSDictionary, error: error)
+            if result.code == 200 {
+                complete(true, result.result["id"] as! String, result)
+            } else {
+                complete(false, "", result)
+            }
+        }
+    }
     
+    func parseVerification(applePayProductId: String, orderId: String, receipt: String,complete: @escaping KMRequestServerComplete) {
+        let urlString = KMLightMemberManager.manager.config.kServerURL + "/pdf-office-website/pay/appStoreOrderSucceed"
+        let params: [String: Any] = ["applePayProductId": applePayProductId,
+                                     "orderId": orderId,
+                                     "receipt": receipt]
+        
+        let token: String = KMLightMemberManager.manager.token.access_token
+        if token == "" {
+            complete(false, Result())
+            return
+        }
+        KMRequestServer.requestServer.request(urlString: urlString, method: .post, params: params) { requestSerializer in
+            requestSerializer.setValue("Apifox/1.0.0 (https://www.apifox.cn)", forHTTPHeaderField: "User-Agent")
+            requestSerializer.setValue("Bearer " + token, forHTTPHeaderField: "Authorization")
+        } completion: { [unowned self] (task, responseObject, error) in
+            let result = self.dealData(responseObject: responseObject as? NSDictionary, error: error)
+            if result.code == 200 {
+                complete(true, result)
+            } else {
+                complete(false, result)
+            }
+        }
+    }
+}
+
+//MARK: - 数据处理
+extension KMRequestServerManager {
     func dealData(responseObject: NSDictionary?, error: NSError?) -> Result {
         var dic: NSDictionary = [:]
         if (error == nil && responseObject != nil) {
@@ -490,7 +562,10 @@ class KMRequestServerManager: NSObject {
         print(dic)
         return Result(result: result,message: message,code: code, error: error)
     }
-    
+}
+
+//MARK: - AI
+extension KMRequestServerManager {
     /**
      @abstract 翻译上传
      @param file  文件路径