From 95dc5bb60c13354be0ba16906d59c08490ca6aa4 Mon Sep 17 00:00:00 2001 From: zeng Date: Thu, 7 Aug 2025 18:28:21 +0800 Subject: [PATCH] =?UTF-8?q?1.0.2=E6=8F=90=E5=AE=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BeeReel.xcodeproj/project.pbxproj | 8 +-- .../Class/Base/Network/API/BRStatAPI.swift | 55 ++++++++++++++ .../Class/Base/Network/API/BRStoreAPI.swift | 7 +- .../Delegate/AppDelegate+Thirdparty.swift | 13 ++++ .../Class/Delegate/SceneDelegate+Open.swift | 2 +- BeeReel/Class/Delegate/SceneDelegate.swift | 4 +- BeeReel/Class/Lib/IAP/BRIAP.swift | 72 ++++++++++++++----- .../Class/Lib/IAP/BRWaitRestoreModel.swift | 3 + .../JXIAPManager/JXIAPManager.swift | 8 +-- 9 files changed, 140 insertions(+), 32 deletions(-) diff --git a/BeeReel.xcodeproj/project.pbxproj b/BeeReel.xcodeproj/project.pbxproj index 033fb1e..1dcd1f4 100644 --- a/BeeReel.xcodeproj/project.pbxproj +++ b/BeeReel.xcodeproj/project.pbxproj @@ -2646,7 +2646,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = beereel/beereel.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = 8NNUR9HPV3; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; @@ -2667,7 +2667,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.0.2; PRODUCT_BUNDLE_IDENTIFIER = com.breeltv.beereel; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; @@ -2752,7 +2752,7 @@ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_ENTITLEMENTS = beereel/beereel.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = 8NNUR9HPV3; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; @@ -2773,7 +2773,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.0.1; + MARKETING_VERSION = 1.0.2; PRODUCT_BUNDLE_IDENTIFIER = com.breeltv.beereel; PRODUCT_NAME = "$(TARGET_NAME)"; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; diff --git a/BeeReel/Class/Base/Network/API/BRStatAPI.swift b/BeeReel/Class/Base/Network/API/BRStatAPI.swift index 91ad0e6..db60a1d 100644 --- a/BeeReel/Class/Base/Network/API/BRStatAPI.swift +++ b/BeeReel/Class/Base/Network/API/BRStatAPI.swift @@ -9,6 +9,13 @@ import UIKit class BRStatAPI { + enum ErrorEventKey: String { + case payCallback = "pay_callback" //支付成功,但是后台接口失败 + case payRestore = "pay_restore" //restore 失败 + case payCancel = "pay_cancel" //用户取消支付 + case payError = "pay_error" //支付过程中的其它错误 + } + ///进入APP static func requestEnterApp() { @@ -78,6 +85,54 @@ class BRStatAPI { } } + + + ///统计错误 + 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" : BRLoginManager.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 = BRNetworkParameters(path: "/event/add") + param.isLoding = false + param.isToast = false + param.parameters = parameters + + BRNetwork.request(parameters: param) { (response: BRNetworkResponse) in + + } + } } extension BRStatAPI { diff --git a/BeeReel/Class/Base/Network/API/BRStoreAPI.swift b/BeeReel/Class/Base/Network/API/BRStoreAPI.swift index e4100da..9e9b39f 100644 --- a/BeeReel/Class/Base/Network/API/BRStoreAPI.swift +++ b/BeeReel/Class/Base/Network/API/BRStoreAPI.swift @@ -61,18 +61,19 @@ class BRStoreAPI { } ///校验内购 - static func requestVerifyOrder(orderCode: String, payId: String, productId: String, purchaseToken: String, completer: ((_ model: BRIAPVerifyModel?) -> Void)?) { + static func requestVerifyOrder(orderCode: String, payId: String, productId: String, transactionId: String, purchaseToken: String, completer: ((_ response: BRNetworkResponse) -> Void)?) { var param = BRNetworkParameters(path: "/applePaid") param.parameters = [ "order_code" : orderCode, "pay_setting_id" : payId, "pkg_name" : kBRAPPBundleIdentifier, - "transaction_id" : productId, +// "transaction_id" : productId, + "transaction_id": transactionId, "purchases_token" : purchaseToken ] BRNetwork.request(parameters: param) { (response: BRNetworkResponse) in - completer?(response.data) + completer?(response) } } diff --git a/BeeReel/Class/Delegate/AppDelegate+Thirdparty.swift b/BeeReel/Class/Delegate/AppDelegate+Thirdparty.swift index f719d72..0566141 100644 --- a/BeeReel/Class/Delegate/AppDelegate+Thirdparty.swift +++ b/BeeReel/Class/Delegate/AppDelegate+Thirdparty.swift @@ -32,8 +32,21 @@ extension AppDelegate { extension AppDelegate: AdjustDelegate { func adjustDeferredDeeplinkReceived(_ deeplink: URL?) -> Bool { + brLog(message: "deeplink========\(deeplink?.absoluteString ?? "")") return true } + + func adjustSessionTrackingFailed(_ sessionFailureResponse: ADJSessionFailure?) { + brLog(message: sessionFailureResponse?.message) + } + + func adjustEventTrackingFailed(_ eventFailureResponse: ADJEventFailure?) { + brLog(message: eventFailureResponse?.message) + } + + func adjustSkanUpdated(withConversionData data: [String : String]) { + brLog(message: data) + } } //MARK: MessagingDelegate diff --git a/BeeReel/Class/Delegate/SceneDelegate+Open.swift b/BeeReel/Class/Delegate/SceneDelegate+Open.swift index 1bec292..9fc949f 100644 --- a/BeeReel/Class/Delegate/SceneDelegate+Open.swift +++ b/BeeReel/Class/Delegate/SceneDelegate+Open.swift @@ -31,7 +31,7 @@ extension SceneDelegate { static var allowOpenMessage = true ///是否需要重试 static var isNeedRetry = false - private static var webpageURL: URL? + static var webpageURL: URL? func br_handleOpenAppMessage(webpageURL: URL?) { guard BRNetworkStatusManager.manager.isReachable == true, //有网 diff --git a/BeeReel/Class/Delegate/SceneDelegate.swift b/BeeReel/Class/Delegate/SceneDelegate.swift index 5a0ecff..6a69a7b 100644 --- a/BeeReel/Class/Delegate/SceneDelegate.swift +++ b/BeeReel/Class/Delegate/SceneDelegate.swift @@ -49,8 +49,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func sceneWillEnterForeground(_ scene: UIScene) { BRStatAPI.uploadNoticeStatus() - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - self.br_handleOpenAppMessage(webpageURL: nil) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + self.br_handleOpenAppMessage(webpageURL: SceneDelegate.webpageURL) } } diff --git a/BeeReel/Class/Lib/IAP/BRIAP.swift b/BeeReel/Class/Lib/IAP/BRIAP.swift index a7567e2..53ea240 100644 --- a/BeeReel/Class/Lib/IAP/BRIAP.swift +++ b/BeeReel/Class/Lib/IAP/BRIAP.swift @@ -18,6 +18,9 @@ class BRIAP { ///成功回调 private var completionHandler: CompletionHandler? + private var shortPlayId: String? + private var videoId: String? + private lazy var iapManager: JXIAPManager = { let manager = JXIAPManager() manager.delegate = self @@ -32,7 +35,6 @@ class BRIAP { private var waitRestoreModel: BRWaitRestoreModel? = UserDefaults.br_object(forKey: kBRWaitRestoreIAPDefaultsKey, as: BRWaitRestoreModel.self) - ///开始内购 func start(model: BRPayItem, shortPlayId: String? = nil, videoId: String? = nil, isDiscount: Bool = false, hudShowView: UIView? = nil, handler: CompletionHandler? = nil) { @@ -46,6 +48,8 @@ class BRIAP { handler?(false) return } + self.shortPlayId = shortPlayId + self.videoId = videoId self.completionHandler = handler self.waitRestoreModel = BRWaitRestoreModel() self.waitRestoreModel?.buyType = model.buy_type @@ -59,6 +63,7 @@ class BRIAP { BRHUD.dismiss() self.waitRestoreModel = nil self.completionHandler?(false) + self.clean() return } self.orderCode = orderModel.order_code @@ -78,7 +83,8 @@ class BRIAP { let orderCode = waitRestoreModel.orderCode, let payId = waitRestoreModel.payId, let productId = waitRestoreModel.productId, - let receipt = waitRestoreModel.receipt + let receipt = waitRestoreModel.receipt, + let transactionId = waitRestoreModel.transactionId else { if isLoding { BRToast.show(text: "beereel_pay_error_3".localized) @@ -89,18 +95,33 @@ class BRIAP { if isLoding { BRHUD.show() } - BRStoreAPI.requestVerifyOrder(orderCode: orderCode, payId: payId, productId: productId, purchaseToken: receipt) { model in + + let verifyData = [ + "order_code" : orderCode, + "pay_setting_id" : payId, + "pkg_name" : kBRAPPBundleIdentifier, + "transaction_id": transactionId, + "purchases_token" : receipt + ] + + let statParamenters: [String : Any] = [ + "type" : isLoding ? "manual" : "auto", + "pay_data" : verifyData.toJsonString() ?? "" + ] + BRStatAPI.requestStatError(shortPlayId: nil, videoId: nil, eventKey: .payRestore, errorMsg: "restore", otherParamenters: statParamenters) + + BRStoreAPI.requestVerifyOrder(orderCode: orderCode, payId: payId, productId: productId, transactionId: transactionId, purchaseToken: receipt) { response in if isLoding { BRHUD.dismiss() } - guard let model = model else { + guard let model = response.data else { completer?(false) return } let buyType = self.waitRestoreModel?.buyType self.waitRestoreModel = nil - UserDefaults.br_setObject(self.waitRestoreModel, forKey: kBRWaitRestoreIAPDefaultsKey) + UserDefaults.br_setObject(nil, forKey: kBRWaitRestoreIAPDefaultsKey) if model.status == "success" { if buyType == .subVip { @@ -126,6 +147,14 @@ class BRIAP { guard let templateId = templateId else { return nil } return BRIAP.IAPPrefix + templateId } + + func clean() { + self.orderCode = nil + self.payId = nil + self.shortPlayId = nil + self.videoId = nil + self.completionHandler = nil + } } //MARK: -------------- JXIAPManagerDelegate -------------- @@ -133,32 +162,31 @@ extension BRIAP: JXIAPManagerDelegate { 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 self.waitRestoreModel = nil self.completionHandler?(false) + self.clean() return } self.waitRestoreModel?.productId = productId self.waitRestoreModel?.receipt = receipt + self.waitRestoreModel?.transactionId = transactionIdentifier UserDefaults.br_setObject(self.waitRestoreModel, forKey: kBRWaitRestoreIAPDefaultsKey) - BRStoreAPI.requestVerifyOrder(orderCode: orderCode, payId: payId, productId: productId, purchaseToken: receipt) { model in + BRStoreAPI.requestVerifyOrder(orderCode: orderCode, payId: payId, productId: productId, transactionId: transactionIdentifier ?? "", purchaseToken: receipt) { response in BRHUD.dismiss() - self.orderCode = nil - self.payId = nil - - guard let model = model else { + guard let model = response.data else { + BRStatAPI.requestStatError(shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCallback, errorMsg: response.msg) self.completionHandler?(false) + self.clean() return } let buyType = self.waitRestoreModel?.buyType self.waitRestoreModel = nil - UserDefaults.br_setObject(self.waitRestoreModel, forKey: kBRWaitRestoreIAPDefaultsKey) + UserDefaults.br_setObject(nil, forKey: kBRWaitRestoreIAPDefaultsKey) if model.status == "success" { if buyType == .subVip { @@ -172,17 +200,15 @@ extension BRIAP: JXIAPManagerDelegate { } } else { BRToast.show(text: "Purchase Failed".localized) + BRStatAPI.requestStatError(shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCallback, errorMsg: model.status) self.completionHandler?(false) } + self.clean() } } - func jx_iapPayFailed(productId: String, code: JXIAPManagerCode) { - self.orderCode = nil - self.payId = nil - self.waitRestoreModel = nil - + func jx_iapPayFailed(productId: String, code: JXIAPManagerCode, msg: String?) { BRHUD.dismiss() if code == .noProduct { @@ -190,7 +216,17 @@ extension BRIAP: JXIAPManagerDelegate { } else if code == .cancelled { BRToast.show(text: "beereel_pay_error_4".localized) } + + if code == .cancelled { + BRStatAPI.requestStatError(shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payCancel, errorMsg: "user cancel") + } else { + BRStatAPI.requestStatError(shortPlayId: self.shortPlayId, videoId: self.videoId, eventKey: .payError, errorMsg: msg) + } + self.completionHandler?(false) + + self.waitRestoreModel = nil + self.clean() } diff --git a/BeeReel/Class/Lib/IAP/BRWaitRestoreModel.swift b/BeeReel/Class/Lib/IAP/BRWaitRestoreModel.swift index 8b6c018..b1e8770 100644 --- a/BeeReel/Class/Lib/IAP/BRWaitRestoreModel.swift +++ b/BeeReel/Class/Lib/IAP/BRWaitRestoreModel.swift @@ -14,6 +14,7 @@ class BRWaitRestoreModel: BRModel, NSSecureCoding { var productId: String? var receipt: String? var buyType: BRStoreAPI.BuyType? + var transactionId: String? required init() { } @@ -30,6 +31,7 @@ class BRWaitRestoreModel: BRModel, 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) { @@ -38,6 +40,7 @@ class BRWaitRestoreModel: BRModel, 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 = BRStoreAPI.BuyType(rawValue: type) } diff --git a/BeeReel/Class/Thirdparty/JXIAPManager/JXIAPManager.swift b/BeeReel/Class/Thirdparty/JXIAPManager/JXIAPManager.swift index 0825ca8..8e7b3fb 100644 --- a/BeeReel/Class/Thirdparty/JXIAPManager/JXIAPManager.swift +++ b/BeeReel/Class/Thirdparty/JXIAPManager/JXIAPManager.swift @@ -12,7 +12,7 @@ import StoreKit /// 购买成功 @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]) // /// 加载 @@ -100,7 +100,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 @@ -176,9 +176,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) } }