高级功能 Android SDK

Android的高级配置和自定义集成。

替代安装方案

基本流程采用自动支付方式显示。如需更多控制选项,请使用以下替代方案:

自定义支付方式选择(startPaymentLite)

控制要显示的支付方式:

// 1. Fetch available methods
val methods = fetchPaymentMethods(sessionId)

// 2. Display in your UI
// 3. Start payment with selected method

startPaymentLite(
    paymentMethodType = selectedMethod, // "CARD", "PIX", etc.
    vaultedToken = null,
    showPaymentStatus = true,
    callbackOTT = { token ->
        token?.let { createPayment(it, checkoutSession) }
    }
)

简化流程 (startPaymentSeamlessLite)

与精简版类似,但具备自动创建付款功能:

startPaymentSeamlessLite(
 paymentMethodType "CARD",
 vaultedToken  null,
 showPaymentStatus  true
)

注册(保存卡片)

付款时节省

// When creating payment on backend, include vault_on_success flag
suspend fun createPayment(token: String, checkoutSession: String) {
    apiClient.post("/payment/create", mapOf(
        "one_time_token" to token,
        "checkout_session" to checkoutSession,
        "vault_on_success" to true // Save after successful payment
    ))
}

// Configure SDK to show save checkbox
startCheckout(
    callbackPaymentState = { state -> handlePaymentState(state) }
)

// Update with session - SDK will show "Save card" checkbox automatically
updateCheckoutSession(
    checkoutSession = session.checkoutSession,
    countryCode = "US"
)

单独注册

// Create customer session on backend
val customerSession = createCustomerSession("cus_123")

// Start enrollment
initEnrollment(
    customerSession = customerSession.id,
    countryCode = "US"
)

// Start enrollment flow
startEnrollment(
    showEnrollmentStatus = true,
    callback = { vaultedToken ->
        vaultedToken?.let {
            println("Card saved: $it")
        }
    }
)

拱顶Token

startPaymentLite(
 paymentMethodType "CARD",
 vaultedToken "vtok_saved_card_123",
 showPaymentStatus  true,
 callbackOTT {token >
 token?.let { createPayment(it,checkoutSession) }
    }
)

自定义用户界面(无头集成)

当您需要完全掌控每个用户界面元素、打造高度定制的结账体验,或拥有开发定制界面的资源时,可构建具备完整用户界面控制权的完全定制化支付表单。

import com.yuno.sdk.Yuno
import com.yuno.sdk.api.ApiClientPayment

lifecycleScope.launch {
    // 1.Initialize 
    val apiClient = Yuno.apiClientPayment(
 countryCode "US",
 checkoutSession "session_id"
    )
    
    // 2. 在自定义界面收集卡片数据
    valtoken  apiClient.generateToken(
 checkoutSession "session_id",
        paymentMethod = PaymentMethod(
            type = "CARD",
            card = CardData(
                number = "4111111111111111",
                expirationMonth = 12,
                expirationYear = 25,
                securityCode = "123",
                holderName = "John Doe",
                type = "CREDIT"
            )
        )
    )
    
    // 3. 使用令token
创建支付
    createPayment(token.oneTimeToken)
    
    // 4. 处理后续操作(如需)
    apiClient.continuePayment(
        activity = this@PaymentActivity,
        onPaymentResult = { result ->
            handlePaymentResult(result)
        }
    )
}

使用拱顶Token

valtoken  apiClient.generateToken(
 checkoutSession "session_id",
    paymentMethod = PaymentMethod(
        type = "CARD",
 vaultedToken "saved_token_id",
        card = CardData(securityCode = "123")
    )
)

渲染模式集成

在您的自定义视图中显示付款表单。

class PaymentActivity : ComponentActivity(), YunoPaymentRenderListener {
    
    private lateinit var paymentController: YunoPaymentFragmentController
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        setContent {
            var paymentView by remember { mutableStateOf<View?>(null) }
            
            Column {
                Button(onClick = { startRenderMode() }) {
                    Text("Pay Now")
                }
                
                paymentView?.let {
                    AndroidView(factory = { it })
                }
            }
        }
    }
    
    private fun startRenderMode() {
        lifecycleScope.launch {
            val session = createCheckoutSession()
            
            paymentController = Yuno.startPaymentRender(
                activity = this@PaymentActivity,
                checkoutSession = session.id,
                countryCode = "US",
                listener = this@PaymentActivity
            )
        }
    }
    
    override fun onFormView(view: View) {
        // Add view to your layout
        findViewById<FrameLayout>(R.id.payment_container).addView(view)
    }
    
    override fun onSubmitForm() {
        // Customer submitted form
    }
    
    override fun onPaymentResult(result: PaymentResult) {
        if (result.status == PaymentStatus.SUCCEEDED) {
            navigateToSuccess()
        }
    }
}

造型设计

通过主题自定义SDK外观。

colors.xml:

<color name="yuno_primary">#007bff</color>
<color name="yuno_background">#ffffff</color>
<color name="yuno_text">#333333</color>
<color name="yuno_error">#dc3545</color>

themes.xml:

<style name="YunoSDKTheme" parent="Theme.MaterialComponents">
    <item name="colorPrimary">@color/yuno_primary</item>
    <item name="colorOnPrimary">@android:color/white</item>
    <item name="android:textColor">@color/yuno_text</item>
</style>

应用主题:

Yuno.setTheme(R.style.YunoSDK主题)

卡片扫描(OCR)

启用摄像头扫码功能。

添加依赖项:

dependencies {
    implementation("com.yuno.sdk:card-scan:2.8.1")
}

在配置中启用:

Yuno.initialize(
    this,
    publicApiKey = "your-key",
    config =YunoConfig(
        cardScanEnabled = true
    )
)

卡片扫描按钮自动以卡片形式显示。

ClearSale 集成

启用欺诈预防功能。

添加 ClearSale SDK:

dependencies {
    implementation("br.com.clearsale:cs-android-sdk:4.0.0")
}

Initialize:

import br.com.clearsale.androidsdk.ClearSale

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        
        // Initialize ClearSale
        ClearSale.init(this, "your-clearsale-app-key")
        
        // Initialize Yuno
        Yuno.initialize(this, "your-public-key", YunoConfig())
    }
}

ClearSalefingerprint 自动收集并发送。

错误处理

处理支付状态回调和支付处理中的错误:

// Set up error handling in payment state callback
startCheckout(
    callbackPaymentState = { state ->
        when (state) {
            "SUCCEEDED" -> handleSuccess()
            "FAIL" -> {
                // Handle payment failure
                showError("Payment failed")
            }
            "REJECT" -> {
                // Handle payment rejection
                showRejectedMessage()
            }
            "PROCESSING" -> showPendingMessage()
            else -> {}
        }
    }
)

// Update session with error handling
try {
    val session = createCheckoutSession()
    updateCheckoutSession(
        checkoutSession = session.checkoutSession,
        countryCode = "US"
    )
} catch (e: Exception) {
    Log.e("Payment", "Session error: ${e.message}")
    showError("Failed to initialize payment")
}

// Handle errors during payment creation
startPayment(
    showStatusYuno = true,
    callbackOTT = { token ->
        lifecycleScope.launch {
            try {
                createPayment(token, checkoutSession)
            } catch (e: Exception) {
                Log.e("Payment", "Payment creation error: ${e.message}")
                showError("Payment failed: ${e.message}")
            }
        }
    }
)

测试与调试

启用日志记录

Yuno.setLogLevel(LogLevel.VERBOSE)

测试模式

Yuno.initialize(
    this,
    publicApiKey = "pk_test_your_key",
    config =YunoConfig(testMode = true)
)

性能

延迟初始化

val yuno by lazy {
    Yuno.initialize(this, "pk_test_key",YunoConfig())
    Yuno.getInstance()
}

预加载 SDK

lifecycleScope.launch(Dispatchers.IO) {
    Yuno.preload(this@MainActivity)
}

外部浏览器返回(深度链接)

处理用户在经历外部支付流程(如3DS认证挑战、银行转账重定向、PIX支付以及其他带外部重定向的支付方式)后返回应用的情况。

1. 在结账会话中设置回调网址

包含 callback_url 在后端创建结账会话时:

{
  "callback_url": "myapp://return"
}
❗️

重要

没有 callback_url用户可能会被困在外部浏览器中,无法返回您的应用。

2. 配置深度链接处理

添加一个 intent-filter 在您的活动中 AndroidManifest.xml:

<activity android:name=".YourMainActivity">
    <intent-filter android:autoVerify="true">
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data
            android:scheme="myapp"
            android:host="return" />
    </intent-filter>
</activity>

该计划 (myapp)和主机(return) 必须与您的 callback_url.

3. 处理退货意向

当用户返回时处理深度链接:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    
    // Check if app was opened via deep link
    intent.data?.let { uri ->
        val url = uri.toString()
        if (url.contains("myapp://return")) {
            handlePaymentReturn(uri)
        }
    }
}

private fun handlePaymentReturn(uri: Uri) {
    val sessionId = uri.getQueryParameter("checkoutSession")
    
    sessionId?.let {
        continuePayment(
            showPaymentStatus = true,
            checkoutSession = it,
            countryCode = "US"
        ) { result ->
            result?.let { status ->
                Toast.makeText(this, "Payment status: $status", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

4. 全面集成示例

class PaymentActivity : ComponentActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        // Initialize checkout
        startCheckout(
            callbackPaymentState = { state ->
                handlePaymentState(state)
            }
        )
        
        // Handle deep link return
        if (intent?.data != null) {
            handleDeepLinkReturn(intent)
        } else {
            // Normal payment flow
            initializePaymentUI()
        }
    }
    
    private fun handleDeepLinkReturn(intent: Intent) {
        intent.data?.let { uri ->
            if (uri.toString().contains("myapp://return")) {
                val sessionId = extractCheckoutSession(uri)
                
                sessionId?.let {
                    continuePayment(
                        showPaymentStatus = true,
                        checkoutSession = it,
                        countryCode = "US"
                    ) { result ->
                        when (result) {
                            "SUCCEEDED" -> navigateToSuccess()
                            "FAILED" -> showError("Payment failed")
                            else -> showPendingMessage()
                        }
                    }
                }
            }
        }
    }
    
    private fun extractCheckoutSession(uri: Uri): String? {
        return uri.getQueryParameter("checkoutSession")
    }
}

最佳实践

  • 始终包含 callback_url 在可能重定向的支付流程中
  • 在多种设备和Android版本上测试深度链接处理
  • 优雅处理缺失或格式错误的深度链接数据
  • 在从外部浏览器返回后,在您的用户界面中更新付款状态