解决元数据丢失问题
This commit is contained in:
parent
1c33b5b991
commit
809679751b
@ -43,9 +43,14 @@ class APUploadIAPListVC: NSViewController {
|
||||
func showUploadView() {
|
||||
// 不能同时 present 出来
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
|
||||
let mainStoryboard = NSStoryboard(name: "InAppPurchseView", bundle: Bundle(for: self.classForCoder))
|
||||
let upVC = mainStoryboard.instantiateController(withIdentifier: "IAPUploadVCID") as? IAPUploadImageVC
|
||||
let screenshot = self.iaps.filter({ $0.reviewScreenshot.count > 0 }).map({ $0.reviewScreenshot })
|
||||
let mainStoryboard = NSStoryboard(
|
||||
name: "InAppPurchseView", bundle: Bundle(for: self.classForCoder))
|
||||
let upVC =
|
||||
mainStoryboard.instantiateController(withIdentifier: "IAPUploadVCID")
|
||||
as? IAPUploadImageVC
|
||||
let screenshot = self.iaps.filter({ $0.reviewScreenshot.count > 0 }).map({
|
||||
$0.reviewScreenshot
|
||||
})
|
||||
// 去重后的图片名
|
||||
let uniquedshot = screenshot.enumerated().filter { (index, value) -> Bool in
|
||||
return screenshot.firstIndex(of: value) == index
|
||||
@ -75,7 +80,6 @@ class APUploadIAPListVC: NSViewController {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
guard let appid = currentApp?.appId else {
|
||||
APHUD.hide(message: "当前 App 的 appleid 为空!", delayTime: 1)
|
||||
return
|
||||
@ -109,7 +113,8 @@ extension APUploadIAPListVC {
|
||||
|
||||
func updateInAppPurchse(iaps: [IAPProduct], appId: String, ascKey: AppStoreConnectKey) {
|
||||
let showApiRateLimit = showApiRateLimitLogsBtn.state.rawValue == 1
|
||||
let ascAPI = APASCAPI.init(issuerID: ascKey.issuerID,
|
||||
let ascAPI = APASCAPI.init(
|
||||
issuerID: ascKey.issuerID,
|
||||
privateKeyID: ascKey.privateKeyID,
|
||||
privateKey: ascKey.privateKey,
|
||||
showApiRateLimit: showApiRateLimit)
|
||||
@ -152,7 +157,8 @@ extension APUploadIAPListVC {
|
||||
if product.inAppPurchaseType == .AUTO_RENEWABLE {
|
||||
await createRenewSubscription(appId: appId, product: product, ascAPI: ascAPI)
|
||||
} else {
|
||||
await createInAppPurchase(appId: appId, product: product, oldIAPs: oldIAPs, ascAPI: ascAPI)
|
||||
await createInAppPurchase(
|
||||
appId: appId, product: product, oldIAPs: oldIAPs, ascAPI: ascAPI)
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,13 +171,15 @@ extension APUploadIAPListVC {
|
||||
// MARK: - 上传内购类型商品
|
||||
|
||||
/// 创建内购商品
|
||||
func createInAppPurchase(appId: String, product: IAPProduct, oldIAPs: [ASCInAppPurchaseV2], ascAPI: APASCAPI) async {
|
||||
func createInAppPurchase(
|
||||
appId: String, product: IAPProduct, oldIAPs: [ASCInAppPurchaseV2], ascAPI: APASCAPI
|
||||
) async {
|
||||
ascAPI.addMessage("开始上传内购商品:\(product.productId),\(product.name) ")
|
||||
// 检查是否已经存在此商品,如果存在就修改信息,如果不存在就创建
|
||||
let iaps = oldIAPs.filter({ $0.attributes?.productID == product.productId })
|
||||
if let iap = iaps.first {
|
||||
ascAPI.addMessage("订阅商品已经存在:\(product.productId) ,跳过更新信息...")
|
||||
return;
|
||||
return
|
||||
|
||||
ascAPI.addMessage("内购已经存在:\(product.productId) ,开始更新信息中...")
|
||||
// 0. 审核备注如果原来有值,而新字段无值,则使用原值
|
||||
@ -180,23 +188,27 @@ extension APUploadIAPListVC {
|
||||
product.reviewNote = note
|
||||
}
|
||||
// 1.修改原商品信息
|
||||
guard let iap = await ascAPI.updateInAppPurchases(iapId: iap.id, product: product) else {
|
||||
guard let iap = await ascAPI.updateInAppPurchases(iapId: iap.id, product: product)
|
||||
else {
|
||||
// 修改失败
|
||||
ascAPI.addMessage("内购已经存在:\(product.productId) ,更新信息失败!❌ ")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 3. 商品本地化语言
|
||||
ascAPI.addMessage("开始更新内购本地化版本:\(product.productId)")
|
||||
let localizations = await ascAPI.fetchInAppPurchasesLocalizations(iapId: iap.id)
|
||||
for localization in product.localizations {
|
||||
|
||||
// 如果已经存在本地化语言,则更新
|
||||
if let locale = localizations.filter({ $0.attributes?.locale == localization.locale }).first {
|
||||
if let locale = localizations.filter({
|
||||
$0.attributes?.locale == localization.locale
|
||||
}).first {
|
||||
// 更新
|
||||
ascAPI.addMessage("内购已存在本地化版本:\(localization.locale),开始更新信息中...")
|
||||
if (await ascAPI.updateInAppPurchasesLocalization(iapLocaleId: locale.id, localization: localization)) != nil {
|
||||
if (await ascAPI.updateInAppPurchasesLocalization(
|
||||
iapLocaleId: locale.id, localization: localization)) != nil
|
||||
{
|
||||
// 本地化语言更新成功
|
||||
ascAPI.addMessage("内购本地化版本:\(localization.locale) ,更新语言成功!✅ ")
|
||||
} else {
|
||||
@ -205,7 +217,8 @@ extension APUploadIAPListVC {
|
||||
}
|
||||
} else {
|
||||
// 创建
|
||||
await createIAPLocalization(iapId: iap.id, localization: localization, product: product, ascAPI: ascAPI)
|
||||
await createIAPLocalization(
|
||||
iapId: iap.id, localization: localization, product: product, ascAPI: ascAPI)
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,10 +239,10 @@ extension APUploadIAPListVC {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// 3. 商品本地化语言
|
||||
for localization in product.localizations {
|
||||
await createIAPLocalization(iapId: iap.id, localization: localization, product: product, ascAPI: ascAPI)
|
||||
await createIAPLocalization(
|
||||
iapId: iap.id, localization: localization, product: product, ascAPI: ascAPI)
|
||||
}
|
||||
|
||||
// 4. 商品截图
|
||||
@ -258,23 +271,37 @@ extension APUploadIAPListVC {
|
||||
ascAPI.addMessage("开始更新价格计划表:\(product.productId),\(baseTerritory),\(baseCustomerPrice) \n")
|
||||
|
||||
let points = await ascAPI.fetchPricePoints(iapId: iapId, territory: [baseTerritory])
|
||||
if let point = points.filter({ $0.attributes?.customerPrice!.normalizePrice() == baseCustomerPrice }).first {
|
||||
if let point = points.filter({
|
||||
$0.attributes?.customerPrice!.normalizePrice() == baseCustomerPrice
|
||||
}).first {
|
||||
var manualPrices: [Any] = []
|
||||
var included: [Any] = []
|
||||
|
||||
ascAPI.addMessage("开始构建基准国家和自定价格:")
|
||||
// base Territory
|
||||
manualPrices.append(["id": "${\(baseTerritory)-\(included.count)}", "type": "inAppPurchasePrices"])
|
||||
included.append(ascAPI.fetchInAppPurchasePriceSchedule(scheduleId: baseTerritory, pricePointId: point.id, iapId: iapId, index: included.count))
|
||||
manualPrices.append([
|
||||
"id": "${\(baseTerritory)-\(included.count)}", "type": "inAppPurchasePrices",
|
||||
])
|
||||
included.append(
|
||||
ascAPI.fetchInAppPurchasePriceSchedule(
|
||||
scheduleId: baseTerritory, pricePointId: point.id, iapId: iapId,
|
||||
index: included.count))
|
||||
|
||||
// customerPrice
|
||||
for pricePoint in schedule.manualPrices {
|
||||
let territory = pricePoint.territory
|
||||
let customerPrice = pricePoint.customerPrice.normalizePrice()
|
||||
let points = await ascAPI.fetchPricePoints(iapId: iapId, territory: [territory])
|
||||
if let point = points.filter({ $0.attributes?.customerPrice!.normalizePrice() == customerPrice }).first {
|
||||
manualPrices.append(["id": "${\(territory)-\(included.count)}", "type": "inAppPurchasePrices"])
|
||||
included.append(ascAPI.fetchInAppPurchasePriceSchedule(scheduleId: territory, pricePointId: point.id, iapId: iapId, index: included.count))
|
||||
if let point = points.filter({
|
||||
$0.attributes?.customerPrice!.normalizePrice() == customerPrice
|
||||
}).first {
|
||||
manualPrices.append([
|
||||
"id": "${\(territory)-\(included.count)}", "type": "inAppPurchasePrices",
|
||||
])
|
||||
included.append(
|
||||
ascAPI.fetchInAppPurchasePriceSchedule(
|
||||
scheduleId: territory, pricePointId: point.id, iapId: iapId,
|
||||
index: included.count))
|
||||
} else {
|
||||
ascAPI.addMessage("自定价格的内购价格点:\(territory),\(customerPrice) ,未找到此档位!❌ ")
|
||||
}
|
||||
@ -282,7 +309,10 @@ extension APUploadIAPListVC {
|
||||
|
||||
ascAPI.saveLogs(log: "内购的基准国家和自定价格:\(manualPrices),\(included)")
|
||||
|
||||
if (await ascAPI.updateInAppPurchasePricePoint(iapId: iapId, baseTerritoryId: baseTerritory, manualPrices: manualPrices, included: included)) != nil {
|
||||
if (await ascAPI.updateInAppPurchasePricePoint(
|
||||
iapId: iapId, baseTerritoryId: baseTerritory, manualPrices: manualPrices,
|
||||
included: included)) != nil
|
||||
{
|
||||
// 价格档位配置成功
|
||||
ascAPI.addMessage("内购价格点:\(baseTerritory),\(baseCustomerPrice) ,更新价格成功!✅ ")
|
||||
} else {
|
||||
@ -295,11 +325,14 @@ extension APUploadIAPListVC {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 创建内购商品本地化信息
|
||||
func createIAPLocalization(iapId: String, localization: IAPLocalization, product: IAPProduct, ascAPI: APASCAPI) async {
|
||||
func createIAPLocalization(
|
||||
iapId: String, localization: IAPLocalization, product: IAPProduct, ascAPI: APASCAPI
|
||||
) async {
|
||||
ascAPI.addMessage("开始更新本地化版本:\(product.productId),\(localization.locale)")
|
||||
if (await ascAPI.createInAppPurchasesLocalization(iapId: iapId, localization: localization)) != nil {
|
||||
if (await ascAPI.createInAppPurchasesLocalization(iapId: iapId, localization: localization))
|
||||
!= nil
|
||||
{
|
||||
// 本地化语言配置成功
|
||||
ascAPI.addMessage("内购本地化版本:\(localization.locale) ,更新语言成功!✅ ")
|
||||
} else {
|
||||
@ -341,7 +374,10 @@ extension APUploadIAPListVC {
|
||||
ascAPI.addMessage("内购商品截图文件错误:\(imgPath) ,文件大小为 0~")
|
||||
return
|
||||
}
|
||||
guard let shot = await ascAPI.createInAppPurchasesScreenshot(iapId: iapId, fileName: uploadFileName, fileSize: imaSize) else {
|
||||
guard
|
||||
let shot = await ascAPI.createInAppPurchasesScreenshot(
|
||||
iapId: iapId, fileName: uploadFileName, fileSize: imaSize)
|
||||
else {
|
||||
// 创建失败
|
||||
ascAPI.addMessage("内购商品:\(product.productId) ,创建送审截图失败!❌ ")
|
||||
return
|
||||
@ -351,7 +387,8 @@ extension APUploadIAPListVC {
|
||||
guard let method = shot.attributes?.uploadOperations?.first?.method,
|
||||
let url = shot.attributes?.uploadOperations?.first?.url,
|
||||
let requestHeaders = shot.attributes?.uploadOperations?.first?.requestHeaders,
|
||||
let baseURL = URL(string: url) else {
|
||||
let baseURL = URL(string: url)
|
||||
else {
|
||||
ascAPI.addMessage("内购商品:\(product.productId) ,创建送审截图失败!苹果参数异常~ ❌ ")
|
||||
return
|
||||
}
|
||||
@ -364,18 +401,23 @@ extension APUploadIAPListVC {
|
||||
|
||||
ascAPI.addMessage("上传新的送审截图:\(uploadFileName)")
|
||||
// 上传图片
|
||||
guard let response = try? await URLSession.shared.upload(for: request, fromFile: imaUrl) else {
|
||||
guard let response = try? await URLSession.shared.upload(for: request, fromFile: imaUrl)
|
||||
else {
|
||||
ascAPI.addMessage("内购商品:\(product.productId) ,创建送审截图失败!上传图片异常~ ❌ ")
|
||||
return
|
||||
}
|
||||
guard let responseCode = (response.1 as? HTTPURLResponse)?.statusCode, responseCode == 200 else {
|
||||
ascAPI.addMessage("内购商品:\(product.productId) ,创建送审截图失败!上传图片异常 \(response.1.description)~ ❌ ")
|
||||
guard let responseCode = (response.1 as? HTTPURLResponse)?.statusCode, responseCode == 200
|
||||
else {
|
||||
ascAPI.addMessage(
|
||||
"内购商品:\(product.productId) ,创建送审截图失败!上传图片异常 \(response.1.description)~ ❌ ")
|
||||
return
|
||||
}
|
||||
|
||||
ascAPI.addMessage("提交新的送审截图:\(uploadFileName)")
|
||||
// 确认图片
|
||||
if ((await ascAPI.updateInAppPurchasesScreenshot(iapShotId: shot.id, fileMD5: fileMD5)) != nil) {
|
||||
if (await ascAPI.updateInAppPurchasesScreenshot(iapShotId: shot.id, fileMD5: fileMD5))
|
||||
!= nil
|
||||
{
|
||||
ascAPI.addMessage("内购商品:\(product.productId) ,送审截图上传成功!✅ ")
|
||||
} else {
|
||||
ascAPI.addMessage("内购商品:\(product.productId) ,送审截图可能上传失败! ")
|
||||
@ -396,11 +438,14 @@ extension APUploadIAPListVC {
|
||||
territories.forEach { territory in
|
||||
allTerritories.append([
|
||||
"type": "territories",
|
||||
"id": territory.id
|
||||
"id": territory.id,
|
||||
])
|
||||
}
|
||||
// 更新全部国家地区
|
||||
if (await ascAPI.updateInAppPurchasesAvailabilityTerritories(iapId: iapId, availableTerritories: allTerritories, availableInNewTerritories: inNew)) != nil {
|
||||
if (await ascAPI.updateInAppPurchasesAvailabilityTerritories(
|
||||
iapId: iapId, availableTerritories: allTerritories,
|
||||
availableInNewTerritories: inNew)) != nil
|
||||
{
|
||||
ascAPI.addMessage("选择:所有国家(地区)销售,\(newTerritory),更新成功!✅ ")
|
||||
} else {
|
||||
ascAPI.addMessage("选择:所有国家(地区)销售,\(newTerritory),更新失败!❌ ")
|
||||
@ -416,19 +461,22 @@ extension APUploadIAPListVC {
|
||||
product.territories.territories?.forEach({ territory in
|
||||
territories.append([
|
||||
"type": "territories",
|
||||
"id": territory.id
|
||||
"id": territory.id,
|
||||
])
|
||||
})
|
||||
|
||||
let customerTerritory = product.territories.territories?.map({ $0.id }).joined(separator: ",") ?? "无"
|
||||
if (await ascAPI.updateInAppPurchasesAvailabilityTerritories(iapId: iapId, availableTerritories: territories, availableInNewTerritories: inNew)) != nil {
|
||||
let customerTerritory =
|
||||
product.territories.territories?.map({ $0.id }).joined(separator: ",") ?? "无"
|
||||
if (await ascAPI.updateInAppPurchasesAvailabilityTerritories(
|
||||
iapId: iapId, availableTerritories: territories, availableInNewTerritories: inNew))
|
||||
!= nil
|
||||
{
|
||||
ascAPI.addMessage("内购商品的销售国家/地区:\(customerTerritory) ,更新成功!✅ ")
|
||||
} else {
|
||||
ascAPI.addMessage("内购商品的销售国家/地区:\(customerTerritory) ,更新失败!❌ ")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - 上传订阅商品
|
||||
|
||||
/// 订阅商品创建或更新
|
||||
@ -447,19 +495,25 @@ extension APUploadIAPListVC {
|
||||
}
|
||||
|
||||
// 创建订阅组
|
||||
if currentSubGroup == nil, let group = await ascAPI.createSubscriptionGroups(appId: appId, groupName: groupName) {
|
||||
if currentSubGroup == nil,
|
||||
let group = await ascAPI.createSubscriptionGroups(appId: appId, groupName: groupName)
|
||||
{
|
||||
currentSubGroup = group
|
||||
subGroups.append(group)
|
||||
|
||||
for localization in product.localizations {
|
||||
let _ = await ascAPI.createSubscriptionGroupLocalizations(iapGroupId: group.id, name: localization.name, locale: localization.locale, customAppName: nil)
|
||||
let _ = await ascAPI.createSubscriptionGroupLocalizations(
|
||||
iapGroupId: group.id, name: localization.name, locale: localization.locale,
|
||||
customAppName: nil)
|
||||
}
|
||||
}
|
||||
|
||||
//订阅组设置国际化
|
||||
if let group = currentSubGroup {
|
||||
if let localization = product.groupLocalization {
|
||||
let _ = await ascAPI.createSubscriptionGroupLocalizations(iapGroupId: group.id, name: localization.name, locale: localization.locale, customAppName: nil)
|
||||
let _ = await ascAPI.createSubscriptionGroupLocalizations(
|
||||
iapGroupId: group.id, name: localization.name, locale: localization.locale,
|
||||
customAppName: nil)
|
||||
}
|
||||
}
|
||||
|
||||
@ -470,15 +524,9 @@ extension APUploadIAPListVC {
|
||||
subscriptions.append(contentsOf: subs)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 3、查看是否存在订阅商品,不存在就创建,存在就更新
|
||||
let subs = subscriptions.filter({ $0.attributes?.productID == product.productId })
|
||||
if let sub = subs.first {
|
||||
///不做更新
|
||||
ascAPI.addMessage("订阅商品已经存在:\(product.productId) ,跳过更新信息...")
|
||||
return;
|
||||
|
||||
ascAPI.addMessage("订阅商品已经存在:\(product.productId) ,开始更新信息中...")
|
||||
// 0. 审核备注如果原来有值,而新字段无值,则使用原值
|
||||
var product = product
|
||||
@ -498,10 +546,14 @@ extension APUploadIAPListVC {
|
||||
// for localization in product.localizations {
|
||||
if let localization = product.subscriptionLocalization {
|
||||
// 如果已经存在本地化语言,则更新
|
||||
if let locale = localizations.filter({ $0.attributes?.locale == localization.locale }).first {
|
||||
if let locale = localizations.filter({
|
||||
$0.attributes?.locale == localization.locale
|
||||
}).first {
|
||||
// 更新
|
||||
ascAPI.addMessage("订阅商品已存在本地化版本:\(localization.locale),开始更新信息中...")
|
||||
if (await ascAPI.updateSubscriptionLocalization(iapLocaleId: locale.id, localization: localization)) != nil {
|
||||
if (await ascAPI.updateSubscriptionLocalization(
|
||||
iapLocaleId: locale.id, localization: localization)) != nil
|
||||
{
|
||||
// 本地化语言更新成功
|
||||
ascAPI.addMessage("订阅商品本地化版本:\(localization.locale) ,更新语言成功!✅ ")
|
||||
} else {
|
||||
@ -510,7 +562,8 @@ extension APUploadIAPListVC {
|
||||
}
|
||||
} else {
|
||||
// 创建
|
||||
await createSubscriptionLocalization(iapId: iap.id, localization: localization, product: product, ascAPI: ascAPI)
|
||||
await createSubscriptionLocalization(
|
||||
iapId: iap.id, localization: localization, product: product, ascAPI: ascAPI)
|
||||
}
|
||||
}
|
||||
|
||||
@ -518,14 +571,20 @@ extension APUploadIAPListVC {
|
||||
await createSubscriptionScreenshot(iapId: iap.id, product: product, ascAPI: ascAPI)
|
||||
|
||||
// 5. 销售国家或地区
|
||||
await updateSubscriptionAvailableTerritories(iapId: iap.id, product: product, ascAPI: ascAPI)
|
||||
await updateSubscriptionAvailableTerritories(
|
||||
iapId: iap.id, product: product, ascAPI: ascAPI)
|
||||
|
||||
// 3. 商品价格档位
|
||||
await updateSubscriptionPricePoint(iapId: iap.id, product: product, ascAPI: ascAPI)
|
||||
|
||||
// Apple 后台偶发会在创建/更新后错误显示“元数据缺失”,补一次等价 PATCH 来触发状态刷新。
|
||||
await refreshSubscriptionMetadata(iapId: iap.id, product: product, ascAPI: ascAPI)
|
||||
|
||||
} else {
|
||||
// 1. 创建新的商品
|
||||
guard let iapGroupId = currentSubGroup?.id, let iap = await ascAPI.createSubscription(iapGroupId: iapGroupId, product: product) else {
|
||||
guard let iapGroupId = currentSubGroup?.id,
|
||||
let iap = await ascAPI.createSubscription(iapGroupId: iapGroupId, product: product)
|
||||
else {
|
||||
// 创建失败
|
||||
ascAPI.addMessage("订阅商品:\(product.productId) ,创建失败!❌ ")
|
||||
return
|
||||
@ -533,28 +592,30 @@ extension APUploadIAPListVC {
|
||||
|
||||
// 2. 商品本地化语言
|
||||
if let localization = product.subscriptionLocalization {
|
||||
await createSubscriptionLocalization(iapId: iap.id, localization: localization, product: product, ascAPI: ascAPI)
|
||||
await createSubscriptionLocalization(
|
||||
iapId: iap.id, localization: localization, product: product, ascAPI: ascAPI)
|
||||
}
|
||||
// for localization in product.localizations {
|
||||
// await createSubscriptionLocalization(iapId: iap.id, localization: localization, product: product, ascAPI: ascAPI)
|
||||
// }
|
||||
|
||||
|
||||
|
||||
// 4. 商品截图
|
||||
await createSubscriptionScreenshot(iapId: iap.id, product: product, ascAPI: ascAPI)
|
||||
|
||||
// 5. 销售国家或地区
|
||||
await updateSubscriptionAvailableTerritories(iapId: iap.id, product: product, ascAPI: ascAPI)
|
||||
await updateSubscriptionAvailableTerritories(
|
||||
iapId: iap.id, product: product, ascAPI: ascAPI)
|
||||
|
||||
// 3. 商品价格档位
|
||||
await updateSubscriptionPricePoint(iapId: iap.id, product: product, ascAPI: ascAPI)
|
||||
|
||||
// Apple 后台偶发会在创建/更新后错误显示“元数据缺失”,补一次等价 PATCH 来触发状态刷新。
|
||||
await refreshSubscriptionMetadata(iapId: iap.id, product: product, ascAPI: ascAPI)
|
||||
}
|
||||
|
||||
ascAPI.addMessage("订阅商品:\(product.productId),\(product.name) ,上传完成!\n")
|
||||
}
|
||||
|
||||
|
||||
/// 更新订阅商品的价格档位
|
||||
func updateSubscriptionPricePoint(iapId: String, product: IAPProduct, ascAPI: APASCAPI) async {
|
||||
guard let schedule = product.priceSchedules else {
|
||||
@ -565,26 +626,37 @@ extension APUploadIAPListVC {
|
||||
let baseTerritory = schedule.baseTerritory
|
||||
let baseCustomerPrice = schedule.baseCustomerPrice.normalizePrice()
|
||||
|
||||
ascAPI.addMessage("开始更新订阅商品价格点,基准国家:\(product.productId),\(baseTerritory),\(baseCustomerPrice) \n")
|
||||
ascAPI.addMessage(
|
||||
"开始更新订阅商品价格点,基准国家:\(product.productId),\(baseTerritory),\(baseCustomerPrice) \n")
|
||||
|
||||
let isPreservePrice = preserveCurrentPriceBtn.state.rawValue == 1
|
||||
ascAPI.addMessage("保留自动续期订阅者现有定价:\(isPreservePrice ? "是" : "否")")
|
||||
|
||||
let points = await ascAPI.fetchSubscriptionPricePoints(iapId: iapId, territory: [baseTerritory])
|
||||
if let point = points.filter({ $0.attributes?.customerPrice!.normalizePrice() == baseCustomerPrice }).first {
|
||||
let points = await ascAPI.fetchSubscriptionPricePoints(
|
||||
iapId: iapId, territory: [baseTerritory])
|
||||
if let point = points.filter({
|
||||
$0.attributes?.customerPrice!.normalizePrice() == baseCustomerPrice
|
||||
}).first {
|
||||
|
||||
ascAPI.addMessage("开始更新自定价格:")
|
||||
// 自定价格的国家或地区, 基准国家也算是自定价格
|
||||
var customerPriceSchedules = schedule.manualPrices
|
||||
customerPriceSchedules.append(IAPPricePoint(territory: baseTerritory, customerPrice: baseCustomerPrice))
|
||||
customerPriceSchedules.append(
|
||||
IAPPricePoint(territory: baseTerritory, customerPrice: baseCustomerPrice))
|
||||
let manualPricesTerritory: [String] = customerPriceSchedules.map({ $0.territory })
|
||||
// 设置自定价格
|
||||
for pricePoint in customerPriceSchedules {
|
||||
let territory = pricePoint.territory
|
||||
let customerPrice = pricePoint.customerPrice.normalizePrice()
|
||||
let points = await ascAPI.fetchSubscriptionPricePoints(iapId: iapId, territory: [territory])
|
||||
if let point = points.filter({ $0.attributes?.customerPrice!.normalizePrice() == customerPrice }).first {
|
||||
if (await ascAPI.updateSubscriptionPricePoint(iapId: iapId, pricePointId: point.id, preserveCurrentPrice: isPreservePrice)) != nil {
|
||||
let points = await ascAPI.fetchSubscriptionPricePoints(
|
||||
iapId: iapId, territory: [territory])
|
||||
if let point = points.filter({
|
||||
$0.attributes?.customerPrice!.normalizePrice() == customerPrice
|
||||
}).first {
|
||||
if (await ascAPI.updateSubscriptionPricePoint(
|
||||
iapId: iapId, pricePointId: point.id, preserveCurrentPrice: isPreservePrice))
|
||||
!= nil
|
||||
{
|
||||
ascAPI.addMessage("自定价格的订阅商品的价格点:\(territory),\(customerPrice) ,更新价格成功!✅ ")
|
||||
} else {
|
||||
ascAPI.addMessage("自定价格的订阅商品的价格点:\(territory),\(customerPrice) ,更新价格失败!❌ ")
|
||||
@ -596,7 +668,8 @@ extension APUploadIAPListVC {
|
||||
|
||||
ascAPI.addMessage("开始更新全球均衡价格:")
|
||||
// 剩余的所有的国家地区的订阅价格点,然后一个一个设置。API不支持全部国家一次配置
|
||||
let allPoints = await ascAPI.fetchSubscriptionPricePointsEqualizations(pointId: point.id, territory: nil)
|
||||
let allPoints = await ascAPI.fetchSubscriptionPricePointsEqualizations(
|
||||
pointId: point.id, territory: nil)
|
||||
for apoint in allPoints {
|
||||
let territory = apoint.relationships?.territory?.data?.id ?? ""
|
||||
// 自定价格的国家跳过
|
||||
@ -604,7 +677,10 @@ extension APUploadIAPListVC {
|
||||
continue
|
||||
}
|
||||
let customerPrice = apoint.attributes?.customerPrice ?? ""
|
||||
if (await ascAPI.updateSubscriptionPricePoint(iapId: iapId, pricePointId: apoint.id, preserveCurrentPrice: isPreservePrice)) != nil {
|
||||
if (await ascAPI.updateSubscriptionPricePoint(
|
||||
iapId: iapId, pricePointId: apoint.id, preserveCurrentPrice: isPreservePrice))
|
||||
!= nil
|
||||
{
|
||||
// 价格档位配置成功
|
||||
ascAPI.addMessage("全球均衡价格的订阅商品的价格点:\(territory),\(customerPrice) ,更新价格成功!✅ ")
|
||||
} else {
|
||||
@ -618,11 +694,14 @@ extension APUploadIAPListVC {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// 更新订阅商品的本地化信息
|
||||
func createSubscriptionLocalization(iapId: String, localization: IAPLocalization, product: IAPProduct, ascAPI: APASCAPI) async {
|
||||
func createSubscriptionLocalization(
|
||||
iapId: String, localization: IAPLocalization, product: IAPProduct, ascAPI: APASCAPI
|
||||
) async {
|
||||
ascAPI.addMessage("开始更新订阅商品本地化版本:\(product.productId),\(localization.locale)")
|
||||
if (await ascAPI.createSubscriptionLocalization(iapId: iapId, localization: localization)) != nil {
|
||||
if (await ascAPI.createSubscriptionLocalization(iapId: iapId, localization: localization))
|
||||
!= nil
|
||||
{
|
||||
// 本地化语言配置成功
|
||||
ascAPI.addMessage("订阅商品本地化版本:\(localization.locale) ,更新语言成功!✅ ")
|
||||
} else {
|
||||
@ -631,6 +710,38 @@ extension APUploadIAPListVC {
|
||||
}
|
||||
}
|
||||
|
||||
/// Apple 后台偶发会缓存订阅元数据状态,补一次无实际变更的更新请求来触发重新校验。
|
||||
func refreshSubscriptionMetadata(iapId: String, product: IAPProduct, ascAPI: APASCAPI) async {
|
||||
ascAPI.addMessage("开始刷新订阅商品元数据状态:\(product.productId)")
|
||||
|
||||
guard (await ascAPI.updateSubscription(iapId: iapId, product: product)) != nil else {
|
||||
ascAPI.addMessage("订阅商品:\(product.productId) ,刷新基础元数据失败!❌ ")
|
||||
return
|
||||
}
|
||||
|
||||
guard let localization = product.subscriptionLocalization else {
|
||||
ascAPI.addMessage("订阅商品:\(product.productId) 无本地化元数据,跳过刷新本地化状态")
|
||||
return
|
||||
}
|
||||
|
||||
let localizations = await ascAPI.fetchSubscriptionLocalizations(iapId: iapId)
|
||||
guard
|
||||
let locale = localizations.first(where: { $0.attributes?.locale == localization.locale }
|
||||
)
|
||||
else {
|
||||
ascAPI.addMessage("订阅商品:\(product.productId) ,未找到本地化 \(localization.locale),跳过本地化刷新")
|
||||
return
|
||||
}
|
||||
|
||||
if (await ascAPI.updateSubscriptionLocalization(
|
||||
iapLocaleId: locale.id, localization: localization)) != nil
|
||||
{
|
||||
ascAPI.addMessage("订阅商品:\(product.productId) ,元数据状态刷新成功!✅ ")
|
||||
} else {
|
||||
ascAPI.addMessage("订阅商品:\(product.productId) ,刷新本地化元数据失败!❌ ")
|
||||
}
|
||||
}
|
||||
|
||||
/// 更新订阅商品的送审截图
|
||||
func createSubscriptionScreenshot(iapId: String, product: IAPProduct, ascAPI: APASCAPI) async {
|
||||
ascAPI.addMessage("开始更新订阅商品的送审截图:\(product.productId),\(product.reviewScreenshot)")
|
||||
@ -664,7 +775,10 @@ extension APUploadIAPListVC {
|
||||
ascAPI.addMessage("订阅商品截图文件错误:\(imgPath) ,文件大小为 0~")
|
||||
return
|
||||
}
|
||||
guard let shot = await ascAPI.createSubscriptionScreenshot(iapId: iapId, fileName: uploadFileName, fileSize: imaSize) else {
|
||||
guard
|
||||
let shot = await ascAPI.createSubscriptionScreenshot(
|
||||
iapId: iapId, fileName: uploadFileName, fileSize: imaSize)
|
||||
else {
|
||||
// 创建失败
|
||||
ascAPI.addMessage("订阅商品:\(product.productId) ,创建送审截图失败!❌ ")
|
||||
return
|
||||
@ -674,7 +788,8 @@ extension APUploadIAPListVC {
|
||||
guard let method = shot.attributes?.uploadOperations?.first?.method,
|
||||
let url = shot.attributes?.uploadOperations?.first?.url,
|
||||
let requestHeaders = shot.attributes?.uploadOperations?.first?.requestHeaders,
|
||||
let baseURL = URL(string: url) else {
|
||||
let baseURL = URL(string: url)
|
||||
else {
|
||||
ascAPI.addMessage("订阅商品:\(product.productId) ,创建送审截图失败!苹果参数异常~ ❌ ")
|
||||
return
|
||||
}
|
||||
@ -687,18 +802,22 @@ extension APUploadIAPListVC {
|
||||
|
||||
ascAPI.addMessage("上传新的送审截图:\(uploadFileName)")
|
||||
// 上传图片
|
||||
guard let response = try? await URLSession.shared.upload(for: request, fromFile: imaUrl) else {
|
||||
guard let response = try? await URLSession.shared.upload(for: request, fromFile: imaUrl)
|
||||
else {
|
||||
ascAPI.addMessage("订阅商品:\(product.productId) ,创建送审截图失败!上传图片异常~ ❌ ")
|
||||
return
|
||||
}
|
||||
guard let responseCode = (response.1 as? HTTPURLResponse)?.statusCode, responseCode == 200 else {
|
||||
ascAPI.addMessage("订阅商品:\(product.productId) ,创建送审截图失败!上传图片异常 \(response.1.description)~ ❌ ")
|
||||
guard let responseCode = (response.1 as? HTTPURLResponse)?.statusCode, responseCode == 200
|
||||
else {
|
||||
ascAPI.addMessage(
|
||||
"订阅商品:\(product.productId) ,创建送审截图失败!上传图片异常 \(response.1.description)~ ❌ ")
|
||||
return
|
||||
}
|
||||
|
||||
ascAPI.addMessage("提交新的送审截图:\(uploadFileName)")
|
||||
// 确认图片
|
||||
if ((await ascAPI.updateSubscriptionScreenshot(iapShotId: shot.id, fileMD5: fileMD5)) != nil) {
|
||||
if (await ascAPI.updateSubscriptionScreenshot(iapShotId: shot.id, fileMD5: fileMD5)) != nil
|
||||
{
|
||||
ascAPI.addMessage("订阅商品:\(product.productId) ,送审截图上传成功!✅ ")
|
||||
} else {
|
||||
ascAPI.addMessage("订阅商品:\(product.productId) ,送审截图可能上传失败! ")
|
||||
@ -706,7 +825,9 @@ extension APUploadIAPListVC {
|
||||
}
|
||||
|
||||
/// 销售国家或地区
|
||||
func updateSubscriptionAvailableTerritories(iapId: String, product: IAPProduct, ascAPI: APASCAPI) async {
|
||||
func updateSubscriptionAvailableTerritories(
|
||||
iapId: String, product: IAPProduct, ascAPI: APASCAPI
|
||||
) async {
|
||||
let inAll = product.territories.availableInAllTerritories
|
||||
let inNew = product.territories.availableInNewTerritories
|
||||
let summary = territoryInfo(product: product)
|
||||
@ -719,11 +840,14 @@ extension APUploadIAPListVC {
|
||||
territories.forEach { territory in
|
||||
allTerritories.append([
|
||||
"type": "territories",
|
||||
"id": territory.id
|
||||
"id": territory.id,
|
||||
])
|
||||
}
|
||||
// 更新全部国家地区
|
||||
if (await ascAPI.updateSubscriptionAvailabilityTerritories(iapId: iapId, availableTerritories: allTerritories, availableInNewTerritories: inNew)) != nil {
|
||||
if (await ascAPI.updateSubscriptionAvailabilityTerritories(
|
||||
iapId: iapId, availableTerritories: allTerritories,
|
||||
availableInNewTerritories: inNew)) != nil
|
||||
{
|
||||
ascAPI.addMessage("选择:所有国家(地区)销售,\(newTerritory),更新成功!✅ ")
|
||||
} else {
|
||||
ascAPI.addMessage("选择:所有国家(地区)销售,\(newTerritory),更新失败!❌ ")
|
||||
@ -739,12 +863,16 @@ extension APUploadIAPListVC {
|
||||
product.territories.territories?.forEach({ territory in
|
||||
territories.append([
|
||||
"type": "territories",
|
||||
"id": territory.id
|
||||
"id": territory.id,
|
||||
])
|
||||
})
|
||||
|
||||
let customerTerritory = product.territories.territories?.map({ $0.id }).joined(separator: ",") ?? "无"
|
||||
if (await ascAPI.updateSubscriptionAvailabilityTerritories(iapId: iapId, availableTerritories: territories, availableInNewTerritories: inNew)) != nil {
|
||||
let customerTerritory =
|
||||
product.territories.territories?.map({ $0.id }).joined(separator: ",") ?? "无"
|
||||
if (await ascAPI.updateSubscriptionAvailabilityTerritories(
|
||||
iapId: iapId, availableTerritories: territories, availableInNewTerritories: inNew))
|
||||
!= nil
|
||||
{
|
||||
ascAPI.addMessage("订阅商品的销售国家/地区:\(customerTerritory) ,更新成功!✅ ")
|
||||
} else {
|
||||
ascAPI.addMessage("订阅商品的销售国家/地区:\(customerTerritory) ,更新失败!❌ ")
|
||||
@ -758,65 +886,91 @@ extension APUploadIAPListVC {
|
||||
func territoryInfo(product: IAPProduct) -> String {
|
||||
let inAll = product.territories.availableInAllTerritories
|
||||
let inNew = product.territories.availableInNewTerritories
|
||||
let customerTerritory = product.territories.territories?.map({ $0.id }).joined(separator: ",") ?? ""
|
||||
let customerTerritory =
|
||||
product.territories.territories?.map({ $0.id }).joined(separator: ",") ?? ""
|
||||
let off = !inAll && !inNew && (product.territories.territories?.isEmpty ?? true)
|
||||
let territory = off ? "下架" : (customerTerritory.isEmpty ? (inAll ? "全部" : "当前下架") : customerTerritory)
|
||||
let stringValue = "在所有国家/地区销售:'\(inAll ? "是" : "否")'\n将来新国家/地区自动提供:'\(inNew ? "是" : "否")'\n指定国家/地区销售:\(territory)"
|
||||
let territory =
|
||||
off ? "下架" : (customerTerritory.isEmpty ? (inAll ? "全部" : "当前下架") : customerTerritory)
|
||||
let stringValue =
|
||||
"在所有国家/地区销售:'\(inAll ? "是" : "否")'\n将来新国家/地区自动提供:'\(inNew ? "是" : "否")'\n指定国家/地区销售:\(territory)"
|
||||
return stringValue
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - NSTableViewDelegate
|
||||
extension APUploadIAPListVC: NSTableViewDelegate, NSTableViewDataSource {
|
||||
func numberOfRows(in tableView: NSTableView) -> Int {
|
||||
return iaps.count
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
|
||||
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int)
|
||||
-> NSView?
|
||||
{
|
||||
let iap = iaps[row]
|
||||
switch tableColumn?.identifier.enumValue() {
|
||||
case ColumnIdetifier.id.cellValue:
|
||||
let cell = tableView.makeView(withIdentifier: ColumnIdetifier.id.cellValue, owner: self) as? NSTableCellView
|
||||
let cell =
|
||||
tableView.makeView(withIdentifier: ColumnIdetifier.id.cellValue, owner: self)
|
||||
as? NSTableCellView
|
||||
cell?.textField?.stringValue = String(row + 1)
|
||||
return cell
|
||||
case ColumnIdetifier.productID.cellValue:
|
||||
let cell = tableView.makeView(withIdentifier: ColumnIdetifier.productID.cellValue, owner: self) as? NSTableCellView
|
||||
let cell =
|
||||
tableView.makeView(withIdentifier: ColumnIdetifier.productID.cellValue, owner: self)
|
||||
as? NSTableCellView
|
||||
cell?.textField?.stringValue = iap.productId
|
||||
return cell
|
||||
case ColumnIdetifier.productName.cellValue:
|
||||
let cell = tableView.makeView(withIdentifier: ColumnIdetifier.productName.cellValue, owner: self) as? NSTableCellView
|
||||
let cell =
|
||||
tableView.makeView(
|
||||
withIdentifier: ColumnIdetifier.productName.cellValue, owner: self)
|
||||
as? NSTableCellView
|
||||
cell?.textField?.stringValue = iap.name
|
||||
return cell
|
||||
case ColumnIdetifier.price.cellValue:
|
||||
let cell = tableView.makeView(withIdentifier: ColumnIdetifier.price.cellValue, owner: self) as? NSTableCellView
|
||||
let cell =
|
||||
tableView.makeView(withIdentifier: ColumnIdetifier.price.cellValue, owner: self)
|
||||
as? NSTableCellView
|
||||
cell?.textField?.stringValue = territoryInfo(product: iap)
|
||||
return cell
|
||||
case ColumnIdetifier.level.cellValue:
|
||||
let cell = tableView.makeView(withIdentifier: ColumnIdetifier.level.cellValue, owner: self) as? NSTableCellView
|
||||
let cell =
|
||||
tableView.makeView(withIdentifier: ColumnIdetifier.level.cellValue, owner: self)
|
||||
as? NSTableCellView
|
||||
let territory = iap.priceSchedules?.baseTerritory ?? "-"
|
||||
let price = iap.priceSchedules?.baseCustomerPrice ?? "-"
|
||||
let customerPrice = iap.priceSchedules?.manualPrices.map({ pp in
|
||||
let customerPrice =
|
||||
iap.priceSchedules?.manualPrices.map({ pp in
|
||||
"{'国家:'\(pp.territory)', '自定价格':'\(pp.customerPrice)'}\n"
|
||||
}).joined() ?? "-"
|
||||
cell?.textField?.stringValue = "基准国家:'\(territory)'\n基准价格:'\(price)'\n\(customerPrice)"
|
||||
return cell
|
||||
case ColumnIdetifier.productPds.cellValue:
|
||||
let cell = tableView.makeView(withIdentifier: ColumnIdetifier.productPds.cellValue, owner: self) as? NSTableCellView
|
||||
let cell =
|
||||
tableView.makeView(
|
||||
withIdentifier: ColumnIdetifier.productPds.cellValue, owner: self)
|
||||
as? NSTableCellView
|
||||
cell?.textField?.stringValue = iap.reviewNote
|
||||
return cell
|
||||
case ColumnIdetifier.state.cellValue:
|
||||
let cell = tableView.makeView(withIdentifier: ColumnIdetifier.state.cellValue, owner: self) as? NSTableCellView
|
||||
let cell =
|
||||
tableView.makeView(withIdentifier: ColumnIdetifier.state.cellValue, owner: self)
|
||||
as? NSTableCellView
|
||||
cell?.textField?.stringValue = iap.inAppPurchaseType.CNValue()
|
||||
return cell
|
||||
case ColumnIdetifier.screenshot.cellValue:
|
||||
let cell = tableView.makeView(withIdentifier: ColumnIdetifier.screenshot.cellValue, owner: self) as? ImageViewCell
|
||||
let cell =
|
||||
tableView.makeView(
|
||||
withIdentifier: ColumnIdetifier.screenshot.cellValue, owner: self)
|
||||
as? ImageViewCell
|
||||
let file_name = iap.reviewScreenshot
|
||||
let imgPath = screenshotPaths[file_name] ?? ""
|
||||
cell?.imgSel.image = NSImage(contentsOfFile: imgPath)
|
||||
return cell
|
||||
case ColumnIdetifier.language.cellValue:
|
||||
let cell = tableView.makeView(withIdentifier: ColumnIdetifier.language.cellValue, owner: self) as? NSTableCellView
|
||||
let cell =
|
||||
tableView.makeView(withIdentifier: ColumnIdetifier.language.cellValue, owner: self)
|
||||
as? NSTableCellView
|
||||
cell?.textField?.stringValue = iap.localizations.map({ lz in
|
||||
"{'locale:'\(lz.locale)', 'title':'\(lz.name)', 'desc':'\(lz.description)'}\n"
|
||||
}).joined()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user