PAYATHON 2026

硬件与订阅捆绑销售是否必须使用 in-app purchase API?

支付阿杰

结论

如果数据订阅只用于 OBD-II dongle 的蜂窝联网、设备遥测或其他现实世界中的硬件服务,通常可以把整个组合归为“实体商品及其配套服务”,通过信用卡、Apple Pay、Google Pay 或第三方支付处理商结算,无需使用 Apple In-App Purchase 或 Google Play Billing。

判断依据不是账单里是否同时包含硬件和订阅,而是用户实际购买了哪些权益:

  • 硬件及其数据连接:通常属于实体商品或实体设备配套服务,可以使用外部支付。
  • 解锁 app 内的数字功能、数字内容或云端分析能力:可能属于数字商品,需要使用相应应用商店的购买系统。
  • 同时包含两类权益:不宜打包成无法区分的统一月费。价格和权益应分别列明,并采用各自适用的支付方式。

因此,对于示例中的 $99/month dongle + $20/month data connection,只要 $20 确实只用于 SIM、蜂窝流量或设备通信,通常不需要接入 StoreKit 或 Google Play Billing。

为什么数据连接通常不属于应用内数字商品

Apple 和 Google 的应用内购买规则主要适用于在 app 中消费的数字内容和数字功能,例如:

  • 高级软件功能
  • 数字内容
  • 云端存储
  • 游戏道具
  • 无广告权益
  • 仅在 app 内使用的数据分析订阅

实体硬件、物流、交通、现场服务,以及与现实世界设备直接相关的服务,一般不通过商店内购结算。如果 OBD-II dongle 的蜂窝数据连接只是帮助硬件上传车辆数据,这项服务主要由实体设备使用,而不是由用户在 app 内消费。

用户在 app 界面中下单,并不等于这笔交易必须使用 In-App Purchase。需要区分的是:

  • 在 app 内发起普通商品付款:可以使用适用于实体商品的支付方式。
  • 使用应用商店的数字商品内购系统:只适用于符合商店内购规则的数字商品。

推荐的产品和计费设计

不建议只设置一个含义不清的 $119/month 商品。订单、协议和后台数据模型都应明确区分各项费用:

{
  "plan": "obd_connected_plan",
  "currency": "USD",
  "items": [
    {
      "type": "hardware",
      "name": "OBD-II dongle",
      "amount": 9900
    },
    {
      "type": "device_connectivity",
      "name": "Cellular data connection",
      "amount": 2000,
      "billing_interval": "month"
    }
  ]
}

即使最终合并为一次扣款,也应向用户清楚展示硬件费用、连接费用、续费周期和取消条件。这既方便应用审核,也能避免用户把 $20 误解为解锁 app 功能的数字订阅。

一种较容易说明的商业模式是:

  • 硬件:一次性购买,或收取明确的租赁费用。
  • 数据连接:按月自动续费。
  • app:免费提供设备配置、状态查看和基础数据展示。
  • 可选高级软件服务:作为独立的数字订阅处理。

如果高级软件服务确实需要通过 App Store 或 Google Play 购买,就不能为了避开内购规则而将其命名为“数据费”。

客户端处理方式

客户端可以向业务服务器创建实体商品订单,再进入普通支付流程。不要将硬件套餐配置为 StoreKit product 或 Google Play Billing product。

下面是简化后的 iOS 业务流程示例:

enum ProductCategory: String, Codable {
    case hardware
    case deviceConnectivity = "device_connectivity"
    case digitalFeature = "digital_feature"
}

func purchaseConnectedDongle() async throws {
    let order = try await api.createOrder(
        sku: "obd_connected_plan",
        quantity: 1
    )

    guard order.paymentCategory == "physical_goods" else {
        throw CheckoutError.invalidProductCategory
    }

    // 调用 Apple Pay、银行卡或支付服务商的 iOS SDK。
    // 不调用 StoreKit.purchase()。
    try await paymentProvider.presentCheckout(
        clientSecret: order.paymentClientSecret
    )
}

Android 端遵循相同的分类原则:

suspend fun purchaseConnectedDongle() {
    val order = api.createOrder(
        sku = "obd_connected_plan",
        quantity = 1
    )

    require(order.paymentCategory == "physical_goods")

    // 调用 Google Pay、银行卡或支付服务商的 Android SDK。
    // 不调用 BillingClient.launchBillingFlow()。
    paymentProvider.presentCheckout(
        clientSecret = order.paymentClientSecret
    )
}

代码中的 paymentProvider 和 createOrder 是业务层抽象,不是 Apple 或 Google 提供的固定 API。具体实现由所选的支付服务商决定。

服务端必须校验实际权益

商品类型不能只依赖客户端传值。服务端应保存 SKU 与权益之间的对应关系,并拒绝客户端修改金额或商品类别:

const catalog = {
  obd_connected_plan: {
    paymentCategory: "physical_goods",
    items: [
      { type: "hardware", amount: 9900 },
      { type: "device_connectivity", amount: 2000 }
    ]
  },
  advanced_analytics_monthly: {
    paymentCategory: "digital_goods",
    items: [
      { type: "digital_feature", amount: 1500 }
    ]
  }
};

function createOrder(request) {
  const product = catalog[request.sku];

  if (!product) {
    throw new Error("Unknown SKU");
  }

  return {
    sku: request.sku,
    amount: product.items.reduce((sum, item) => sum + item.amount, 0),
    paymentCategory: product.paymentCategory
  };
}

如果 advanced_analytics_monthly 会直接解锁面向消费者的 app 内分析功能,通常不能继续使用硬件付款通道。除非业务明确符合某项例外,否则 iOS 和 Android 应根据各自的商店规则,接入对应的数字商品购买系统。

混合套餐需要特别谨慎

下面这类套餐的审核风险较高:

$99 hardware
$20 data connection
Included: advanced reports, unlimited cloud history and AI diagnostics

虽然账单名称写的是“data connection”,套餐中却包含可以单独识别的 app 内数字权益。审核人员可能按照权益的实际内容判断,而不是只看营销名称。

可以按以下方式处理:

  1. 将硬件和设备连接服务放入普通支付订单。
  2. 将高级报告、长期云端历史记录等数字权益定义为独立 SKU。
  3. 在 iOS 上通过 StoreKit 销售需要内购的数字权益。
  4. 在 Google Play 版本中通过 Google Play Billing 销售需要商店结算的数字权益。
  5. 由后端统一管理用户、设备和订阅状态,同时保留每项权益的购买来源。

例如:

{
  "entitlements": {
    "device_connected": {
      "source": "external_checkout",
      "expires_at": "2026-10-14T00:00:00Z"
    },
    "advanced_analytics": {
      "source": "app_store",
      "expires_at": "2026-10-14T00:00:00Z"
    }
  }
}

提交审核时应说明什么

审核备注应清楚说明:

  • app 需要配合实体 OBD-II 设备使用。
  • 普通支付购买的只有硬件、配送和设备蜂窝连接服务。
  • 数据连接由 dongle 使用,用于传输车辆遥测数据。
  • 外部付款不会解锁额外的纯数字功能。
  • 如果存在数字订阅,应说明它使用了哪种商店购买机制。
  • 提供审核账号、测试设备模式或演示视频,避免审核人员因缺少硬件而无法验证。

商品页、付款页和服务条款也应明确列出:

  • 硬件采用购买、租赁还是分期方式提供。
  • $99 是否按月收取,以及用户取消后是否需要归还设备。
  • $20 的续费周期、流量限制和超额费用。
  • 取消方式、生效时间和退款规则。
  • 数据服务终止后,app 和 dongle 各自还能使用哪些功能。

注意事项

应用商店不会因为商品被称为“bundle”,就自动允许它使用外部支付。支付方式取决于每项权益的实际用途。

如果用户没有 dongle 也能使用订阅中的主要功能,或者订阅的主要价值来自 app 内的软件能力,就不能只凭“附带硬件”这一点绕过应用内购买。

汽车数据套餐还可能涉及自动续费披露、消费者保护、税务、通信服务转售、隐私和车辆数据合规。这些要求与应用商店支付规则属于两类不同的问题,需要按照销售地区分别确认。

Apple 和 Google 的政策、地区性例外以及外部支付条款都可能调整。正式上线前,应以提交时有效的 App Review Guidelines 和 Google Play Payments policy 为准。如果套餐中包含难以拆分的数字服务,最好通过开发者支持渠道提交完整的 SKU、价格和权益说明,并取得针对该业务模式的书面确认。

备注:内容仅供参考。