本文首要介绍了 AppleParty v3,一款方便开发者办理 App Store Connect 的东西。文章具体描述了新版别中支撑的功用,如内购产品的批量上传、设置出售规模和价格机制等。作者还说到了 API 的一些限制和未来改进的或许性。若您对游戏职业有需求,如办理许多内购项目和多言语运用,AppleParty 或许是一个不错的挑选。总之,本文为您供给了一个全面了解 AppleParty v3 的机会,以便更好地办理您在 App Store Connect 上的运用。

一、前言

咱们好!咱们又见面啦,咱们在上篇文章《运用 App Store Connect API v2.3 办理 App Store 新定价机制》讲解了关于 App Store 新定价机制 API 的介绍。但其时没有对 API 之间的联系性和联动进行介绍,有接口也不知道怎样串联起来运用。所以本文将具体介绍 App Store Connect API v2.3 如何实现批量装备自定价格和出售规模等。

首要,纠正一下咱们之前文章《App Store 新定价机制 – 2023年最全版》说到 订阅类型价格调整 的影响,其时认为苹果全球均衡价格体系,会影响到主动续期订阅产品!但是仔细看 App Store Connect API 后发现,Apple 不会对你的主动续期订阅产品进行价格调整。

汇率改变和税务调整会如何影响主动续期订阅的价格?

Apple 不会对你的主动续期订阅产品进行价格调整。Apple 或许会针对税务改变和重大汇率变动调整零售价格,但价格调整不涉及主动续期订阅。请留意,因为你的收益和 Apple 的佣金均在扣除增值税(VAT)之后计算,因此 VAT 税率改变会影响你的收益。你能够挑选调整你的订阅价格,以削减税务或外汇改变对你的收益形成影响。

主动续期订阅产品,跟现有 App 和一次性 App 内购买项目的价格相同,不再运用价格等级,并且支撑的价格点是一致的。但是主动续期订阅产品的价格,不能设置主动依据全球均衡价格体系调价! 这个便是差异,下文会具体介绍到~

二、支撑 App Store 新定价机制

在讲解 AppleParty(苹果派)支撑 App Store 新定价机制之前,假如咱们对 AppleParty(苹果派)不太了解,能够通过咱们自己的文章学习,这儿就不展开了。

  • AppleParty 下载
  • 苹果派装置运用教程:开源一款苹果 macOS 东西 – AppleParty(苹果派)
  • 苹果派批量创立内购教程:运用 App Store Connect API 批量创立内购产品

2.1 基本功用和表格模板

运用批量内购产品装备,首要要更新到 v3.0.0 版别,登陆账号后挑选 “我的 App”,然后点击 “上传内购项目”,翻开内购办理内容:

AppleParty(苹果派)v3 支持 App Store 新定价机制 - 批量配置自定价格和销售范围

  • 改写:改写当时 App 的内购产品列表(刚刚上传的产品不会主动改写,所以能够手动改写)
  • 导入表格:通过固定表格的方式,批量创立内购品项
  • 导出表格:导出一切品项的信息 Excel 表
  • 导出品项 ID:导出品项 productID 和内购品项 id 的映射表
  • 下载表格示例:批量创立内购品项的示例 Excel 表格

首次,需求点击 下载表格示例,下载模板表格,用于装备内购信息的信息。

2.2 内购产品:基本信息装备

翻开示例表格,能够看到如下图所示例:

AppleParty(苹果派)v3 支持 App Store 新定价机制 - 批量配置自定价格和销售范围

留意:ApplePartyPricePointsTerritories 这 3 个作业表的姓名不能更改,App 是依据这些姓名来读取对应的内容。

  • Product ID:内购产品的标识,留意不能重复。
  • 参阅姓名:内购产品 ASC 后台显现的姓名,不会对用户显现。但需求留意,每个内购产品的参阅姓名不能相同!
  • 运用内购买类型:内购类型,具体不同类型介绍,拜见 协助 作业表。
  • 审阅截图(可选):内购审阅的截图,填写的是需求上传的图片的姓名,包括后缀,例如 test01.jpgt01.png
  • 审阅补白(可选):内购审阅的补白。
  • zh-Hans | en-US:对应 ASC 后台的 App Store 本地化版别,能够装备多个言语版别,只需求在表格后边,表头增加对应的言语标识。

下面是示例阐明:

Product ID 参阅姓名 运用内购买类型 审阅截图(可选) 审阅补白(可选) zh-Hans zh-Hans en-US en-US
com.iap.01 测验suc1 消耗型 test01.jpg 中文姓名01 中文描述01 英文姓名01 英文描述01

示例表格中运用 zh-Hansen-US,在编辑内购产品的信息时,假如不需求这2种言语,能够删去或更改其它言语。需求留意,表格前面的几列,位置顺序不能更改,也不能删去列数等。上传到苹果 ASC 后台的作用:

AppleParty(苹果派)v3 支持 App Store 新定价机制 - 批量配置自定价格和销售范围

App Store 本地化版别言语代码,能够检查表格的 协助 作业表。例如日本是 ja,在 AppleParty 作业表后边增加2列 ja 的表头,然后就能够装备对应的多言语。

审阅截图的上传,下文会说到,这儿暂时略过。

2.3 内购产品:基准国家和自定价格装备

切换到 PricePoints 作业表,能够看到如下图所示例:

AppleParty(苹果派)v3 支持 App Store 新定价机制 - 批量配置自定价格和销售范围

  • Product ID:用于映射多个作业表的内容,所以能够在 AppleParty 作业表的内购产品信息填写好后,直接复制过来。
  • 基准国家(代码):当时内购产品的基准国家,留意是填写代码。175 个国家和区域的代码,可参阅 苹果各国家区域代码 作业表。
  • 基准国价格:当时内购产品的基准国家对应的价格点,表格中供给了 部分国家和区域价格点 作业表,悉数的国家和区域的价格点,请从苹果 ASC 后台下载。
  • 自定价格国家 | 自定价格:需求自定(固定)价格的国家或区域,假如不填写,则表明以基准国家的价格点,依据苹果的全球均衡价格主动设置价格。

下面是示例阐明:

Product ID 基准国家(代码) 基准国价格 自定价格国家1 自定价格1 自定价格国家2 自定价格2 自定价格国家3 自定价格3 自定价格国家4 自定价格4
com.iap.01 JPN 100
com.iap.02 HKG 10 MAC 1.9 TWN 65
com.iap.03 USA 2.79 KOR 990 CHN 7 LBR 2.19 COL 6500
  • com.iap.01:设置基准国家为 JPN(日本),定价为 100 日元,而没有填写自定价格国家或区域,所以其他 174 个国家或区域,依据基准国家的 100 日元,苹果全球均衡价格体系主动调整对应的区域价格。
  • com.iap.02:设置基准国家为 HKG(我国香港),定价为 10 港元,分别设置了我国澳门和我国台湾 2 个自定价格,其他 172 个国家或区域,依据基准国家的 10 港元,苹果全球均衡价格体系主动调整对应的区域价格。
  • com.iap.03:设置基准国家为 USA(美国),定价为 2.79 美元,分别设置了4个国家或区域的自定价格,其他 170 个国家或区域,依据基准国家的 2.79 美元,苹果全球均衡价格体系主动调整对应的区域价格。

总结:

  • 假如没有自定价格的国家或区域,则只装备基准国家和基准国价格就能够。
  • 假如有自定价格的国家或区域,则在表格右边填写对应的自定价格的国家或区域,不同内购产品能够填写不同的国家和区域,并且填写个数也能够不同。
  • 175 个国家和区域的代码,可参阅 苹果各国家区域代码 作业表。

2.4 内购产品:出售规模装备

切换到 Territories 作业表,能够看到如下图所示例:

AppleParty(苹果派)v3 支持 App Store 新定价机制 - 批量配置自定价格和销售范围

  • Product ID:用于映射多个作业表的内容,所以能够在 AppleParty 作业表的内购产品信息填写好后,直接复制过来。
  • 在一切国家/区域出售(1是,0否):留意,假如此值为 1,则其它项的装备直接忽视,并且为 1 时,包括将来新国家/区域主动供给。假如值为 0,则默认下架状况,然后依据其它项的装备来决定出售规模,见下一项的装备。
  • 将来新国家/区域主动供给(1是,0否):假如字段 在一切国家/区域出售 值为 1,则此字段值固定为 1。不然,此值为 1 表明将来 App Store 增加新国家/区域时主动供给出售,值为 0 表明将来新国家/区域不会主动供给出售。
  • 自定出售国家:假如字段 在一切国家/区域出售 值为 1,则此字段设置无效。不然,填写一个或多个国家或区域时,则表明不会在一切国家/区域出售,只会在填写的国家和区域中上架出售。

下面是示例阐明:

Product ID 在一切国家/区域出售(1是,0否) 将来新国家/区域主动供给(1是,0否) 出售1 出售2 出售3 出售4 出售5
com.iap.01 0 1 TWN HKG MAC
com.iap.02 1 0
com.iap.03 0 0 USA JPN CHN LBR COL
com.iap.04 0 1
com.iap.05 0 0
  • com.bbbap.01:当时只在 TWN(我国台湾)、HKG(我国香港)、MAC(我国澳门) 出售,并且将来新国家/区域主动供给出售。
  • com.bbbap.02:在一切国家/区域出售,并且将来新国家/区域主动供给出售。
  • com.bbbap.03:当时只在 USA(美国)、JPN(日本)、CHN(我国)、LBRCOL 出售,并且将来新国家/区域不供给出售。
  • com.bbbap.04:当时下架状况,直到将来有新国家/区域时主动供给出售。
  • com.bbbap.05:下架。

关于这个出售规模的描述,在导入表格后,会显现对应的出售规模阐明,参阅下一章节内容。

2.5 内购产品:批量上传

点击 “导入表格”,可挑选excel表进行导入,然后会显现导入的品项明细表:

AppleParty(苹果派)v3 支持 App Store 新定价机制 - 批量配置自定价格和销售范围

首要,检查导入的数据,是否正确,包括 出售规模价格机制 等。

然后,在右下角有 上传截图 按钮,点击导入图片。如下图:

AppleParty(苹果派)v3 支持 App Store 新定价机制 - 批量配置自定价格和销售范围

截图是依据表格中填写的姓名,匹配对应的图片文件,所以需求保证截图文件的姓名和后缀一致,不然无法辨认和上传。假如截图为空或错误,产品信息会正常更新,但截图不会更新。

左下角的 保存主动续期订阅者现有定价,便是表明主动订阅产品,现已订阅的用户,假如价格调整的话,是否原有用户保持原订阅价格。如下图,是不保存原定价和保存的不同作用:

AppleParty(苹果派)v3 支持 App Store 新定价机制 - 批量配置自定价格和销售范围

首次点击 提交 后,如未设置 API 密钥,会显现下面的界面:

AppleParty(苹果派)v3 支持 App Store 新定价机制 - 批量配置自定价格和销售范围

首次需求设置,或许点击右下角 设置密钥 从头设置。密钥获取,参阅咱们之前的文章:App Store Connect API 密钥生成

最终,点击 提交,会显现提交的日志输出:

AppleParty(苹果派)v3 支持 App Store 新定价机制 - 批量配置自定价格和销售范围

上传失利时,检查 便是阐明有异常或错误内容,需求自行判别是否正常:

[04-18 10:12:50] 内购现已存在:com.tc.2 ,开端更新信息中...
[04-18 10:12:51] 开端更新价格计划表:com.tc.2,HKG,10
[04-18 10:12:53] 基准国家的内购价格点:HKG,10.1 ,未找到此档位!❌ 
[04-18 10:13:23] 内购产品:com.tc.6 无送审截图或未上传截图~
[04-18 12:22:17] 内购现已存在:com.tc.7 ,开端更新信息中...
[04-18 12:22:17] 无价格计划表:com.tc.7 ,请确认!❌ 

至此,批量内购创立和上传操作完结!✅

2.6 其它问题

  • 订阅产品:不支撑装备订阅时限,现在默认值是一个月
  • 家人共享:现在默认是不敞开
  • 删去产品:防止运营错误操作风险,所以暂时没有供给删去内购产品的功用。下文有脚本,能够主动获取。
  • 临时调价:现在不支撑不同时间段的价格调整,后续看看咱们是否有需求才持续迭代。

别的,近期会增加表格和苹果 ASC 后台产品的价格检查,用于检查装备价格是否正常。

最终,咱们运用过程中,有任何疑问或主张,欢迎在谈论区反应。

三、代码细节和留意点

3.1 价格点

从苹果 ASC 下载的价格点矩阵表,比方我国 customerPrice1,而通过 List all price points for an in-app purchase API 获取到的是 1.0

"attributes": {
    "customerPrice": "1.0", 
    "proceeds": "0.84", 
    "priceTier": "10001"
}, 

所以,咱们的表格上应该是填写 1 仍是 1.0 呢?还有港元 10,API 获取到的是 10.0 等。

答案是,都能够!怎样办到呢?

咱们把价格,统一转换成保存 2 位小数的价格点,来保证价格点一致。

/// 回来保存2位小数的价格格式
/// 因为苹果接口回来的价格或许是 "3","3.0" 或 "3.00"
/// - Parameter price: 原价格
/// - Returns: 保存2位小数的价格字符串
func normalizePrice(price: String) -> String {
    let components = price.split(separator: ".")
    if components.count == 1 {
        return price + ".00"
    } else if components.count == 2 {
        let decimalPart = components[1]
        if decimalPart.count == 1 {
            return "\(components[0]).\(decimalPart)0"
        } else if decimalPart.count >= 2 {
            return "\(components[0]).\(decimalPart.prefix(2))"
        }
    }
    return price
}

当然,眼尖的朋友,或许关注到一个字段 "priceTier": "10001",不是说没有价格等级了吗?怎样还有!!!理论上是没有了,但其实,苹果也是要保存这些价格之间的联系表,所以能够理解 priceTier 为价格点的 id。

那咱们不填写价格,用这个 priceTier 不就好了吗!理想很美好,实际很严酷!

当我调用主动续期订阅的 List All Price Points for a Subscription API 获取到的结果:

"attributes" : {
      "customerPrice" : "1.0",
      "proceeds" : "0.84",
      "proceedsYear2" : "0.84"
},

主动续期订阅的没有 priceTier 字段,所以你能够还有怀疑,咱们在看看 InAppPurchasePricePoint.Attributes 和 SubscriptionPricePoint.Attributes 文档,确实没有!

所以,关于价格点,应该怎样让运营同学定义,主张仍是直接运用价格,简单明了!

3.2 出售规模

苹果供给的更改内购的出售规模接口,只支撑 availableInNewTerritories,也便是是否将来新国家/区域主动供给!假如你需求支撑悉数的一切国家或区域,你只能把一切的国家代码,悉数放到 availableTerritories 数组里!疯了吧!

最终,发现之前的 API Create an In-App Purchase 和 Modify an In-App Purchase 里有一个字段 availableInAllTerritories,这样,假如咱们期望在一切国家/区域出售,设置为 ture 就能够!留意,这儿是包括了将来新国家/区域主动供给。

3.3 删去内购(包括订阅产品)

最终,能够便是咱们会一向调试和测验一个或多个内购产品。然后,咱们又想从头生成一次,想删去之前一切产品,在苹果 ASC 后台一个一个删去也不太实际,所以,仍是写了一个脚本,一键主动删去一切:

#!/usr/bin/env python3
# pip install pyjwt
import jwt
# pip install requests
import requests
import time
import json
def createASCToken(p8KeyPath, kid, iss):
	try:
		header = {
			"alg": "ES256",
			"typ": "JWT",
			"kid": kid
		}
		payload = {
			"iss": iss,
			"aud": "appstoreconnect-v1",
			"iat": int(time.time()),
			"exp": int(round(time.time() + (20.0 * 60.0))) # 20 minutes timestamp
		}
		file = open(p8KeyPath)
		key_data = file.read()
		file.close()
		token = jwt.encode(headers=header, payload=payload, key=key_data, algorithm="ES256")
		return token
	except Exception as e:
		print(e)
		return ""
# ---- TODO: 装备你的参数! ----
p8 = "xxxxxx.p8"
kid = "xxxxxx"
iss = "xxxxxx"
token = createASCToken(p8, kid, iss)
header = {
	"Authorization": f"Bearer {token}"
}
def get(url):
	rs1 = requests.get(url, headers=header)
	print(rs1.status_code)
	print(rs1.text)
	#	data = json.loads(rs1.text)
	#	print(data)
	if rs1.status_code != 200:
		print(url)
def post(url, body):
	rs1 = requests.post(url, headers=header, json=body)
	print(rs1.status_code)
	print(rs1.text)
def patch(url, body):
	rs1 = requests.patch(url, headers=header, json=body)
	print(rs1.status_code)
	print(rs1.text)
def delete(url):
	rs1 = requests.delete(url, headers=header)
	print(rs1.status_code)
	print(rs1.text)
# ---- IAP 删去 ----
# 1. 悉数 app
def apps():
	url = "https://api.appstoreconnect.apple.com/v1/apps" 
	get(url)
#apps()
# 2. 某个 app 信息
def app_versions(app_id):
	url = f'https://api.appstoreconnect.apple.com/v1/apps/{app_id}/appStoreVersions'
	get(url)
# ---- TODO: 填写要清空的 app id ----
app_id = "xxxxxx"
#app_versions(app_id)
# 3. app 内购列表
def app_inAppPurchases_list(app_id):
	# List All In-App Purchases for an App
	url = f'https://api.appstoreconnect.apple.com/v1/apps/{app_id}/inAppPurchasesV2?limit=200' #'?limit=50&offset=1'
	#url = f'https://api.appstoreconnect.apple.com/v1/apps/{app_id}/inAppPurchasesV2?cursor=Mg.ANrqDAc&limit=50'
	return get(url)
## 4. 删去内购产品信息
def app_iap_delete(app_iap_id):
	id = app_iap_id
	#Delete an In-App Purchase
	url = f'https://api.appstoreconnect.apple.com/v2/inAppPurchases/{id}'
	delete(url)
## 5. Delete All IAP
def delete_all_iap(data):
	iaps = data["data"]
	for iap in iaps:
		id = iap["id"]
		print(id)
		app_iap_delete(id)
data = app_inAppPurchases_list(app_id)
delete_all_iap(data)
## 6. 获取一切订阅组
def app_subscriptionGroups(app_id):
	id = app_id
	# List All Subscription Groups for an App
	url = f'https://api.appstoreconnect.apple.com/v1/apps/{id}/subscriptionGroups'
	return get(url)
## 7. 获取订阅组下一切内购产品
def app_subscriptionGroups_subscriptions(app_iap_grop_id):
	id = app_iap_grop_id
	# List All Subscriptions for a Subscription Group
	url = f'https://api.appstoreconnect.apple.com/v1/subscriptionGroups/{id}/subscriptions'
	return get(url)
## 8. 删去订阅产品
def app_iap_subscriptions_delete(app_iap_id):
	id = app_iap_id
	#Delete a Review Screenshot for an In-App Purchase
	url = f'https://api.appstoreconnect.apple.com/v1/subscriptions/{id}'
	delete(url)
## 9. 删去订阅组
def app_iap_subscriptionGroups_delete(app_iap_grop_id):
	id = app_iap_grop_id
	#Delete a Subscription Group
	url = f'https://api.appstoreconnect.apple.com/v1/subscriptionGroups/{id}'
	delete(url)
## 10. Get All Subscription
def all_subscription(groups):
	app_subscriptions = []
	for group in groups.get("data", []):
		app_iap_grop_id = group.get("id", "")
		subscriptions = app_subscriptionGroups_subscriptions(app_iap_grop_id)
		app_subscriptions += subscriptions.get("data", [])	
	return app_subscriptions
## 11. Delete All Subscription
def delete_all_subs(subscriptions):
	for subs in subscriptions:
		app_iap_id = subs.get("id", "")
		print(app_iap_id)
		app_iap_subscriptions_delete(app_iap_id)
## 12. Delete All Subscription Group
def delete_all_groups(groups):
	for group in groups.get("data", []):
		app_iap_grop_id = group.get("id", "")
		print(app_iap_grop_id)
		app_iap_subscriptionGroups_delete(app_iap_grop_id)
groups = app_subscriptionGroups(app_id)
subscriptions = all_subscription(groups)
delete_all_subs(subscriptions)
delete_all_groups(groups)

最终,这个脚本也放到了咱们 GitHub 仓库 37iOS/AppStoreConnectAPI-Demo,后续 API 晋级都会一同更新,咱们能够自行获取。

四、总结和未来

开发过程有许多细节文中没有说到,具体咱们能够阅读源代码 37iOS/AppleParty,或许有遇到什么问题,欢迎谈论区交流。

关于苹果 App Store Connect API 的问题,仍是有许多优化的空间的。比方接口恳求频率过快:

Error code: RATE_LIMIT_EXCEEDED, title: The request rate limit has been reached., detail: Optional("We\'ve received too many requests for this API. Please wait and try again or slow down your request rate.")

还有便是设置自定价格和出售规模,不支撑增量修改!每次必然全量调整,假如有 20 个自定价格的国家或区域,那个自定价格每个恳求 2 个,就 40 个恳求了。假如有 100 个内购产品,便是 4000 次恳求。所以,仍是期望苹果后续能完善 API,支撑更多场景的装备。

AppleParty 要处理的问题是开发者有许多 app 的情况下的办理,比方有多言语、频频更新等,当然首要是对游戏职业的需求,比方内购买项目到达 100+ 个,人工一个一个创立显现无法满意,并且如今 App Store 新价格机制,需求看完 175 个国家和区域,现已不再实际!所以,假如团队没有精力打造一套东西流,AppleParty 也许是不错的挑选!

以上便是 AppleParty v3 更新的简单介绍,咱们能够在 GitHub 37iOS/AppleParty 检查具体的源代码。假如觉得不错,给咱们点个赞!如有疑问或许问题,欢迎留言交流~

最终,Apple Party(苹果派)是一个新生儿,所以或许会存在许多缺点,甚至不能满意一切的场景,这也是咱们开源的上的,期望咱们一同参加进来!期望咱们多担待和理解万岁,等待咱们一同给项目提主张,提代码,一同好卷!

最终的最终,仍是要重提一次,准备好迎候即将在 5 月 9 日推出的增强全球定价机制,2023 年 5 月 9 号还没有挑选根底国家的 App 或 IAP(包括订阅产品),苹果会以美国为基准定价,直接影响:比方我国大陆出售的 6 元档位产品,按 1 美元换算会涨价到 8 元! 所以,现在马上装备吧!防止用户嫌贵!影响销量!

WWDC23 将于北京时间 6 月 6 日举行,让咱们一同等待 Apple 全新的技能晋级吧!咱们也会第一时间进行解读和分享,欢迎关注咱们,了解更多 iOS 和 Apple 的资讯~

参阅引证

  • 运用 App Store Connect API v2.3 办理 App Store 新定价机制 –
  • App Store 新定价机制 – 2023年最全版 –
  • 办理主动续期订阅的定价 – 办理订阅 – App Store Connect
  • 开源一款苹果 macOS 东西 – AppleParty(苹果派) –
  • 运用 App Store Connect API 批量创立内购产品 –
  • 37iOS/AppleParty – Download
  • List all price points for an in-app purchase | Apple Developer Documentation
  • InAppPurchasePricePoint.Attributes | Apple Developer Documentation
  • List All Price Points for a Subscription | Apple Developer Documentation
  • SubscriptionPricePoint.Attributes | Apple Developer Documentation
  • Create an In-App Purchase | Apple Developer Documentation
  • Modify an In-App Purchase | Apple Developer Documentation
  • 37iOS/AppleParty
  • 准备好迎候即将在 5 月 9 日推出的增强全球定价机制 – Apple Developer

注:如若转载,请注明来历。