术→技巧, 研发

App Store 应用内购买(IAP)完全指南

钱魏Way · · 5 次浏览

App Store 应用内购买(In-App Purchase,简称 IAP)是苹果为 iOS、macOS、tvOS 等平台上的应用提供的一套标准化的虚拟商品与数字服务交易系统。它允许开发者在其应用中安全地销售数字内容、订阅服务、高级功能等,并由苹果处理支付、分发和部分客户服务。对于在 App Store 上分发且涉及虚拟商品或数字服务交易的应用,使用 IAP 通常是强制要求。

核心概念

IAP 商品类型

IAP 商品并非简单的支付金额,而是需要在 App Store Connect 后台预先创建并经过审核的“商品”。主要分为四种类型:

类型 描述 典型场景 购买次数 跨设备同步 恢复机制
消耗型 可使用多次,使用后失效,需再次购买。 游戏金币、一次性道具、虚拟货币。 多次 不会 不支持
非消耗型 一次购买,永久有效,不会过期或消耗。 电子书、游戏关卡、永久解锁的功能。 一次 系统同步 系统恢复
自动续期订阅 在固定周期内提供动态内容,到期自动续费,直至用户取消。 流媒体会员(如 Apple Music)、云服务月费。 多次(周期内) 系统同步 系统恢复
非续期订阅 提供有时限的服务或静态内容,不会自动续费。 为期一年的杂志存档访问权、固定期限的会员。 多次 App 自己同步 App 自己处理

关键点

  • “订阅”类商品(尤其是自动续期订阅)是苹果主推的模式,订阅超过一年后,苹果分成会从标准的30%降至15%。
  • 选择商品类型需符合业务本质。例如,有时限的会员服务应使用“非续期订阅”,而非通过消耗型货币间接购买,否则可能审核被拒。
  • 非消耗型商品必须在应用中提供“恢复购买”功能。

订阅模式详解

订阅是增加用户粘性和稳定收入的重要模式。

  • 订阅群组:订阅商品必须归属于一个群组。同一群组内,用户一次只能拥有一个活跃订阅(例如,不能同时订阅“标准会员”和“高级会员”)。
  • 订阅等级:同一群组内可设置不同等级(如黄金、铂金、钻石会员),代表不同的服务内容。
    • 升级:立即生效,用户会获得原订阅剩余价值的按比例退款。
    • 降级:当前订阅周期保持不变,在下一个续订日期生效。
    • 跨级切换:切换到同等级但不同周期(如月付切年付)的订阅,新订阅在下一个续订日期生效。

促销与优惠

为吸引和留存用户,苹果提供了多种促销工具。

  • 推介促销:主要面向新订阅用户
    • 类型:免费试用、随用随付折扣、提前支付折扣。
    • 限制:每个订阅群组,每位用户(Apple ID)只能享受一次
    • 服务端验证:通过收据中的 is_trial_period(免费试用)和 is_in_intro_offer_period(折扣价)字段判断。
  • 订阅优惠:面向现有或已流失的订阅用户,用于提升留存或赢回用户。

  • 可控性:开发者可控制优惠对象、数量、时间。
  • 技术实现:需要服务端使用从 App Store Connect 生成的密钥,对包含 productIdentifier、offerIdentifier、nonce、timestamp 等参数的字符串进行 ECDSA 签名,客户端使用该签名发起购买。

App Store 推广

从 iOS 11 开始,开发者可以在 App Store 的应用详情页直接推广特定的 IAP 商品。

  • 用户路径
    • 用户已安装应用:点击推广位直接跳转应用,并通过 paymentQueue:shouldAddStorePayment:forProduct: 回调通知应用。
    • 用户未安装应用:点击后先下载应用,安装后通过推送通知或首次启动时的回调通知应用。
  • 重要性
    • 流量占位:在搜索结果中占据有利位置,降低竞品曝光。
    • 转化提升:结合免费试用等推介促销,直接吸引潜在付费用户。
  • 开发要求:实现上述回调方法,并返回 NO 以接管购买流程;商品需单独提交审核。

开发实现与架构

基本原理与流程

IAP 的核心流程是:应用内发起购买 -> App Store 处理支付并生成收据 -> 应用/服务端验证收据 -> 交付商品。

核心 API (StoreKit)

  • SKPaymentQueue:支付队列,是 IAP 的核心单例对象。
    • 在应用启动时(如 AppDelegate 的 didFinishLaunching)设置其委托:[[SKPaymentQueue defaultQueue] addTransactionObserver:self]。
    • 发起购买前检查:[SKPaymentQueue canMakePayments]。
  • SKPaymentTransactionObserver:交易状态观察者协议。必须实现 paymentQueue:updatedTransactions: 方法来处理交易状态变化(purchasing, purchased, failed, restored, deferred)。
  • 关键实践
    • 收到 purchased 状态后,不要立即调用 finishTransaction:,必须在确认服务端已成功验证收据并交付商品后调用,以防丢单。
    • 交易可能跨应用生命周期完成(如支付时应用被关闭),因此监听必须持久化。

服务端验证与订单设计

推荐架构:生成订单 -> 支付 -> 完成订单

  • 客户端在发起 IAP 前,先请求服务端创建一笔“待支付”订单,获得订单号。
  • 将订单号通过 SKMutablePayment 的 applicationUsername 属性传递给 StoreKit(但此字段在回调时可能为 nil,需有备用方案)。
  • 支付成功后,客户端将收据和订单号一同发送给服务端。
  • 服务端用收据向 Apple 验证,验证成功后,标记该订单为“已完成”并交付商品。

优点

  • 服务端可动态控制商品售卖(如下架)。
  • 便于追踪和排查丢单问题。
  • 更符合通用支付系统设计。

用户身份映射的挑战与方案

Apple 没有提供将 IAP 交易与开发者自身用户系统可靠绑定的机制。常用解决方案是组合策略:

  • 首选:使用 applicationUsername 传递用户ID或订单号。
  • 备用:在发起购买时,将 productIdentifier 到 userID 的映射关系同时保存在内存和 Keychain 中。
  • 回调时恢复:若 applicationUsername 为 nil,则依次尝试从内存、Keychain 中恢复映射关系。
  • 最终兜底:若无法恢复,可假设购买者为当前登录用户,或提供“订单找回”功能。

订阅服务的特殊处理

  • 唯一标识:首次订阅成功的 original_transaction_id 是用户与 Apple “签约”的唯一标识,服务端应将其与用户绑定。
  • 续费逻辑:与微信/支付宝的“服务端主动扣款”不同,IAP 订阅是 Apple 在到期前自动尝试扣款。扣款成功后,StoreKit 会回调客户端,客户端需上传新收据。
  • 服务端轮询:服务端应在订阅到期前定时用最后一条收据验证,检查 is_in_billing_retry_period 字段判断 Apple 是否仍在尝试扣款。
  • Server-to-Server 通知:强烈建议在 App Store Connect 配置通知 URL,以接收订阅关键事件(如 INITIAL_BUY, CANCEL, DID_RENEW, INTERACTIVE_RENEWAL)的实时 HTTP POST 通知,特别是用于处理用户通过苹果客服退款(CANCEL)的情况。

测试、审核与上线

测试环境

  • 沙盒环境:开发阶段、TestFlight 测试使用的环境。需要在 App Store Connect 中创建“沙箱技术测试员”账号。
  • 生产环境:从 App Store 正式下载的应用使用的环境。
  • 测试订阅:沙盒环境中,自动续期订阅的周期会极大缩短(例如,1年订阅仅对应1小时),且每天最多自动续订6次。
  • 服务端验证注意:服务端验证收据时,若收到状态码 21007,表示此为沙盒收据,应转向沙盒验证地址 (https://sandbox.itunes.apple.com/verifyReceipt)。审核人员的购买也走沙盒。

审核要点

  • 匿名购买:应用必须支持用户在未登录自身账号的情况下进行购买(可关联到设备匿名账号)。
  • 元数据:使用订阅的应用,必须在应用内提供易于访问的《自动续费服务说明》和《会员服务协议》链接。
  • 商品审核同类型商品的首次提交,必须随应用新版本一同提交审核。后续同类型商品可单独提交。
  • 规避审核:严禁在审核时开启 IAP,上线后切换为第三方支付。此行为风险极高,可能导致应用下架或开发者账号被封。

常见问题与“坑”

  • 丢单:因网络中断、应用崩溃导致收据未成功验证。解决方案:持久化未完成交易的信息(存于 Keychain),应用下次启动时继续处理。
  • 重复回调:在 App Store 政策更新时,用户需先同意条款,可能导致先回调 failed,再回调 purchased。服务端需能处理此情况。
  • applicationUsername 丢失:该字段在交易恢复回调时可能为 nil,必须有备用方案(见上文)。
  • 越狱设备:越狱设备可能安装内购破解插件。可在客户端进行越狱检测并禁止内购,但更可靠的是依赖服务端收据验证。
  • 退款:用户可联系 Apple 客服退款。对于非消耗型和订阅商品,收据中会有 cancellation_date 字段;但消耗型商品退款无法感知,会造成坏账。这是 IAP 的固有风险。
  • 价格修改:IAP 商品价格修改无需审核,但生效可能有延迟(数分钟到24小时)。日常运营建议通过创建不同商品ID来实现。

总结

集成 App Store 应用内购买是一个涉及产品、开发、运维的多环节工程。成功的核心在于:

  • 正确设计:根据业务选择正确的 IAP 类型和促销方案。
  • 稳健实现:采用“先订单后支付”的架构,妥善处理用户映射、丢单恢复和订阅续费逻辑。
  • 全面验证:充分利用沙盒环境测试,服务端做好沙盒与生产环境的收据验证兼容。
  • 遵守规则:严格遵循苹果的审核指南,特别是关于匿名购买、元数据和支付方式的规定。

通过精心设计和开发,IAP 不仅能成为应用合规的收入来源,更能通过订阅和促销工具,有效提升用户生命周期价值。

参考资料:

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注