Android 应用中最简单、常用的支付方式有哪些?
结论
支付方式要根据商品类型来选:
- 数字商品或应用内功能:包括会员、虚拟币、关卡、去广告和电子内容等。应用通过 Google Play 分发时,通常应接入 Google Play Billing。这种方案最常见,用户的支付操作也比较简单。
- 实体商品或线下服务:包括衣服、食品、打车和酒店预订等。此类交易通常使用 Stripe、PayPal、银行卡收单或本地支付服务,不应作为 Google Play 应用内商品处理。
- 应用外销售的数字内容:是否可以引导用户使用其他支付方式,要看应用的分发渠道、用户所在地区、商品类型,以及当时有效的 Google Play 政策。上线前需要核对最新政策,不能只根据技术可行性判断。
如果主要考虑接入简单,数字商品优先使用 Google Play Billing;实体商品则选择提供 Android SDK 或托管收银台的支付服务商。
数字商品:使用 Google Play Billing
Google Play Billing 主要用于以下两类商品:
- 一次性商品:永久解锁、虚拟币、道具、去广告等。
- 订阅商品:月度会员、年度会员和持续提供的数字服务等。
基本接入流程如下:
- 在 Google Play Console 中创建一次性商品或订阅商品。
- 在 Android 项目中加入 Google Play Billing Library。
- 创建
BillingClient,并连接 Google Play。 - 查询后台配置的
ProductDetails。 - 调用
launchBillingFlow()打开 Google Play 支付界面。 - 收到购买结果后,将
purchaseToken发送到自己的服务器进行验证。 - 发放商品,并确认或消耗这笔购买。
依赖版本会不断更新,应按照官方文档选择当前的稳定版本:
dependencies {
implementation("com.android.billingclient:billing-ktx:<current-version>")
}
下面的 Kotlin 代码简要展示了连接和购买回调的结构。实际项目还需要处理断线重连、商品查询、服务端验证和异常情况:
class BillingManager(
context: Context
) : PurchasesUpdatedListener {
private val billingClient = BillingClient.newBuilder(context)
.setListener(this)
.enablePendingPurchases(
PendingPurchasesParams.newBuilder()
.enableOneTimeProducts()
.build()
)
.build()
fun connect() {
billingClient.startConnection(
object : BillingClientStateListener {
override fun onBillingSetupFinished(
billingResult: BillingResult
) {
if (billingResult.responseCode ==
BillingClient.BillingResponseCode.OK
) {
// 此时可以查询商品和已有购买记录
}
}
override fun onBillingServiceDisconnected() {
// 在合适的时机重试连接
}
}
)
}
override fun onPurchasesUpdated(
billingResult: BillingResult,
purchases: MutableList<Purchase>?
) {
when (billingResult.responseCode) {
BillingClient.BillingResponseCode.OK -> {
purchases.orEmpty().forEach { purchase ->
// 将 purchase.purchaseToken 发送到服务器验证
// 验证成功后发放商品并 acknowledge 或 consume
}
}
BillingClient.BillingResponseCode.USER_CANCELED -> {
// 用户取消支付,无须显示错误
}
else -> {
// 根据 responseCode 记录并处理失败
}
}
}
}
取得 ProductDetails 后,可以打开购买界面:
fun launchPurchase(
activity: Activity,
productDetails: ProductDetails,
offerToken: String? = null
) {
val productParamsBuilder =
BillingFlowParams.ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
if (offerToken != null) {
productParamsBuilder.setOfferToken(offerToken)
}
val billingFlowParams = BillingFlowParams.newBuilder()
.setProductDetailsParamsList(
listOf(productParamsBuilder.build())
)
.build()
billingClient.launchBillingFlow(activity, billingFlowParams)
}
是否需要提供 offerToken,取决于商品类型和优惠配置,不能对所有商品采用同一种处理方式。
实体商品或线下服务:使用第三方支付
销售实体商品或现实世界中的服务时,可以选择:
- Stripe 等支付网关;
- PayPal;
- 银行卡收单服务;
- 微信支付、支付宝等本地支付方式;
- 支付服务商提供的托管收银台。
为了降低开发和合规成本,可以优先使用服务商提供的 SDK 或托管支付页面。不要在应用内自行收集、传输或保存银行卡号、CVV 等敏感信息。
常见的支付流程如下:
Android 客户端请求下单
↓
业务服务器创建支付订单
↓
客户端使用 SDK 或托管收银台完成支付
↓
支付服务商向服务器发送回调
↓
服务器验证回调并更新订单状态
↓
客户端查询并展示最终结果
订单金额、币种和商品信息应由服务器确定,不能直接信任客户端上传的价格。
必须注意的问题
不要只依赖客户端判断支付成功
APK 可能被修改,客户端回调也可能被伪造。对于数字商品,应将 purchaseToken 发送到服务器,由服务器通过对应的平台接口验证购买状态。使用第三方支付时,则应以服务端完成签名验证后的异步回调为准。
正确处理确认和消耗
在 Google Play Billing 中,购买成功并不意味着整个流程已经结束:
- 对于可以重复购买的消耗型商品,需要在发货后执行消耗。
- 对于非消耗型商品和订阅,通常需要在确认发货后执行购买确认。
- 服务端验证完成前,不要过早发放高价值商品。
具体的确认时限和接口要求可能会随 Billing Library 版本与平台政策变化,应以当前官方文档为准。
处理重复回调和未完成订单
支付回调可能重复发送,网络也可能在付款成功后中断。服务器的发货接口必须具备幂等性。例如,可以使用订单号或购买令牌建立唯一约束,防止同一笔交易重复发货。
应用启动、恢复到前台或重新连接 Billing 服务时,也应该查询已有的购买记录,以便恢复已经付款、但客户端尚未发货的订单。
先确认分发渠道
Google Play、第三方 Android 商店和企业内部分发可能采用不同的支付规则。技术上可以接入某个支付 SDK,不代表对应商店允许用它销售应用内数字商品。
比较稳妥的做法是:Google Play 上的数字商品使用 Google Play Billing;实体商品和线下服务使用合规的第三方支付服务;其他分发渠道按照各自的规则单独设计。
备注:内容仅供参考。
