开始
本篇仅为我个人的Flutter Paypal 支付接入历程整理及记录,有些许的凌乱~
一开始接到这个需求,我心里想的是:Paypal支付是什么鬼,都没用过,想必接入文档有点难找吧。第一时间就去度娘求证,果不其然,寥寥无几的几篇介绍,甚至都有些年份了...
建议接入PayPal前,一定要了解Payay的支付流程有两种,分别是 Client-side integration
和 Server-side integration ,我就因为一开始没有了解就去撸代码吃了不少苦头,后面发现和服务端接入的不是同一个流程,白干了!!!。按我的理解,简单的说说这个两流程吧。
Client-side integration :
(1)用户点击购买商品,客户端携带商品信息向 PayPal 服务器发起支付请求;
(2)PayPal 服务器收到支付请求,处理后将结果返回客户端;
(3)客户端收到 PayPal 服务器返回的支付结果,将其发送给商家服务器端;
(4)商家服务器等待 PayPal 的异步消息通知(IPN 或者Webhooks),一般异步消息通知会有一段时间的延迟,通常在几分钟内;
(5)商家服务器收到PayPal 服务器端的支付结果;
(6)商家服务器验证本次支付,得到支付结果,将其返回客户端,本次支付结束;
Server-side integration:
(1)用户点击购买商品,客户端携带商品信息向商家服务器端发起支付请求;
(2)商家服务器端收到客户端支付请求,整理订单信息后向 PayPal 服务器端发起支付请求,商家服务器端收到PayPal 服务器生成的OrderId,将其返回客户端;
(3)客户端收到商家服务器端返回的OrderId,将其发送PayPal 服务器端,调起支付界面,用户进行支付操作;
(4)客户端收到PayPal 服务器端的支付结果,并将结果回传给商家服务器端请求验证;
(5)商家服务器端收到客户端的支付结果,将OrderId发送PayPal 服务器端请求验证;;
(6)商家服务器收到PayPal 验证结果,并将其返回客户端,本次支付结束;
从这两种方式看,很明显Server-side integration更有主动性,更利于后端服务器的业务逻辑处理,Client-side integration 的缺陷是,存在掉单的可能。
写到这里我想起来网上通篇一律讲解的都是Client-side integration方式,包括Flutter插件市场pub.dev封装好的插件也没有一个适合我的业务流程,而我们选用了第二种Server-side integration,于是我接下来专门记录一下这个方式的接入历程。
先去PayPal Developer 找找接入文档,好家伙!都是英文介绍,耐心点看吧,毕竟人家在国外是非常受欢迎的支付方式,地位可以说是相当于在国内的Alipay了。
注意:我们移动客户端大多时候是需要自定义UI的,要记得如下图切换选项。
安卓端接入
在根目录下的build.gradle文件中添加如下代码
allprojects {
repositories {
google()
mavenCentral()
....
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"
}
}
}
}
在app目录下的build.gradle文件添加
android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
defaultConfig {
// You must have a minSdkVersion of API 21
//(Android 5.0 Lollipop) or later.
minSdkVersion 21
...
}
}
dependencies {
...
implementation('com.paypal.checkout:android-sdk:1.2.0')
}
在app->src->main->AndroidManifest.xml清单文件中添加
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
...
</manifest>
清单添加 tools:replace="android:label"
<application
xmlns:tools="http://schemas.android.com/tools"
tools:replace="android:allowBackup, android:label" android:allowBackup="false"
清单修改 .MainActivity为全路径了:
<activity
android:name="com.example.xxxxx.MainActivity"
清单添加定位权限
<!-- 允许访问大概地理位置-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
在main目录下的MainActivity.kt添加下面代码,调用安卓的Paypal SDK ,然后和flutter通过通道交互
package com.example.xxxxx
import android.app.Application
import android.os.Bundle
import android.widget.Toast
import androidx.annotation.NonNull
import com.xxx.xxx.BuildConfig //包名.BuildConfig
import com.paypal.checkout.PayPalCheckout
import com.paypal.checkout.PayPalCheckout.registerCallbacks
import com.paypal.checkout.PayPalCheckout.setConfig
import com.paypal.checkout.PayPalCheckout.startCheckout
import com.paypal.checkout.approve.Approval
import com.paypal.checkout.approve.OnApprove
import com.paypal.checkout.cancel.OnCancel
import com.paypal.checkout.config.CheckoutConfig
import com.paypal.checkout.config.Environment
import com.paypal.checkout.config.SettingsConfig
import com.paypal.checkout.createorder.CreateOrder
import com.paypal.checkout.createorder.CreateOrderActions
import com.paypal.checkout.createorder.CurrencyCode
import com.paypal.checkout.createorder.UserAction
import com.paypal.checkout.error.ErrorInfo
import com.paypal.checkout.error.OnError
import com.paypal.checkout.shipping.OnShippingChange
import com.paypal.checkout.shipping.ShippingChangeActions
import com.paypal.checkout.shipping.ShippingChangeData
import io.flutter.embedding.android.FlutterFragmentActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugins.GeneratedPluginRegistrant
class MainActivity: FlutterFragmentActivity() {
// flutter 原生交互关键词
companion object {
private const val CHANNEL = "PaypalSDKChanel"
private const val MakeOrder = "MakeOrder"
private const val InitPaypalSDK = "InitPaypalSDK"
private const val PaypalOnApprove = "PaypalOnApprove"
private const val PaypalOnCancel = "PaypalOnCancel"
private const val PaypalOnError = "PaypalOnError"
}
var channel: MethodChannel? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun configureFlutterEngine(@NonNull flutterEn