PAYATHON 2026

iPhone in-app content payment process及Apple佣金问题

支付阿杰

明确结论

通常必须使用 IAP。

杂志期号是在 App 内消费的数字内容。只要用户可以在 iPhone App 中购买并解锁这些内容,原则上就需要使用 Apple 的 In-App Purchase(IAP),由 App Store 处理付款并按适用费率收取佣金。

佣金比例并不完全相同,具体取决于开发者计划、订阅期限、所在地区及当前的 App Store 政策。常见比例是 30%,符合特定计划或订阅条件时可能降至 15%。提交审核前,应以最新的《App Store Review Guidelines》和开发者协议为准。

为什么需要使用 IAP

Apple 通常根据商品的性质判断可以使用哪种支付方式:

  • 实体杂志、食品、交通服务等在 App 外消费的商品或服务,可以使用第三方支付。
  • 电子杂志、电子书、视频、会员内容等在 App 内消费的数字内容,通常必须通过 IAP 销售。
  • App 是否免费下载不会改变这一判断。即使下载价格为零,只要 App 内销售数字内容,仍受 IAP 规则约束。

因此,不能只通过 PayPal、Stripe、微信支付或自建信用卡页面,在 App 内直接出售并解锁电子杂志期号。

推荐的商品设计

如果每一期杂志都需要单独购买,可以将每个期号配置为一个非消耗型商品,例如:

com.example.magazine.issue.2026.01
com.example.magazine.issue.2026.02
com.example.magazine.issue.2026.03

非消耗型商品适合永久解锁。用户使用同一 Apple Account 重新安装 App 后,可以通过“恢复购买”重新取得已经购买的内容。

如果杂志按月或按年持续更新,更适合使用自动续期订阅。也可以同时提供两种购买模式:

  • 单期购买:非消耗型 IAP。
  • 月度或年度会员:自动续期订阅。
  • 免费试读:由 App 自行提供,不需要发起支付。

实现流程

1. 创建付费协议和税务信息

在 App Store Connect 中完成付费 App 协议、银行账户和税务资料。即使 App 本身免费,只要包含 IAP,也需要配置接收销售款项所需的信息。

2. 创建商品

在 App Store Connect 中为每个期号或订阅方案创建商品,并设置:

  • Product ID
  • 商品类型
  • 显示名称与描述
  • 价格等级
  • 审核所需的截图和说明

Product ID 投入使用后不宜随意变更。App 中使用的标识必须与 App Store Connect 完全一致。

3. 使用 StoreKit 获取商品并购买

下面是一个简化的 StoreKit 2 示例:

import StoreKit

enum MagazineStoreError: Error {
    case verificationFailed
}

@MainActor
final class MagazineStore: ObservableObject {
    @Published private(set) var products: [Product] = []
    @Published private(set) var purchasedProductIDs: Set<String> = []

    private let productIDs: Set<String> = [
        "com.example.magazine.issue.2026.01",
        "com.example.magazine.issue.2026.02"
    ]

    func loadProducts() async throws {
        products = try await Product.products(for: productIDs)
            .sorted { $0.displayPrice < $1.displayPrice }
    }

    func purchase(_ product: Product) async throws {
        let result = try await product.purchase()

        switch result {
        case .success(let verification):
            let transaction = try verified(verification)
            purchasedProductIDs.insert(transaction.productID)

            // 在此处解锁对应期号
            await transaction.finish()

        case .pending:
            // 交易等待批准,例如需要家长确认
            break

        case .userCancelled:
            break

        @unknown default:
            break
        }
    }

    func refreshEntitlements() async {
        var purchased: Set<String> = []

        for await entitlement in Transaction.currentEntitlements {
            guard case .verified(let transaction) = entitlement else {
                continue
            }

            if transaction.revocationDate == nil {
                purchased.insert(transaction.productID)
            }
        }

        purchasedProductIDs = purchased
    }

    private func verified<T>(
        _ result: VerificationResult<T>
    ) throws -> T {
        switch result {
        case .verified(let value):
            return value
        case .unverified:
            throw MagazineStoreError.verificationFailed
        }
    }
}

实际项目还需要持续监听交易更新,以免付款完成时 App 不在前台,导致内容没有解锁:

func observeTransactions() -> Task<Void, Never> {
    Task.detached {
        for await update in Transaction.updates {
            guard case .verified(let transaction) = update else {
                continue
            }

            // 更新本地权限,必要时同步到服务器
            await transaction.finish()
        }
    }
}

4. 提供恢复购买入口

对于非消耗型商品和订阅,应允许用户恢复购买。StoreKit 2 通常会自动同步交易,也可以提供明确的恢复按钮:

func restorePurchases() async throws {
    try await AppStore.sync()
    await refreshEntitlements()
}

恢复购买不能要求用户再次付款,也不能只依靠本地 UserDefaults 判断购买状态。

5. 验证交易并交付内容

简单应用可以使用 StoreKit 2 的本地签名验证结果。如果杂志文件存储在自己的服务器上,建议同时进行服务端验证,由服务器根据有效交易发放下载权限。

基本流程如下:

用户选择期号
    ↓
StoreKit 发起购买
    ↓
验证交易
    ↓
服务器登记用户权益
    ↓
允许下载或阅读该期杂志
    ↓
调用 transaction.finish()

不要在交易验证完成前直接解锁内容,也不要仅凭客户端传来的 Product ID 发放资源。

能否绕过 Apple 佣金

一般不能通过在 App 内嵌入网页支付来规避 IAP。对于数字杂志,这种做法可能导致审核被拒。

某些“阅读器”类 App 可以让用户登录,访问已经通过其他渠道购买的内容。在部分地区或符合特定资格的情况下,也可能允许提供外部购买链接。不过,相关规则涉及应用类型、地区、授权资格、链接文案和跳转方式,而且可能随政策或监管要求变化,不能据此认为所有杂志 App 都能自由接入第三方支付。

如果采用这种模式,需要注意:

  • App 可以让已有订阅用户登录阅读,并不代表一定可以在 App 内宣传外部价格。
  • 能否跳转到外部购买页面,需要核对目标地区的现行规则。
  • 外部购买与 IAP 的展示方式可能受到限制。
  • 不同 App Store 地区可能需要采用不同的实现。
  • 未经确认,不应使用 WebView 隐藏第三方数字内容支付流程。

佣金如何计算

Apple 通常会从 IAP 销售收入中扣除适用佣金,再向开发者结算。实际到账金额还可能受到税费、币种和当地法规影响。

假设某期杂志的用户支付价格为 P,佣金率为 r,暂不考虑税费和其他调整,开发者的税前结算金额可以近似表示为:

开发者结算金额 ≈ P × (1 - r)

这只是用于预算的简化模型。不能直接将用户看到的含税价格乘以固定比例,作为最终的财务结算结果。

注意事项

  • 杂志 PDF 或其他资源应设置访问控制,防止用户取得下载地址后长期绕过权限检查。
  • 商品列表应使用 StoreKit 返回的本地化价格,不要自行拼接货币符号。
  • 必须正确处理 .pending、用户取消、退款和交易撤销。
  • 自动续期订阅需要清楚说明价格、周期和自动续期条件。
  • 审核账号应能访问购买页面及相关内容,否则审核人员可能无法验证功能。
  • App Store 沙盒测试结果不等同于正式环境的结算结果。
  • 上线前应再次核对 Apple 最新的审核规则、IAP 协议及目标发行地区政策。

较稳妥的设计是为单期杂志使用非消耗型 IAP,为长期会员使用自动续期订阅,并在定价和收入预算中计入 Apple 佣金。

备注:内容仅供参考。