阅读 628

Android完整接入PayPal支付及常见问题(使用paypal支付)

前言

1.我是参考了一下@TimberBug哥子的文章www.jianshu.com/p/346e7f308…,感谢,了解了一个大概,但是支付的代码没跑起来,最终还是参考Paypal的Demo代码才跑起来,估计是我用的最新版本的问题,然后吐槽哈Paypal官方的Android的示例代码,你们示例代码写得那么简单,看得大家一脸懵逼,真的良心不会痛吗? 2.服务端集成接口文档地址:developer.paypal.com/docs/api/or… 3.Android端集成接口文档地址:developer.paypal.com/docs/busine…或新版的地址developer.paypal.com/sdk/in-app/…

Paypal集成准备工作

  1. 登录或注册账号,注册新账号需要选择国家,最好绑定一张银行卡,储蓄卡或信用卡均可

  2. 登录进去在Dashboard界面左边的菜单“My apps & credentials”里面的“REST API apps”项创建一个App或修改一个已有的App,目前系统会默认创建一个Default Application,可直接点击进去修改使用

11559288-4be3f65d1a103998.webp

  1. 点进去之后主要有3大块:

1).SANDBOX API CREDENTIALS:配置信息相关;主要包含Sandbox account(沙箱环境商家收款邮箱账号),Client ID(后台Api接口认证加签和App的Sdk初始化需要用到),Secret(后台Api接口认证加签需要用到)

2.webp

2).SANDBOX APP SETTINGS:App的Sdk相关配置设置;主要关注Return URL(自定义协议Uri,这个不是支付宝、微信支付完成的回调Url,这个是调起支付需要登录Paypal买家账号时,Paypal会跳转到浏览器进行网页登录,当登录完成需要返回App的时候就需要自定义协议Uri返回我们App里面,格式类类似于网址:com.xxxx.protocol://xxxx.xxx,目前Paypal固定后缀格式:xxx.xxx.xx://paypalpay,一般xxx.xxx.xx设置为当前App的包名);其他需要关注的是Accept payments,必须勾上,且Advanced options展开Native Checkout SDK必须是绿色的勾勾;然后Log in with PayPal,必须勾上,且Advanced options展开Full name和Email必须勾上,Privacy policy URL和User agreement URL随便填写给地址就行,比如百度www.baidu.com/;总体参数按我如下截图…

3.webp 4.webp

3).SANDBOX WEBHOOKS:这个就是支付完成Paypal后台通知我们自己后台的配置地方,这个才是类似支付宝、微信支付完成的回调Url,一般配置后台的接口,按需使用

5.webp

  1. 其他需要关注的就是沙箱环境里面的卖家测试账号和买家账号,账号类型Type字段Business标识的就是卖家,如果需要就配置在代码收款商Payee位置,Type字段Personal标识的就是买家,需要在App的Sdk拉起网页付款登录时登录这个账号;点开Manage accounts对应的三个点,选择View/edit account,在弹框中可点击Change password修改系统随机生成的密码成你自己想要的,注意:修改保存完成后并不会显示,但是已经修改成功啦,可用这个密码去做付款账号的登录了(但是换成生产账号测试时遇到一个奇怪现象:我在App的Sdk拉起网页付款登录时登录Personal标识的买家账号时,结果网页一直提示我是登录的卖家账号,不能完成登录付款,换成Business标识的账号登录就成功了,测试环境就必须登录Personal标识的才能付款,因此暂时只能定义成Paypal的Bug了)

6.webp 7.webp

Paypal Android SDK集成工作

  • 1.开启网络权限

<manifest xmlns:android="http://schemas.android.com/apk/res/android">       ...       <uses-permission android:name="android.permission.INTERNET" />       ...   </manifest> 复制代码

  • 2.项目根build.gradle文件中配置paypal的仓库

allprojects {     repositories {         ...         maven {             url  "https://cardinalcommerceprod.jfrog.io/artifactory/android"             credentials {// Be sure to add these non-sensitive credentials in order to retrieve dependencies from the private repository.                 username 'paypal_sgerritz'  //官方文档这里字符串没得单引号,导致报错,差评                 password 'AKCp8jQ8tAahqpT5JjZ4FRP2mW7GMoFZ674kGqHmupTesKeAY2G8NcmPKLuTxTGkKjDLRzDUQ'  //官方文档这里字符串没得单引号,导致报错,差评             }         }     } } 复制代码

  • 3.添加Java 8的兼容处理

android {     ...     compileOptions {         sourceCompatibility JavaVersion.VERSION_1_8         targetCompatibility JavaVersion.VERSION_1_8     }     kotlinOptions {         jvmTarget = "1.8"     } } 复制代码

  • 4.添加Paypal的lib库最新版依赖(注:因Paypal Sdk是用kotlin写的,请提前添加androidx.core:core-ktx和org.jetbrains.kotlin:kotlin-stdlib-jdk7支持)

implementation('com.paypal.checkout:android-sdk:0.5.2') {         exclude group: 'com.google.code.gson', module: 'gson'  //这里排除gson是因为和我主项目的gson冲突了,而且paypal依赖的还是比我新的版本,导致我本地报错了;其实还有个重要冲突是okhttp,我们项目用的是3.14.0,paypal用的是4.8.0,因为4.x版本比3.x版本变化比较大,而且还不能排除paypal的4.x版本,会导致paypal初始化就报错,所以我们只有把主项目okhttp升级到最新了     } 复制代码

Paypal Android SDK开发工作

  • 1.在Application的onCreate方法做如下Paypal初始化操作

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {//其中clientId需要替换成上面步骤申请到的客户端id     PayPalCheckout.setConfig(CheckoutConfig(application, clientId, if (BuildConfig.DEBUG) Environment.SANDBOX else Environment.LIVE, String.format("%s://paypalpay", BuildConfig.APPLICATION_ID), CurrencyCode.USD, UserAction.PAY_NOW, PaymentButtonIntent.CAPTURE, SettingsConfig(BuildConfig.DEBUG, false))) }else{     System.out.println("initPayPal失败,系统版本过低") } 复制代码

  • 2.Paypal的3种代码集成方式

1). Client-side integration: 客户端集成,主要特点是需要集成一个PayPal自带的支付按钮PayPalButton,这个按钮仅可做少量Paypal固定的UI定制,侵入性比较强,然后创建订单和执行订单捕获逻辑均在App端,适用于不要后台参与的情况

2). Server-side integration: 服务端集成,主要特点是服务端创建订单和执行订单捕获,App端只需接收服务端返回的paypal订单id,调用createOrderActions.set(orderId)设置即可开启订单支付逻辑,适合于主流支付逻辑,后台订单可信可控,我们采用的这种方式

3). Programmatically start the SDK: 客户端集成,主要特点和Client-side integration比较类似,只是不需要集成PayPal自带的支付按钮PayPalButton,然后创建订单和订单捕获逻辑均在App端,适用于不要后台参与的情况

  • 3.我们集成Server-side integration的代码如下(参数paypalOrderId为后台去调paypal的创单接口获取到的订单id)

    private var checkOrderMax: Int = 300//循环检测的最大次数     private var checkOrderCount: Int = -1//循环检测的初始次数     private var isCheckOrderFlag: Boolean = false//是否检测订单状态中   @RequiresApi(Build.VERSION_CODES.M)   private fun startPaypal(context: Activity, paypalOrderId: String){         PayPalCheckout.start(CreateOrder { createOrderActions -> createOrderActions.set(paypalOrderId) }, null, null,             OnCancel {//实测取消订单后没走这个方法,走到了报错,报的returnUrl是空,但我们再paypal后台和sdk初始化均设置了的,而且在手机浏览器登录paypal买家账号后也是可以拉回我们app的,但是它还是会报这个错,无语子,估计还是paypal得bug                 resetCheckPaypalOrder()                 System.out.println("用户取消Paypal支付")             },             OnError { errorInfo ->                 resetCheckPaypalOrder()                 System.out.println("==========paypal onError=======ErrorInfo=======>: $errorInfo")                 System.out.println(if(errorInfo?.reason.isNullOrBlank()) (if(errorInfo?.error?.message.isNullOrBlank())                     "Paypal支付未知错误" else errorInfo.error.message) else errorInfo!!.reason)             })         checkOrderCount = 0         isCheckOrderFlag = true         startCheckPaypalOrder(context, paypalOrderId)     }     private fun startCheckPaypalOrder(context: Activity, paypalOrderId: String){         System.out.println("======Stephen=======checkPaypalOrder====>Count:$checkOrderCount")         if(!isCheckOrderFlag)return         if(checkOrderCount >= checkOrderMax){             resetCheckPaypalOrder()             System.out.println("Paypal订单支付等待超时")             return         }//end of if         ApiRequestMethod.checkPaypalOrder(paypalOrderId, object : RequestAllCallback<String> {//这个是我们接口调用封装方法,换成你们自己的哈(REST v2订单详情接口:https://developer.paypal.com/api/orders/v2/#orders_get)             override fun onSuccess(data: String?) {//接口返回正确json形如:{"paypal_status":"CREATED"}                 var isContinueLoop = true                 val jsonObject = ToolUtils.instance.fromJsonToObj(data)                 if(null != jsonObject && jsonObject.has("paypal_status")){                     when(jsonObject.getString("paypal_status")){                         "APPROVED" -> {//这个状态表示用户已经支付完成,后台开始捕获订单并开始执行确认了,实测这个状态有时差不多得持续1分多钟,快的话也是耗费20多秒,因此添加一个loading逻辑如下,此具体loading显示逻辑更换成你自己实际的loading框,注意loading框得依附在你自己App的当前支付界面上,因为你看到paypal的支付框实质是一个activity,依附在paypal上面会被误关闭                             if(!ToolUtils.instance.isLoadingShow())ToolUtils.instance.showLoading("确认支付结果中...", appendActivity = context)                         }                         "COMPLETED" -> {//这个状态表示后台捕获确认订单完成,也就是这笔订单真正的完成了                             isContinueLoop = false                             resetCheckPaypalOrder()                             System.out.println("Paypal订单支付成功")                         }                     }                 }//end of if                 if(isContinueLoop){                     ToolUtils.instance.delayExecute(1000L){//这个是我们延时调用封装方法,换成你们自己的哈                         checkOrderCount++                         startCheckPaypalOrder(context, paypalOrderId)                     }                 }//end of if             }             override fun onFailure(aliErrorResponse: AliErrorResponse, httpCode: Int): Boolean {                 ToolUtils.instance.delayExecute(1000L){                     checkOrderCount++                     startCheckPaypalOrder(context, paypalOrderId)                 }                 return false             }         })     }     private fun resetCheckPaypalOrder(){         checkOrderCount = 0         isCheckOrderFlag = false         ToolUtils.instance.closeLoading()//关闭loading框     } 复制代码

  • 4.说一下我们集成Server-side integration的代码遇到的问题

1).当开始支付时如果没有登录过Paypal买家账号或账号登录过期了,Sdk会拉起外部浏览器进行网页登录,登录成功后会通过returnUrl拉回业务App进行原生App的支付,然而有时又会直接就待在网页进行支付,支付完成后才会拉回业务App;更有情况登录操作是直接拉起的内部浏览器进行操作,具体原因均未可知,知道的铁子可评论区回复哈

2).官方文档写的:【Note: If you're integrating for the first time, we recommend using the REST v2 server-side integration. You must complete the first five steps in a Client-side integration.】,意思是服务端集成前面步骤和客户端集成一样,需要添加PayPal自带的支付按钮PayPalButton,然后调用payPalButton.setup()方法设置订单id,同时也可以覆盖OnApprove()回调方法;然而我实测发现,可以不用集成支付按钮PayPalButton,直接调用PayPalCheckout.start()方法设置订单id即可开启支付流程,只是最好不要去覆盖OnApprove()回调方法,因为这里执行it.orderActions.capture {  }捕获状态时,会报上下文异常:

com.paypal.checkout.order.OrderContextNotAvailableException: Tried to retrieve OrderContext before it was created.         at com.paypal.checkout.order.OrderContext$Companion.get(OrderContext.kt:27)         at com.paypal.checkout.order.UpdateOrderStatusAction$execute$orderContext$1.invokeSuspend(UpdateOrderStatusAction.kt:28)         at com.paypal.checkout.order.UpdateOrderStatusAction$execute$orderContext$1.invoke(Unknown Source:10)         at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:91)         at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:161)         at kotlinx.coroutines.BuildersKt.withContext(Unknown Source:1)         at com.paypal.checkout.order.UpdateOrderStatusAction.execute(UpdateOrderStatusAction.kt:27)         at com.paypal.checkout.order.CaptureOrderAction$execute$2.invokeSuspend(CaptureOrderAction.kt:21)         at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)         at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)         at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:571)         at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:738)         at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:678)         at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:665) 复制代码

因此我们的逻辑就是如上代码示例,当执行PayPalCheckout.start()方法开启支付时,同步开启一个定时器,循环去轮询paypal订单的状态,接口为REST v2订单详情,检测status是否是COMPLETED支付成功了

3).还发现一个异常问题,当sdk拉起浏览器登录paypal账号或支付时,此时从最近任务列表切换回app,app会回调到OnError方法里面,此时我们的业务支付流程已经结束了,但如果此时任然回浏览器完成paypal的支付,支付完成拉回业务app时,app会被paypal的sdk搞崩溃,应该是支付服务被关闭导致的状态异常,再次无语子

2021-12-27 17:51:45.505 E/DEBUG: Back traces starts. 2021-12-27 17:51:45.509 E/DEBUG:     at com.paypal.openid.AuthorizationService.a(Unknown Source:9) 2021-12-27 17:51:45.507 E/DEBUG: java.lang.IllegalStateException: Service has been disposed and rendered inoperable 2021-12-27 17:51:45.510 E/DEBUG:     at com.paypal.openid.AuthorizationService.performTokenRequest(Unknown Source:0) 2021-12-27 17:51:45.509 E/DEBUG:     at com.paypal.openid.AuthorizationService.a(Unknown Source:9) 2021-12-27 17:51:45.511 E/DEBUG:     at com.paypal.openid.AuthorizationService.performTokenRequest(Unknown Source:2) 2021-12-27 17:51:45.510 E/DEBUG:     at com.paypal.openid.AuthorizationService.performTokenRequest(Unknown Source:0) 2021-12-27 17:51:45.513 E/DEBUG:     at com.paypal.authcore.authentication.Authenticator.a(Unknown Source:191) 2021-12-27 17:51:45.511 E/DEBUG:     at com.paypal.openid.AuthorizationService.performTokenRequest(Unknown Source:2) 2021-12-27 17:51:45.514 E/DEBUG:     at com.paypal.authcore.authentication.Authenticator.authenticateForAccessTokenWithDelegate(Unknown Source:86) 2021-12-27 17:51:45.513 E/DEBUG:     at com.paypal.authcore.authentication.Authenticator.a(Unknown Source:191) 2021-12-27 17:51:45.515 E/DEBUG:     at com.paypal.pyplcheckout.flavorauth.ThirdPartyAuth.getUserAccessToken(ThirdPartyAuth.java:149) 2021-12-27 17:51:45.514 E/DEBUG:     at com.paypal.authcore.authentication.Authenticator.authenticateForAccessTokenWithDelegate(Unknown Source:86) 2021-12-27 17:51:45.516 E/DEBUG:     at com.paypal.pyplcheckout.home.viewmodel.MainPaysheetViewModel.logInUser(MainPaysheetViewModel.java:1629) 2021-12-27 17:51:45.515 E/DEBUG:     at com.paypal.pyplcheckout.flavorauth.ThirdPartyAuth.getUserAccessToken(ThirdPartyAuth.java:149) 2021-12-27 17:51:45.517 E/DEBUG:     at com.paypal.pyplcheckout.home.viewmodel.MainPaysheetViewModel.$r8$lambda$u3bJQV5CM255mmoJkHAH5Y7Tgzs(Unknown Source:0) 2021-12-27 17:51:45.516 E/DEBUG:     at com.paypal.pyplcheckout.home.viewmodel.MainPaysheetViewModel.logInUser(MainPaysheetViewModel.java:1629) 2021-12-27 17:51:45.518 E/DEBUG:     at com.paypal.pyplcheckout.home.viewmodel.MainPaysheetViewModel$$ExternalSyntheticLambda9.onUpdateClientConfig(Unknown Source:2) 2021-12-27 17:51:45.517 E/DEBUG:     at com.paypal.pyplcheckout.home.viewmodel.MainPaysheetViewModel.$r8$lambda$u3bJQV5CM255mmoJkHAH5Y7Tgzs(Unknown Source:0) 2021-12-27 17:51:45.519 V/nxoBaseCallback: https://www.paypal.com/xoplatform/logger/api/logger returned with response 2021-12-27 17:51:45.518 E/DEBUG:     at com.paypal.pyplcheckout.home.viewmodel.MainPaysheetViewModel$$ExternalSyntheticLambda9.onUpdateClientConfig(Unknown Source:2) 2021-12-27 17:51:45.520 E/DEBUG:     at com.paypal.pyplcheckout.home.viewmodel.MainPaysheetViewModel.lambda$updateClientConfigBefore$22(MainPaysheetViewModel.java:818) 2021-12-27 17:51:45.519 V/nxoBaseCallback: https://www.paypal.com/xoplatform/logger/api/logger returned with response 2021-12-27 17:51:45.521 E/DEBUG:     at com.paypal.pyplcheckout.home.viewmodel.MainPaysheetViewModel$$ExternalSyntheticLambda0.onEvent(Unknown Source:2) 2021-12-27 17:51:45.520 E/DEBUG:     at com.paypal.pyplcheckout.home.viewmodel.MainPaysheetViewModel.lambda$updateClientConfigBefore$22(MainPaysheetViewModel.java:818) 2021-12-27 17:51:45.522 E/DEBUG:     at com.paypal.pyplcheckout.events.Events.fire(Events.java:116) 2021-12-27 17:51:45.521 E/DEBUG:     at com.paypal.pyplcheckout.home.viewmodel.MainPaysheetViewModel$$ExternalSyntheticLambda0.onEvent(Unknown Source:2) 2021-12-27 17:51:45.523 E/DEBUG:     at com.paypal.pyplcheckout.services.callbacks.ClientConfigUpdateCallback.onApiSuccess(ClientConfigUpdateCallback.kt:54) 2021-12-27 17:51:45.522 E/DEBUG:     at com.paypal.pyplcheckout.events.Events.fire(Events.java:116) 2021-12-27 17:51:45.525 E/DEBUG:     at com.paypal.pyplcheckout.services.callbacks.BaseCallback.handleApiSuccess(BaseCallback.kt:114) 2021-12-27 17:51:45.523 E/DEBUG:     at com.paypal.pyplcheckout.services.callbacks.ClientConfigUpdateCallback.onApiSuccess(ClientConfigUpdateCallback.kt:54) 2021-12-27 17:51:45.526 E/DEBUG:     at com.paypal.pyplcheckout.services.callbacks.BaseCallback.onResponse(BaseCallback.kt:68) 2021-12-27 17:51:45.525 E/DEBUG:     at com.paypal.pyplcheckout.services.callbacks.BaseCallback.handleApiSuccess(BaseCallback.kt:114) 2021-12-27 17:51:45.527 V/nxoBaseCallback: https://www.paypal.com/xoplatform/logger/api/logger returned with response 2021-12-27 17:51:45.526 E/DEBUG:     at com.paypal.pyplcheckout.services.callbacks.BaseCallback.onResponse(BaseCallback.kt:68) 2021-12-27 17:51:45.527 E/DEBUG:     at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519) 2021-12-27 17:51:45.527 V/nxoBaseCallback: https://www.paypal.com/xoplatform/logger/api/logger returned with response 2021-12-27 17:51:45.529 E/DEBUG:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 2021-12-27 17:51:45.527 E/DEBUG:     at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519) 2021-12-27 17:51:45.530 E/DEBUG:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636) 2021-12-27 17:51:45.529 E/DEBUG:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162) 2021-12-27 17:51:45.531 E/DEBUG:     at java.lang.Thread.run(Thread.java:784) 复制代码

  • 5.以上操作Server-side integration集成就完成了,我再补上个参考TimberBug老哥和Paypal的Demo代码的Programmatically start the SDK客户端集成方式的测试代码以做备份:

  fun startPaypal(context: Activity){       if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {           PayPalCheckout.start(             createOrder = CreateOrder { actions ->                 val createdItems = listOf(CreatedItem("TestGoods", "1", "1", "0.1", ItemCategory.DIGITAL_GOODS))//参数依次:商品名称,数量,单价,税费,商品类型                 val shippingPreference = ShippingPreference.NO_SHIPPING //航运信息,非必须                 val currencyCode = CurrencyCode.USD //收款货币Code                 //以下为统一计算总数,避免出现不一致情况                 val itemTotal = createdItems.map { it.amount.toDouble() * it.quantity.toInt() }                     .sum().toBigDecimal().scaledForMoney                 val taxTotal = createdItems.map { it.taxAmount.toDouble() * it.quantity.toInt() }                     .sum().toBigDecimal().scaledForMoney                 val shippingTotal = BigDecimal(0.00).scaledForMoney                 val handlingTotal = BigDecimal(0.00).scaledForMoney                 val shippingDiscountTotal = BigDecimal(0.00).scaledForMoney                 val itemDiscountTotal = BigDecimal(0.00).scaledForMoney                 val totalValue = itemTotal.add(taxTotal).add(shippingTotal).add(handlingTotal).subtract(shippingDiscountTotal).subtract(itemDiscountTotal)                 actions.create(                     Order.Builder()                     .intent(OrderIntent.CAPTURE)                     .purchaseUnitList(listOf(PurchaseUnit.Builder()                             .referenceId(UUID.randomUUID().toString())//唯一id                             .amount(                                 Amount.Builder()                                     .currencyCode(currencyCode)                                     .value(totalValue.asMoneyString)                                     .breakdown(                                         BreakDown.Builder()                                             .itemTotal(itemTotal.unitAmountFor(currencyCode))                                             .shipping(shippingTotal.unitAmountFor(currencyCode))                                             .handling(handlingTotal.unitAmountFor(currencyCode))                                             .taxTotal(taxTotal.unitAmountFor(currencyCode))                                             .shippingDiscount(shippingDiscountTotal.unitAmountFor(currencyCode))                                             .discount(itemDiscountTotal.unitAmountFor(currencyCode))                                             .build())                                     .build())                             .items(                                 createdItems.map { createdItem ->                                     Items.Builder().name(createdItem.name)                                         .quantity(createdItem.quantity)                                         .category(createdItem.itemCategory)                                         .unitAmount(UnitAmount.Builder().value(createdItem.amount).currencyCode(currencyCode).build())                                         .tax(UnitAmount.Builder().value(createdItem.taxAmount).currencyCode(currencyCode).build()).build()                                 })                             .shipping(Shipping.Builder().address(Address.Builder()                                         .addressLine1("123 Townsend St")                                         .addressLine2("Floor 6")                                         .adminArea2("San Francisco")                                         .adminArea1("CA")                                         .postalCode("94107")                                         .countryCode("US")                                         .build()).options(null).build())//航运地址,非必须,Omitting shipping will default to the customer's default shipping address.                             .customId("CUSTOM-123")//The API caller-provided external ID. Used to reconcile API caller-initiated transactions with PayPal transactions. Appears in transaction and settlement reports.                             .description("Purchase from Orders Quick Start")                             .softDescriptor("800-123-1234")//The soft descriptor is the dynamic text used to construct the statement descriptor that appears on a payer's card statement.不太清楚有啥用                             .build() )                     ).appContext(                             AppContext.Builder().brandName("公司品牌,非必须")                                 .userAction(UserAction.PAY_NOW)                                 .shippingPreference(shippingPreference)                                 .build()                         ).build()){ id ->                             System.out.println("生成的订单ID: $id")                         }             },             onApprove = OnApprove { approval ->                 approval.orderActions.capture { result ->                     val message = when (result) {                         is CaptureOrderResult.Success -> {                             "Order Capture Succeeded"                         }                         is CaptureOrderResult.Error -> {                             "Order Capture Failed"                         }                     }                     System.out.println(message)                 }             },             onCancel = OnCancel {                 System.out.println("Buyer Cancelled Checkout")             },             onError = OnError { errorInfo ->                 System.out.println("An Error Occurred")             }         )       }else{           System.out.println("payPal支付失败,系统版本过低")       }     }     private fun BigDecimal.unitAmountFor(currencyCode: CurrencyCode): UnitAmount {         return UnitAmount.Builder().value(asMoneyString).currencyCode(currencyCode).build()     }     private val BigDecimal.asMoneyString: String         get() = DecimalFormat("#0.00").format(this)     private val BigDecimal.scaledForMoney: BigDecimal         get() = setScale(2, RoundingMode.HALF_UP)


作者:逆水寒本尊
链接:https://juejin.cn/post/7047036654254555166


文章分类
ANDROID
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐