从旧版 AppCoins SDK 升级
本指南介绍如何从旧版 AppCoins iOS SDK 升级到当前版本。新版本与 StoreKit 2 的公开接口保持一致,因此需要重命名若干属性、以 Transaction 取代 Purchase 类型,并完全移除 PurchaseIntent / Purchase.updates 流程。
概览
当前 SDK 版本的主要变更如下:
Purchase重命名为Transaction——Purchase.all、Purchase.unfinished和Purchase.latest现在分别为Transaction.all、Transaction.unfinished和Transaction.latest(for:)。- 移除
PurchaseIntent与Purchase.updates—— 旧的Purchase.updates发出的是需要显式确认的PurchaseIntent对象。购买结果现在直接由product.purchase()以VerificationResult<Transaction>的形式返回。 Product属性重命名 ——sku→id,title→displayName,priceLabel→displayPrice。Product.products(domain:for:)已简化 —— 移除了domain参数,SDK 会自动读取 bundle identifier。- 购买错误改为抛出 —— 请将
.failed(let error)结果情形替换为围绕product.purchase()的do/catch。 transaction.finish()不再抛出异常 —— 请移除try关键字。
破坏性变更一览
| 旧 API | 新 API |
|---|---|
product.sku | product.id |
product.title | product.displayName |
product.priceLabel | product.displayPrice |
product.priceValue | product.displayPrice(已格式化)或 product.price(Decimal) |
Product.products(domain:for:) | Product.products(for:) —— 已移除 domain |
PurchaseResult.failed(let error) | throws AppCoinsSDKError —— 使用 do/catch |
try await purchase.finish() | await transaction.finish() —— 不再抛出异常 |
Purchase.unfinished()(async,throws) | Transaction.unfinished —— AsyncStream,不抛异常 |
Purchase.all()(async,throws) | Transaction.all —— AsyncStream |
Purchase.latest(sku:) | Transaction.latest(for: productID:) |
Purchase.updates(PurchaseIntent 流) | 已移除 —— 改用 product.purchase() 的返回值 |
PurchaseIntent.confirm() | 已移除 |
PurchaseIntent.reject() | 已移除 |
Xcode 配置
请确认您的 Xcode target 已完成以下设置。这些是 SDK 正常运行的必要条件:
-
Keychain Sharing
- 在 Project Navigator(左侧栏)中选择您的工程。
- 在 TARGETS 下选择您的 target。
- 进入 Signing & Capabilities 标签页。
- 点击 + 按钮添加新能力。
- 搜索 Keychain Sharing 并选中。
- 在 Keychain Groups 字段中,将默认值准确替换为
com.aptoide.appcoins-wallet。
-
URL Scheme
- 在 TARGETS 下选择您的 target。
- 进入 Info 标签页。
- 展开 URL Types 部分并点击 +。
- 将 URL Schemes 设置为
$(PRODUCT_BUNDLE_IDENTIFIER).iap,Role 设置为 Editor。
-
MKSellsDigitalGoods
- 在 Info 标签页中滚动到 Custom iOS Target Properties 部分并点击 +。
- 添加键
MKSellsDigitalGoods,并将其值设置为YES(Boolean)。
1. 更新购买流程
变更前:
let result = await product.purchase()
switch result {
case .success(let verificationResult):
switch verificationResult {
case .verified(let purchase):
try await purchase.finish()
case .unverified(let purchase, let error):
print("Unverified: \(error)")
}
case .pending:
break
case .userCancelled:
break
case .failed(let error):
print("Purchase failed: \(error)")
}
变更后:
do {
let result = try await product.purchase()
switch result {
case .success(let verificationResult):
switch verificationResult {
case .verified(let transaction):
await transaction.finish()
case .unverified(let transaction, let error):
print("Unverified: \(error)")
}
case .pending:
break
case .userCancelled:
break
}
} catch let error as AppCoinsSDKError {
print("Purchase failed: \(error)")
}
两处差异是:
product.purchase()现在写作try await product.purchase()——该调用可能抛出异常。try await purchase.finish()现在写作await transaction.finish()——该调用不再抛出异常。
2. 更新未完成交易的处理
变更前:
func processUnfinished() async {
do {
let purchases = try await Purchase.unfinished()
for purchase in purchases {
giveItem(for: purchase.sku)
try await purchase.finish()
}
} catch {
print("Error loading unfinished: \(error)")
}
}
变更后:
func processUnfinished() async {
if await AppcSDK.isAvailable() {
for await verificationResult in Transaction.unfinished {
if case .verified(let transaction) = verificationResult {
giveItem(for: transaction.productID)
await transaction.finish()
}
}
}
}
Transaction.unfinished 是一个 AsyncStream——请使用 for await 遍历。既不需要 try,也不存在需要单独遍历的包装数组。
⚠️
请在每次应用启动时调用此逻辑。在此前会话中已付款的用户,只有在其交易被完成后才能收到商品。购买若未被消耗,将在 24 小时后自动退款。
3. 更新 Transaction.all 与 Transaction.latest
变更前:
let purchases = try await Purchase.all()
let latest = try await Purchase.latest(sku: "gas")
变更后:
// Iterate all transactions
for await verificationResult in Transaction.all {
if case .verified(let transaction) = verificationResult {
// handle transaction
}
}
// Get the latest transaction for a product
if let verificationResult = await Transaction.latest(for: "gas") {
if case .verified(let transaction) = verificationResult {
// handle transaction
}
}
4. 移除 PurchaseIntent 的处理逻辑
旧版 SDK 通过 Purchase.updates 暴露了一个 PurchaseIntent 对象流,需要显式确认或拒绝。请删除所有订阅 Purchase.updates 的代码——没有替代的流。购买结果由 product.purchase() 直接返回。
变更前:
for await intent in Purchase.updates {
if User.isSignedIn {
let result = await intent.confirm()
// handle result
}
}
变更后: 完全删除该订阅逻辑,改在调用 product.purchase() 的位置处理结果:
let result = try await product.purchase()
switch result {
case .success(let verificationResult):
if case .verified(let transaction) = verificationResult {
giveItem(for: transaction.productID)
await transaction.finish()
}
case .pending, .userCancelled:
break
}
如果您此前依赖「等用户完成认证后再确认」的机制,请先保存待购买的商品,待用户登录后再调用 product.purchase()。
5. 错误处理的变化
变更前:
switch result {
case .failed(let error):
switch error {
case .networkError:
showNetworkAlert()
case .purchaseNotAllowed:
showNotAllowedAlert()
default:
showGenericAlert()
}
// ...
}
变更后:
do {
let result = try await product.purchase()
// handle result
} catch let error as AppCoinsSDKError {
switch error {
case .networkError:
showNetworkAlert()
case .purchaseNotAllowed:
showNotAllowedAlert()
case .productUnavailable:
showUnavailableAlert()
case .notEntitled:
showEntitlementAlert()
case .systemError:
showSystemErrorAlert()
case .unknown:
showGenericAlert()
}
}
所有 AppCoinsSDKError 情形均保持不变,改变的只是接收方式——从结果情形改为抛出的异常。