硬件与订阅捆绑销售是否必须使用 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 内数字权益。审核人员可能按照权益的实际内容判断,而不是只看营销名称。
可以按以下方式处理:
- 将硬件和设备连接服务放入普通支付订单。
- 将高级报告、长期云端历史记录等数字权益定义为独立 SKU。
- 在 iOS 上通过 StoreKit 销售需要内购的数字权益。
- 在 Google Play 版本中通过 Google Play Billing 销售需要商店结算的数字权益。
- 由后端统一管理用户、设备和订阅状态,同时保留每项权益的购买来源。
例如:
{
"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、价格和权益说明,并取得针对该业务模式的书面确认。
备注:内容仅供参考。
