桥接层架构:创建 Bridge 接口、定义支付请求与响应数据类、线程调度抽象

4.1 桥接层的作用与设计原则

在支付宝支付 SDK 与 Jetpack Compose 之间加入桥接层,是为了将原生 SDK 的同步 / 回调式 API 转化为 Compose 可组合函数能够安全调用的异步、无副作用接口。桥接层承担三个职责:

  • 接口统一:屏蔽支付宝 SDK 不同版本的 API 差异,对外暴露简洁的 PaymentBridge 接口。
  • 数据封装:将原始 Map<String, String> 或回调参数转换为强类型数据类,便于 Compose 状态管理。
  • 线程调度:保证支付请求在 IO 线程执行,结果回调自动切换到主线程,避免 Compose 重组线程冲突。
桥接层本身不应包含任何业务逻辑(如订单校验、签名计算),只负责协议转换与线程安全。业务逻辑应放在 ViewModel 或 UseCase 层。

4.2 Bridge 接口定义

接口围绕支付生命周期设计,包含发起支付、查询支付结果、取消支付三个核心方法。

// PaymentBridge.kt
interface PaymentBridge {
    suspend fun pay(request: PaymentRequest): PaymentResult

    suspend fun queryPaymentResult(orderId: String): PaymentResult

    fun cancelPayment(orderId: String)
}
  • pay 为挂起函数,调用后会启动支付宝 SDK 支付流程,并在支付完成后返回结果。
  • queryPaymentResult 用于在异常断网或回调未收到时主动轮询。
  • cancelPayment 为普通函数,用于在 UI 层主动取消等待中的支付。

4.3 支付请求与响应数据类

数据类将支付宝 SDK 的 Map / Bundle 参数和回调结果映射为不可变对象,便于在 Compose 中作为状态使用。

数据类字段说明
PaymentRequestval orderInfo: String服务端签名的订单信息字符串
val appScheme: String用于跳转回应用的 URL Scheme
PaymentResultval resultStatus: Int9000 成功,6001 取消,6002 网络错误等
val memo: String结果说明文字
val result: String?同步返回的完整结果 JSON(可选)
PaymentErrorval errorCode: Int自定义错误码(-1 未初始化,-2 参数错误)
val message: String人类可读的错误描述
// PaymentRequest.kt
data class PaymentRequest(
    val orderInfo: String,
    val appScheme: String = "alipays"
)

// PaymentResult.kt
data class PaymentResult(
    val resultStatus: Int,
    val memo: String,
    val result: String? = null
)

// PaymentError.kt
data class PaymentError(
    val errorCode: Int,
    val message: String
)
支付宝 SDK 的 resultStatus 为 9000 仅代表支付成功,但仍需对 result 字段做签名校验。桥接层不负责签名验证,但应保留原始 result 字符串供上层校验。

4.4 线程调度抽象

为了保证 Compose 状态更新的线程安全,桥接层必须提供线程调度抽象。推荐使用 Kotlin 协程的 Dispatchers,但为了便于单元测试和切换实现,定义 PaymentDispatcher 接口。

// PaymentDispatcher.kt
interface PaymentDispatcher {
    val io: CoroutineDispatcher
    val main: CoroutineDispatcher
}

class DefaultPaymentDispatcher : PaymentDispatcher {
    override val io: CoroutineDispatcher = Dispatchers.IO
    override val main: CoroutineDispatcher = Dispatchers.Main
}

在 Bridge 实现类中,通过依赖注入接收 PaymentDispatcher,并使用 withContext 切换调度器:

class AlipayBridgeImpl(
    private val dispatcher: PaymentDispatcher = DefaultPaymentDispatcher()
) : PaymentBridge {

    override suspend fun pay(request: PaymentRequest): PaymentResult = withContext(dispatcher.io) {
        // 调用支付宝 SDK 同步方法(阻塞 IO 线程)
        val resultMap = AlipayService.payV2(request.orderInfo, request.appScheme)
        withContext(dispatcher.main) {
            PaymentResult(
                resultStatus = resultMap["resultStatus"]?.toIntOrNull() ?: -1,
                memo = resultMap["memo"] ?: "",
                result = resultMap["result"]
            )
        }
    }
    // ... 其他方法类似
}

4.5 桥接层架构总览

桥接层架构组件关系图 桥接层架构组件关系图 PaymentBridge pay / query / cancel PaymentRequest orderInfo + appScheme PaymentResult status / memo / result PaymentDispatcher io + main AlipayBridgeImpl 实现类 说明 实线: 依赖/使用关系 虚线: 依赖注入或数据流

4.6 实现流程(逐步指南)

  1. 创建 bridge 包,包含接口、数据类、调度器三个文件。
  2. 定义 PaymentBridge 接口,方法签名如上。
  3. 定义 PaymentRequest、PaymentResult、PaymentError 数据类。
  4. 定义 PaymentDispatcher 接口及默认实现。
  5. 创建实现类 AlipayBridgeImpl,注入 PaymentDispatcher,在每个方法中使用 withContext(dispatcher.io) 包裹支付宝 SDK 调用,并在返回前切回 dispatcher.main。
  6. 在 Application 或依赖注入模块中提供 PaymentBridge 的单例实例。

4.7 调试与常见错误

调试点:在 AlipayBridgeImpl 的 pay 方法入口和出口添加日志,打印线程名称和 resultStatus,确认调度器正常工作。
  • 错误:Context 泄漏 — 如果 AlipayBridgeImpl 持有 Activity 引用,会导致内存泄漏。解决:只传递 Application Context。
  • 错误:主线程卡死 — 支付宝 SDK 的 payV2 是同步方法,如果在主线程调用会 ANR。确保使用 withContext(dispatcher.io)。
  • 错误:Compose 重组异常 — 如果在非主线程更新 Compose 状态,会抛出 CalledFromWrongThreadException。解决:始终通过 dispatcher.main 返回结果。

4.8 性能与稳定性优化

优化目标措施
减少线程切换开销支付宝 SDK 本身可能异步回调,可在回调内部直接切线程,避免多次调度
结果缓存对 queryPaymentResult 添加短期内存缓存(5秒),避免重复请求
取消支持在 cancelPayment 中设置 AtomicBoolean 标志,pay 方法内轮询该标志并尽早返回
自定义调度器对于高并发场景,可提供 LimitedParallelismDispatcher 限制并发数
稳定性最关键的实践:在 AlipayBridgeImpl 内将所有支付宝 SDK 原生异常捕获为 PaymentError 并抛出,而不是让上层直接捕获平台异常。这样可以做到错误类型统一。