diff --git a/AppleParty/AppleParty/AppListView/InAppPurchseView/APUploadIAPListVC.swift b/AppleParty/AppleParty/AppListView/InAppPurchseView/APUploadIAPListVC.swift index 79b805a..788286f 100644 --- a/AppleParty/AppleParty/AppListView/InAppPurchseView/APUploadIAPListVC.swift +++ b/AppleParty/AppleParty/AppListView/InAppPurchseView/APUploadIAPListVC.swift @@ -13,6 +13,7 @@ class APUploadIAPListVC: NSViewController { @IBOutlet weak var enterBtn: NSButton! @IBOutlet weak var preserveCurrentPriceBtn: NSButton! @IBOutlet weak var showApiRateLimitLogsBtn: NSButton! + @IBOutlet weak var submitSubscriptionReviewBtn: NSButton! public var currentApp: App? { didSet { @@ -151,11 +152,17 @@ extension APUploadIAPListVC { // 3、获取所有的内购商品,如果存在的商品就直接修改,如果不存在就创建 let oldIAPs = await ascAPI.fetchInAppPurchasesList(appId: appId) + let submitSubscriptionReview = self.submitSubscriptionReviewBtn.state == .on + // 4、遍历所有要上传的商品 for product in iaps { // 订阅类型与非订单类型不一样的处理逻辑 if product.inAppPurchaseType == .AUTO_RENEWABLE { - await createRenewSubscription(appId: appId, product: product, ascAPI: ascAPI) + await createRenewSubscription( + appId: appId, + product: product, + ascAPI: ascAPI, + submitForReview: submitSubscriptionReview) } else { await createInAppPurchase( appId: appId, product: product, oldIAPs: oldIAPs, ascAPI: ascAPI) @@ -480,7 +487,12 @@ extension APUploadIAPListVC { // MARK: - 上传订阅商品 /// 订阅商品创建或更新 - func createRenewSubscription(appId: String, product: IAPProduct, ascAPI: APASCAPI) async { + func createRenewSubscription( + appId: String, + product: IAPProduct, + ascAPI: APASCAPI, + submitForReview: Bool + ) async { let groupName = product.groupName var currentSubGroup: ASCSubscriptionGroup? // 1、是否有订阅组,没有时要先创建 @@ -580,6 +592,10 @@ extension APUploadIAPListVC { // Apple 后台偶发会在创建/更新后错误显示“元数据缺失”,补一次等价 PATCH 来触发状态刷新。 await refreshSubscriptionMetadata(iapId: iap.id, product: product, ascAPI: ascAPI) + if submitForReview { + await submitSubscriptionForReview(iapId: iap.id, product: product, ascAPI: ascAPI) + } + } else { // 1. 创建新的商品 guard let iapGroupId = currentSubGroup?.id, @@ -611,11 +627,57 @@ extension APUploadIAPListVC { // Apple 后台偶发会在创建/更新后错误显示“元数据缺失”,补一次等价 PATCH 来触发状态刷新。 await refreshSubscriptionMetadata(iapId: iap.id, product: product, ascAPI: ascAPI) + + if submitForReview { + await submitSubscriptionForReview(iapId: iap.id, product: product, ascAPI: ascAPI) + } } ascAPI.addMessage("订阅商品:\(product.productId),\(product.name) ,上传完成!\n") } + /// 提交订阅商品至审核 + func submitSubscriptionForReview(iapId: String, product: IAPProduct, ascAPI: APASCAPI) async { + ascAPI.addMessage("开始提交订阅商品审核:\(product.productId)") + + let maxRetryCount = 12 + for retryIndex in 0.. 0 { + ascAPI.addMessage("订阅商品:\(product.productId) 尚未进入准备提交状态,\(waitSeconds) 秒后重试,剩余 \(remainingCount) 次") + try? await Task.sleep(nanoseconds: waitSeconds * 1_000_000_000) + } + } + + if let submission = await ascAPI.submitSubscriptionForReview(iapId: iapId) { + ascAPI.addMessage("订阅商品:\(product.productId) ,提交审核成功!提交ID:\(submission.id) ✅ ") + if let subscription = await ascAPI.fetchSubscription(iapId: iapId), + let state = subscription.attributes?.state { + ascAPI.addMessage("订阅商品:\(product.productId) 提交后状态:\(state.rawValue)") + } + } else { + ascAPI.addMessage("订阅商品:\(product.productId) ,提交审核失败!请检查商品是否为准备提交状态,或是否需要随 App 版本提交。❌ ") + } + } + /// 更新订阅商品的价格档位 func updateSubscriptionPricePoint(iapId: String, product: IAPProduct, ascAPI: APASCAPI) async { guard let schedule = product.priceSchedules else { diff --git a/AppleParty/AppleParty/AppListView/InAppPurchseView/InAppPurchseView.storyboard b/AppleParty/AppleParty/AppListView/InAppPurchseView/InAppPurchseView.storyboard index b852f64..9335063 100644 --- a/AppleParty/AppleParty/AppListView/InAppPurchseView/InAppPurchseView.storyboard +++ b/AppleParty/AppleParty/AppListView/InAppPurchseView/InAppPurchseView.storyboard @@ -454,11 +454,22 @@ DQ + + @@ -466,6 +477,7 @@ DQ + @@ -490,6 +502,7 @@ DQ + diff --git a/AppleParty/AppleParty/Shared/Network/AppStoreConnectAPI.swift b/AppleParty/AppleParty/Shared/Network/AppStoreConnectAPI.swift index 75b9fa2..292d5c8 100644 --- a/AppleParty/AppleParty/Shared/Network/AppStoreConnectAPI.swift +++ b/AppleParty/AppleParty/Shared/Network/AppStoreConnectAPI.swift @@ -31,6 +31,7 @@ typealias ASCSubscriptionScreenshot = AppStoreConnect_Swift_SDK.SubscriptionAppS typealias ASCSubscriptionGroup = AppStoreConnect_Swift_SDK.SubscriptionGroup typealias ASCSubscriptionGroupLocale = AppStoreConnect_Swift_SDK.SubscriptionGroupLocalization typealias ASCSubscriptionAvailability = AppStoreConnect_Swift_SDK.SubscriptionAvailability +typealias ASCSubscriptionSubmission = AppStoreConnect_Swift_SDK.SubscriptionSubmission class APASCAPI { @@ -844,6 +845,27 @@ class APASCAPI { } } + /// 获取订阅商品详情 + /// - Parameter iapId: 订阅商品 id + /// - Returns: 订阅商品详情 + func fetchSubscription(iapId: String) async -> ASCSubscription? { + let request = APIEndpoint.v1.subscriptions.id(iapId).get(parameters: .init( + fieldsSubscriptions: [.name, .productID, .state] + )) + + do { + guard let provider = provider else { + return nil + } + return try await provider.request(request).data + } catch APIProvider.Error.requestFailure(let statusCode, let errorResponse, _) { + handleRequestFailure(statusCode, errorResponse) + } catch { + handleError("获取订阅商品详情失败: \(error.localizedDescription)") + } + return nil + } + /// 创建订阅商品 /// - Parameters: @@ -1303,6 +1325,41 @@ class APASCAPI { } return nil } + + /// 提交订阅商品至 App Review + /// - Parameter iapId: 订阅商品 id + /// - Returns: 成功时返回对应的提交信息 + func submitSubscriptionForReview(iapId: String) async -> ASCSubscriptionSubmission? { + let body = [ + "data": [ + "type": "subscriptionSubmissions", + "relationships": [ + "subscription": [ + "data": [ + "id": iapId, + "type": "subscriptions" + ] + ] + ] + ] + ] + + do { + guard let provider = provider else { + return nil + } + let json = try JSONSerialization.data(withJSONObject: body, options: .prettyPrinted) + let model = try JSONDecoder().decode(SubscriptionSubmissionCreateRequest.self, from: json) + let request = APIEndpoint.v1.subscriptionSubmissions.post(model) + let data = try await provider.request(request).data + return data + } catch APIProvider.Error.requestFailure(let statusCode, let errorResponse, _) { + handleRequestFailure(statusCode, errorResponse) + } catch { + handleError("提交订阅商品审核失败: \(error.localizedDescription)") + } + return nil + } }