From 5bb65dc1f40855d2e3fb15615ed06b7323ddc0f1 Mon Sep 17 00:00:00 2001 From: zjx Date: Fri, 8 Aug 2025 18:10:36 +0800 Subject: [PATCH] =?UTF-8?q?1.1.3=E5=8F=91=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Veloria.xcodeproj/project.pbxproj | 46 +++++++++++++++- Veloria/AppDelegate/SceneDelegate+APNS.swift | 4 ++ .../Base/Controller/VPTabBarController.swift | 6 +++ Veloria/Base/Networking/API/VPStatAPI.swift | 54 +++++++++++++++++++ Veloria/Base/Networking/API/VPWalletAPI.swift | 4 +- .../Controller/VPStoreViewController.swift | 6 +++ Veloria/Libs/VPIAPManager/VPIAPManager.swift | 48 +++++++++++++---- .../VPIAPManager/VPWaitRestoreModel.swift | 2 + .../JXIAPManager/JXIAPManager.swift | 10 ++-- 9 files changed, 162 insertions(+), 18 deletions(-) diff --git a/Veloria.xcodeproj/project.pbxproj b/Veloria.xcodeproj/project.pbxproj index 4119352..7057276 100644 --- a/Veloria.xcodeproj/project.pbxproj +++ b/Veloria.xcodeproj/project.pbxproj @@ -264,6 +264,12 @@ BFF5B2792DF679720044227A /* VPMoreVideoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B2782DF679720044227A /* VPMoreVideoViewController.swift */; }; BFF5B4AF2DF6B6630044227A /* VPMutualCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B4AE2DF6B6630044227A /* VPMutualCollectionView.swift */; }; BFF5B6E52DF7C8590044227A /* VPEmptyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFF5B6E42DF7C8580044227A /* VPEmptyView.swift */; }; + BFFFE7302E45E7F5001E92D2 /* FirebaseAuth in Frameworks */ = {isa = PBXBuildFile; productRef = BFFFE72F2E45E7F5001E92D2 /* FirebaseAuth */; }; + BFFFE7322E45E7F5001E92D2 /* FirebaseCore in Frameworks */ = {isa = PBXBuildFile; productRef = BFFFE7312E45E7F5001E92D2 /* FirebaseCore */; }; + BFFFE7342E45E7F5001E92D2 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = BFFFE7332E45E7F5001E92D2 /* FirebaseFirestore */; }; + BFFFE7362E45E7F5001E92D2 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = BFFFE7352E45E7F5001E92D2 /* FirebaseMessaging */; }; + BFFFE7382E45ED9D001E92D2 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = BFFFE7372E45ED9D001E92D2 /* FirebaseMessaging */; }; + BFFFE73A2E45ED9D001E92D2 /* FirebasePerformance in Frameworks */ = {isa = PBXBuildFile; productRef = BFFFE7392E45ED9D001E92D2 /* FirebasePerformance */; }; F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F57E87E765BF8D72A43DCA /* Pods_Veloria.framework */; }; /* End PBXBuildFile section */ @@ -562,9 +568,15 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + BFFFE73A2E45ED9D001E92D2 /* FirebasePerformance in Frameworks */, + BFFFE7362E45E7F5001E92D2 /* FirebaseMessaging in Frameworks */, F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */, + BFFFE7382E45ED9D001E92D2 /* FirebaseMessaging in Frameworks */, + BFFFE7302E45E7F5001E92D2 /* FirebaseAuth in Frameworks */, BFF5B2442DF050260044227A /* FacebookCore in Frameworks */, BFCCE1262DFBF57B00EDE165 /* FirebaseMessaging in Frameworks */, + BFFFE7322E45E7F5001E92D2 /* FirebaseCore in Frameworks */, + BFFFE7342E45E7F5001E92D2 /* FirebaseFirestore in Frameworks */, BFCCE1242DFBF57B00EDE165 /* FirebaseCore in Frameworks */, BFF5B2462DF050260044227A /* FacebookLogin in Frameworks */, ); @@ -1929,7 +1941,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.2; + MARKETING_VERSION = 1.1.3; PRODUCT_BUNDLE_IDENTIFIER = com.qjwl168.veloria.ios; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1972,7 +1984,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.2; + MARKETING_VERSION = 1.1.3; PRODUCT_BUNDLE_IDENTIFIER = com.qjwl168.veloria.ios; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2232,6 +2244,36 @@ package = BFF5B2422DF050260044227A /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */; productName = FacebookLogin; }; + BFFFE72F2E45E7F5001E92D2 /* FirebaseAuth */ = { + isa = XCSwiftPackageProductDependency; + package = BFCCE1222DFBF57B00EDE165 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseAuth; + }; + BFFFE7312E45E7F5001E92D2 /* FirebaseCore */ = { + isa = XCSwiftPackageProductDependency; + package = BFCCE1222DFBF57B00EDE165 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseCore; + }; + BFFFE7332E45E7F5001E92D2 /* FirebaseFirestore */ = { + isa = XCSwiftPackageProductDependency; + package = BFCCE1222DFBF57B00EDE165 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseFirestore; + }; + BFFFE7352E45E7F5001E92D2 /* FirebaseMessaging */ = { + isa = XCSwiftPackageProductDependency; + package = BFCCE1222DFBF57B00EDE165 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseMessaging; + }; + BFFFE7372E45ED9D001E92D2 /* FirebaseMessaging */ = { + isa = XCSwiftPackageProductDependency; + package = BFCCE1222DFBF57B00EDE165 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebaseMessaging; + }; + BFFFE7392E45ED9D001E92D2 /* FirebasePerformance */ = { + isa = XCSwiftPackageProductDependency; + package = BFCCE1222DFBF57B00EDE165 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */; + productName = FirebasePerformance; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = 1B056DEC2DDABE2B007EE38D /* Project object */; diff --git a/Veloria/AppDelegate/SceneDelegate+APNS.swift b/Veloria/AppDelegate/SceneDelegate+APNS.swift index be2d059..d563398 100644 --- a/Veloria/AppDelegate/SceneDelegate+APNS.swift +++ b/Veloria/AppDelegate/SceneDelegate+APNS.swift @@ -8,6 +8,10 @@ import UIKit import FirebaseMessaging import FirebaseCore +import FirebaseFirestore +import FirebaseAuth +import FirebasePerformance + extension AppDelegate { ///是否展示过通知提示 diff --git a/Veloria/Base/Controller/VPTabBarController.swift b/Veloria/Base/Controller/VPTabBarController.swift index dd0b215..2962304 100644 --- a/Veloria/Base/Controller/VPTabBarController.swift +++ b/Veloria/Base/Controller/VPTabBarController.swift @@ -64,6 +64,12 @@ class VPTabBarController: UITabBarController { } VPRewardedAdManager.manager.loadAd() + + VPIAPManager.manager.restore(isLoding: false) { isFinish in + if isFinish { + VPLoginManager.manager.updateUserInfo(completer: nil) + } + } } diff --git a/Veloria/Base/Networking/API/VPStatAPI.swift b/Veloria/Base/Networking/API/VPStatAPI.swift index 036730c..55ab86c 100644 --- a/Veloria/Base/Networking/API/VPStatAPI.swift +++ b/Veloria/Base/Networking/API/VPStatAPI.swift @@ -9,6 +9,13 @@ import UIKit class VPStatAPI: NSObject { + enum ErrorEventKey: String { + case payCallback = "pay_callback" //支付成功,但是后台接口失败 + case payRestore = "pay_restore" //restore 失败 + case payCancel = "pay_cancel" //用户取消支付 + case payError = "pay_error" //支付过程中的其它错误 + } + ///进入APP static func requestEnterApp() { @@ -108,4 +115,51 @@ class VPStatAPI: NSObject { } } + + + static func requestStatError(shortPlayId: String?, videoId: String?, eventKey: ErrorEventKey, errorMsg: String?, otherParamenters: [String : Any]? = nil) { + + var eventName = "" + switch eventKey { + case .payCallback: + eventName = "pay callback failed" + + case .payRestore: + eventName = "pay restore" + + case .payCancel: + eventName = "user pay canceled" + + default: + eventName = "platform pay failed" + } + + var parameters: [String : Any] = [ + "userId" : VPLoginManager.manager.userInfo?.customer_id ?? "", + "event_name" : eventName, + "event_key" : eventKey.rawValue, + "short_play_id" : shortPlayId ?? "0", + "short_play_video_id" : videoId ?? "0" + ] + + if let errorMsg = errorMsg { + parameters["error_msg"] = errorMsg + } + + + if let otherParamenters = otherParamenters { + otherParamenters.forEach { + parameters[$0] = $1 + } + } + + var param = VPNetworkParameters(path: "/event/add") + param.isLoding = false + param.isToast = false + param.parameters = parameters + + VPNetwork.request(parameters: param) { (response: VPNetworkResponse) in + + } + } } diff --git a/Veloria/Base/Networking/API/VPWalletAPI.swift b/Veloria/Base/Networking/API/VPWalletAPI.swift index ce48579..c6179a3 100644 --- a/Veloria/Base/Networking/API/VPWalletAPI.swift +++ b/Veloria/Base/Networking/API/VPWalletAPI.swift @@ -135,7 +135,7 @@ class VPWalletAPI { } ///校验内购 - static func requestVerifyOrder(orderCode: String, payId: String, productId: String, transactionId: String, purchaseToken: String, completer: ((_ model: VPIAPVerifyModel?) -> Void)?) { + static func requestVerifyOrder(orderCode: String, payId: String, productId: String, transactionId: String, purchaseToken: String, completer: ((_ response: VPNetworkResponse?) -> Void)?) { var param = VPNetworkParameters(path: "/applePaid") param.parameters = [ "order_code" : orderCode, @@ -146,7 +146,7 @@ class VPWalletAPI { ] VPNetwork.request(parameters: param) { (response: VPNetworkResponse) in - completer?(response.data) + completer?(response) } } } diff --git a/Veloria/Class/Wallet/Controller/VPStoreViewController.swift b/Veloria/Class/Wallet/Controller/VPStoreViewController.swift index eb5c7d5..9ba370c 100644 --- a/Veloria/Class/Wallet/Controller/VPStoreViewController.swift +++ b/Veloria/Class/Wallet/Controller/VPStoreViewController.swift @@ -75,6 +75,12 @@ class VPStoreViewController: VPViewController { requestData() self.stackView.addArrangedSubview(self.tipView) + + VPIAPManager.manager.restore(isLoding: false) { isFinish in + if isFinish { + VPLoginManager.manager.updateUserInfo(completer: nil) + } + } } override func viewWillAppear(_ animated: Bool) { diff --git a/Veloria/Libs/VPIAPManager/VPIAPManager.swift b/Veloria/Libs/VPIAPManager/VPIAPManager.swift index d800c40..8bb7198 100644 --- a/Veloria/Libs/VPIAPManager/VPIAPManager.swift +++ b/Veloria/Libs/VPIAPManager/VPIAPManager.swift @@ -17,6 +17,9 @@ class VPIAPManager { static let manager = VPIAPManager() + private var shortPlayId: String? + private var videoId: String? + ///成功回调 private var completionHandler: CompletionHandler? @@ -39,7 +42,6 @@ class VPIAPManager { ///开始内购 func start(model: VPPayTemplateItem, shortPlayId: String? = nil, videoId: String? = nil, isDiscount: Bool = false, hudShowView: UIView? = nil, handler: CompletionHandler? = nil) { -// self.iapManager.showCodeRedemption() if let _ = self.waitRestoreModel { VPToast.show(text: "veloria_pay_error_1".localized) @@ -51,6 +53,8 @@ class VPIAPManager { handler?(false) return } + self.shortPlayId = shortPlayId + self.videoId = videoId self.completionHandler = handler self.waitRestoreModel = VPWaitRestoreModel() self.waitRestoreModel?.buyType = model.buy_type @@ -98,6 +102,8 @@ class VPIAPManager { let receipt = waitRestoreModel.receipt, let transactionId = waitRestoreModel.transactionId else { + self.waitRestoreModel = nil + UserDefaults.vp_setObject(nil, forKey: kVPWaitRestoreIAPDefaultsKey) if isLoding { VPToast.show(text: "veloria_pay_error_3".localized) } @@ -107,18 +113,33 @@ class VPIAPManager { if isLoding { VPHUD.show() } - VPWalletAPI.requestVerifyOrder(orderCode: orderCode, payId: payId, productId: productId, transactionId: transactionId, purchaseToken: receipt) { model in + + let verifyData = [ + "order_code" : orderCode, + "pay_setting_id" : payId, + "pkg_name" : kVPAPPBundleIdentifier, + "transaction_id": transactionId, + "purchases_token" : receipt + ] + + let statParamenters: [String : Any] = [ + "type" : isLoding ? "manual" : "auto", + "pay_data" : verifyData.toJsonString() ?? "" + ] + VPStatAPI.requestStatError(shortPlayId: nil, videoId: nil, eventKey: .payRestore, errorMsg: "restore", otherParamenters: statParamenters) + + VPWalletAPI.requestVerifyOrder(orderCode: orderCode, payId: payId, productId: productId, transactionId: transactionId, purchaseToken: receipt) { response in if isLoding { VPHUD.dismiss() } - guard let model = model else { + guard let model = response?.data else { completer?(false) return } let buyType = self.waitRestoreModel?.buyType self.waitRestoreModel = nil - UserDefaults.vp_setObject(self.waitRestoreModel, forKey: kVPWaitRestoreIAPDefaultsKey) + UserDefaults.vp_setObject(nil, forKey: kVPWaitRestoreIAPDefaultsKey) if model.status == "success" { if buyType == .subVip { @@ -155,7 +176,7 @@ class VPIAPManager { //MARK: -------------- JXIAPManagerDelegate -------------- extension VPIAPManager: JXIAPManagerDelegate { - func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String?) { + func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String) { guard let orderCode = self.orderCode, let payId = self.payId else { self.orderCode = nil self.payId = nil @@ -170,20 +191,21 @@ extension VPIAPManager: JXIAPManagerDelegate { UserDefaults.vp_setObject(self.waitRestoreModel, forKey: kVPWaitRestoreIAPDefaultsKey) - VPWalletAPI.requestVerifyOrder(orderCode: orderCode, payId: payId, productId: productId, transactionId: transactionIdentifier ?? "", purchaseToken: receipt) { model in + VPWalletAPI.requestVerifyOrder(orderCode: orderCode, payId: payId, productId: productId, transactionId: transactionIdentifier, purchaseToken: receipt) { response in VPHUD.dismiss() self.orderCode = nil self.payId = nil - guard let model = model else { + guard let model = response?.data else { + VPStatAPI.requestStatError(shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCallback, errorMsg: response?.msg) self.completionHandler?(false) return } let buyType = self.waitRestoreModel?.buyType self.waitRestoreModel = nil - UserDefaults.vp_setObject(self.waitRestoreModel, forKey: kVPWaitRestoreIAPDefaultsKey) + UserDefaults.vp_setObject(nil, forKey: kVPWaitRestoreIAPDefaultsKey) if model.status == "success" { if buyType == .subVip { @@ -196,13 +218,14 @@ extension VPIAPManager: JXIAPManagerDelegate { NotificationCenter.default.post(name: VPIAPManager.buyVipFinishNotification, object: nil) } } else { + VPStatAPI.requestStatError(shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCallback, errorMsg: model.status) self.completionHandler?(false) } } } - func jx_iapPayFailed(productId: String, code: JXIAPManagerCode) { + func jx_iapPayFailed(productId: String, code: JXIAPManagerCode, msg: String?) { self.orderCode = nil self.payId = nil self.waitRestoreModel = nil @@ -214,6 +237,13 @@ extension VPIAPManager: JXIAPManagerDelegate { } else if code == .cancelled { VPToast.show(text: "veloria_pay_error_4".localized) } + + if code == .cancelled { + VPStatAPI.requestStatError(shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCancel, errorMsg: "user cancel") + } else { + VPStatAPI.requestStatError(shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payError, errorMsg: msg) + } + self.completionHandler?(false) } diff --git a/Veloria/Libs/VPIAPManager/VPWaitRestoreModel.swift b/Veloria/Libs/VPIAPManager/VPWaitRestoreModel.swift index ff997c4..2db6d14 100644 --- a/Veloria/Libs/VPIAPManager/VPWaitRestoreModel.swift +++ b/Veloria/Libs/VPIAPManager/VPWaitRestoreModel.swift @@ -31,6 +31,7 @@ class VPWaitRestoreModel: VPModel, NSSecureCoding { coder.encode(productId, forKey: "productId") coder.encode(receipt, forKey: "receipt") coder.encode(buyType?.rawValue, forKey: "buyType") + coder.encode(transactionId, forKey: "transactionId") } required init?(coder: NSCoder) { @@ -39,6 +40,7 @@ class VPWaitRestoreModel: VPModel, NSSecureCoding { payId = coder.decodeObject(of: NSString.self, forKey: "payId") as? String productId = coder.decodeObject(of: NSString.self, forKey: "productId") as? String receipt = coder.decodeObject(of: NSString.self, forKey: "receipt") as? String + transactionId = coder.decodeObject(of: NSString.self, forKey: "transactionId") as? String if let type = coder.decodeObject(of: NSString.self, forKey: "buyType") as? String { buyType = VPWalletAPI.BuyType(rawValue: type) } diff --git a/Veloria/Thirdparty/JXIAPManager/JXIAPManager.swift b/Veloria/Thirdparty/JXIAPManager/JXIAPManager.swift index a8ff67e..551997c 100644 --- a/Veloria/Thirdparty/JXIAPManager/JXIAPManager.swift +++ b/Veloria/Thirdparty/JXIAPManager/JXIAPManager.swift @@ -12,9 +12,9 @@ import StoreKit /// 获取到可购买商品列表 @objc optional func jx_iapPayGotProducts(products: [SKProduct]) /// 购买成功 - @objc optional func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String?) + @objc optional func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String) /// 购买失败 - @objc optional func jx_iapPayFailed(productId: String, code: JXIAPManagerCode) + @objc optional func jx_iapPayFailed(productId: String, code: JXIAPManagerCode, msg: String?) /// 恢复商品(仅限永久有效商品) @objc optional func iapPayRestore(productIds: [String], transactionIds: [String]) // /// 加载 @@ -172,7 +172,7 @@ extension JXIAPManager: SKProductsRequestDelegate { DispatchQueue.main.async { if let productId = self.productId { self.productId = nil - self.delegate?.jx_iapPayFailed?(productId: productId, code: .noProduct) + self.delegate?.jx_iapPayFailed?(productId: productId, code: .noProduct, msg: nil) } } return @@ -251,9 +251,9 @@ extension JXIAPManager { switch error?.code { case SKError.paymentCancelled: - self.delegate?.jx_iapPayFailed?(productId: productId, code: .cancelled) + self.delegate?.jx_iapPayFailed?(productId: productId, code: .cancelled, msg: error?.localizedDescription) default: - self.delegate?.jx_iapPayFailed?(productId: productId, code: .unknown) + self.delegate?.jx_iapPayFailed?(productId: productId, code: .unknown, msg: error?.localizedDescription) } }