mcpField
I
implement-in-app-purchases

implement-in-app-purchases

github.com/unity-technologies开发1.2k6.0k 次安装1 天前更新
代码仓库

关于 implement-in-app-purchases

用于使用 Unity Purchasing 包实现应用内购买的 Unity 技能,涵盖新项目和迁移。重点说明 v5 的事件驱动连接流程,以及从待处理到确认的购买步骤。

主要功能

  1. 01扫描项目现状并选择实现路径
  2. 02连接商店并获取商品与购买记录
  3. 03处理购买确认、恢复和权益检查
  4. 04涵盖收据验证及平台相关细节
  5. 05提供从其他购买系统迁移的路径

适用场景

  1. 01在没有现有购买功能的项目中添加 Unity IAP
  2. 02从 Unity IAP v4 或原生计费代码迁移
  3. 03实现商品目录、订阅或购买恢复

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/unity-technologies/skills --skill implement-in-app-purchases

安装后在 Claude Code 中输入/implement-in-app-purchases确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
api-notes.md
codeless-catalog.md
convert-adapty.md
convert-essentialkit.md
convert-revenuecat.md
convert-unipay.md
migration-v4-to-v5.md
path-add-iap-to-new-project.md
path-convert-native-google-billing.md
path-convert-native-storekit.md
path-implement-iap-d2c.md
platform-notes.md
pre-check.md

详细介绍

Unity 应用内购买

命名空间:UnityEngine.Purchasing | 安全:UnityEngine.Purchasing.Security 包:com.unity.purchasing

Unity IAP 有独立的初始化流程,通过 UnityIAPServices.StoreController() → store.Connect() 完成。它不需要 UnityServices.InitializeAsync(),但如果项目使用了其他 UGS 服务,两者可以共存。如果项目中包含 Analytics 并调用了 InitializeAsync(),IAP 会自动发送交易事件。

开始之前

请务必先阅读 references/pre-check.md。 该文件会扫描项目中的第三方 IAP 包、原生 Google Billing 和现有 Unity IAP 版本,然后引导至正确的处理路径。在确定处理路径之前,请勿阅读任何其他参考文件或进行任何更改。

详细参考资料

按需阅读参考文件——仅在需要特定 API 签名、平台扩展详情或迁移映射时阅读。

初始化流程

  1. 通过 UnityIAPServices.StoreController() 获取 StoreController(或通过 DefaultStore()、DefaultProduct()、DefaultPurchase() 获取单项服务)
  2. 调用 Connect() 之前订阅所有必需事件(见下文“必需的事件订阅”)
  3. 使用 await store.Connect() 连接到平台商店
  4. 在 OnStoreConnected 中调用 store.FetchProducts(List<ProductDefinition>) 加载目录
  5. 在 OnProductsFetched 后,商品即可用于展示和购买

使用 Awake() 进行初始化,确保在其他 Start() 方法运行前 IAP 已就绪。

商品类型:ProductType.Consumable、ProductType.NonConsumable、ProductType.Subscription。

获取商品

将商品定义为 List<ProductDefinition> 并传入 store.FetchProducts()。如果 Apple Store 和 Google Store 中的商品 ID 不同,请使用 StoreSpecificIds。对于复杂的商品目录,请使用 CatalogProvider 管理商品集和商店特定 ID。

方法行为
GetProducts()返回缓存的商品列表(同步;如果未调用 FetchProducts,则数据可能过时)
FetchProducts()向商店查询最新价格和可用情况,并更新缓存
GetProductById(id)按 ID 返回单个缓存商品

这些方法不可互换。依赖 GetProducts() 之前,请务必先调用 FetchProducts()。

两步购买流程

IAP v5 使用强制性的两步流程:待处理 → 确认。

  1. store.PurchaseProduct(product) — 启动平台购买对话框
  2. 触发 OnPurchasePending — 收到一个 PendingOrder
  3. 验证收据,并向玩家发放内容
  4. store.ConfirmPurchase(pendingOrder) — 完成交易
  5. 触发 OnPurchaseConfirmed — 收到 Order 基类;通过模式匹配区分 ConfirmedOrder(成功)和 FailedOrder(确认失败)

发放内容后,必须调用 ConfirmPurchase(pendingOrder)。 为防止购买丢失,未确认的购买会在下次启动应用时重新传递。

去重: 同一笔购买的 OnPurchasePending 可能触发多次(例如,应用在确认前重启)。请务必检查内容是否已发放。

消耗品: FetchPurchases 不会返回已确认的消耗品购买。请自行跟踪消耗品的发放情况(例如,使用 Cloud Save 或 Economy)。

延期购买: 对于“询问购买”(iOS)和 Google Play 延期购买,会触发 OnPurchaseDeferred。请勿发放内容——等待购买获批后触发 OnPurchasePending。

恢复交易

store.RestoreTransactions(callback) 会重新传递非消耗品和订阅购买。每笔恢复的购买都会触发 OnPurchasePending。

为符合 Apple App Store 的要求,iOS 上必须添加“恢复购买”按钮。

无法通过 RestoreTransactions 恢复 Apple 非自动续订订阅。请在服务器端跟踪这些订阅。

收据验证

平台方式
Google Play使用 GooglePlayTangle.Data() 的 CrossPlatformValidator — 支持本地验证
Apple(StoreKit 2)本地验证为空操作。请使用 order.Info.Apple?.jwsRepresentation 进行服务器端验证

在 Unity Editor 中,通过 Services > In-App Purchasing > Receipt Validation Obfuscator 生成混淆数据。

权益检查

当你没有 Order,但想了解特定商品的状态时使用(替代 v4 的 product.hasReceipt)。如果已有 Order,请改为检查其类型:PendingOrder 对应 EntitledUntilConsumed(消耗品)或 EntitledButNotFinished(非消耗品/订阅),ConfirmedOrder 对应 FullyEntitled。

调用 store.CheckEntitlement(product) 并处理 store.OnCheckEntitlement。检查 entitlement.Status == EntitlementStatus.FullyEntitled。

EntitlementStatus 的值:FullyEntitled、EntitledUntilConsumed、EntitledButNotFinished、NotEntitled、Unknown。

获取现有购买

store.FetchPurchases() 会从商店获取所有当前购买记录,适用于应用启动时调用。

方法行为
GetPurchases()返回缓存的购买列表
FetchPurchases()向商店查询当前购买记录,并覆盖缓存列表

每次调用 FetchPurchases() 都会替换整个缓存列表。只会重新获取非消耗品和订阅——已确认的消耗品不会返回(见上文“两步购买流程”)。

订阅信息

订阅信息位于 IPurchasedProductInfo 上,通过 order.Info.PurchasedProductInfo 访问——不在 CartItem 上(CartItem 只有 Product 和 Quantity)。

IsSubscribed() 返回的是 Result 枚举(True/False/Unsupported),不是 bool。使用 == Result.True 进行空值安全比较。

必需的事件订阅

始终同时订阅成功和失败事件。 未订阅失败事件会产生运行时警告。

调用成功事件失败事件(必需)
FetchProducts()OnProductsFetchedOnProductsFetchFailed
FetchPurchases()OnPurchasesFetchedOnPurchasesFetchFailed
Connect()OnStoreConnectedOnStoreDisconnected
PurchaseProduct()OnPurchasePendingOnPurchaseFailed
CheckEntitlement()OnCheckEntitlement—

始终订阅 OnPurchaseDeferred——Ask-to-Buy(iOS)和 Google Play 延迟购买都会触发此事件。未订阅会导致延迟购买被静默丢弃。

在调用 Connect() 之前订阅事件——上一会话中的待处理购买可能会立即触发事件。

失败描述属性名称

这些属性名称不可互换——使用错误的名称会导致 CS1061:

类型字段属性错误写法
StoreConnectionFailureDescription.message.Message.reason
ProductFetchFailed—.FailureReason、.FailedFetchProducts.Message
FailedOrder—.FailureReason、.Details—
PurchasesFetchFailureDescription.message、.failureReason.Message、.FailureReason—

验证

使用此包编写代码后:

  1. 验证项目能否无错误地编译。
  2. 确认所有 API 调用都符合 api-notes.md 中的 v5 签名——不要使用 v4 旧版模式(IStoreListener、UnityPurchasing.Initialize、ConfigurationBuilder)。
  3. 检查 api-notes.md 中的“防止幻觉:常见 v5 错误”表格——不要使用 OnStoreConnectionFailed(应使用 OnStoreDisconnected),不要向 FetchProducts/FetchPurchases 传递回调(应使用事件),不要使用 product.receipt(应使用 order.Info.Receipt)。
  4. 检查是否在调用 Connect() 之前订阅了所有必需事件(参见上方的“必需的事件订阅”表格)。
  5. 验证两步购买流程:OnPurchasePending → 授予内容 → ConfirmPurchase(pendingOrder)。
  6. 确认每个异步操作都订阅了成功和失败事件(OnProductsFetched/OnProductsFetchFailed、OnStoreConnected/OnStoreDisconnected 等)。
  7. 如果处理订阅,验证 IsSubscribed() 是通过 == Result.True 比较,而不是转换为 bool。
  8. 如果同一项目中同时存在更新后的文件和旧版文件,请使用唯一命名空间(例如添加 .Updated 后缀),以避免 CS0101/CS0111 编译错误。
  9. 如果项目订阅了 OnAuthAccountChanged(v5.4+):验证处理程序会从头重新获取产品和购买记录——Unity IAP 会在触发此事件前清除这两项缓存。不要在处理程序中读取 GetProducts() 或 GetPurchases()。

评论

支持 Markdown