PayME SDK 是一套库,允许应用程序与 PayME 平台交互。PayME SDK 包括以下主要功能:
- PayME 钱包账户的登录和管理
- 支持应用程序获取 PayME 钱包的余额信息
- 从 PayME 钱包中充值和提现的功能。
一些术语解释:
名称 | 解释 | |
---|---|---|
1 | app | 它是 iOS/Android 移动应用程序或 Web 应用程序,将 SDK 集成进来以实现 PayME 钱包的支付功能。 |
2 | SDK | 它是支持应用程序集成 PayME 钱包的一套工具。 |
3 | backend | 它是支持应用程序、服务器或 API 的一套集成系统。 |
4 | AES | AES256 PKCS5 数据加密函数。 查看 |
5 | RSA | 数据加密 RSA 算法。 |
6 | IPN | Instant Payment Notification,用于在应用程序后端和 PayME 后端之间通信。 |
安装方法
PayMESDK 存储在 CocoaPods 平台上。要安装,只需在 Podfile 中添加以下行
pod 'PayMESDK'
然后运行 pod install
命令以完成安装
Info.plist
请更新应用程序的 Info.plist 文件,包括以下 key(字符串值可更改,这是请求用户授权时显示的消息)
<key > NSCameraUsageDescription </ key>
<string > Need to access your camera to capture a photo add and update profile picture .</ string>
<key > NSPhotoLibraryAddUsageDescription </ key>
<string > Need to access your library to add a photo or videoo off kyc video </ string>
<key > NSPhotoLibraryUsageDescription </ key>
<string > Need to access your photo library to select a photo add and update profile picture </ string>
<key > NSContactsUsageDescription </ key>
<string > Need to access your contact </ string>
如果没有使用联系人功能,则请在 podfile 的末尾添加
post_install do |installer|
installer.pods_project.targets.each do |target|
if target.name == 'PayMESDK'
target.build_configurations.each do |config|
config.build_settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] ||= '$(inherited)'
config.build_settings['SWIFT_ACTIVE_COMPILATION_CONDITIONS'] << 'IGNORE_CONTACT'
end
end
end
end
SDK 使用方法
PayME 系统将为集成的应用程序提供以下信息
- PublicKey:用于加密数据,应用程序整合需要传递给 SDK 以进行加密。
- AppToken:由 AppId 独立定制的标识符,应用于每个应用程序,需要传递给 SDK 以进行加密。
- SecretKey : 适用于在集成应用中,为后端系统加密和验证数据的密钥。
应用端将向 PayME 系统提供以下信息
- AppPublicKey : 将通过 PayME 后端系统发送用于加密。 (不要传入 SDK 中)
- AppPrivateKey : 将传入 PayME SDK 以执行解密操作。
加密标准:RSA-512bit。可以使用以下工具生成 在此处
初始化 PayME SDK
在使用 PayME SDK 之前,需要一次性调用初始化方法来初始化 SDK。
let payme = PayME(appToken: "AppToken",
publicKey: "PublicKey",
connectToken: "ConnectToken",
appPrivateKey: "AppPrivateKey",
language: PayME.Language.VIETNAMESE,
configColor: ["#07A922"],
env: PayME.Env.SANDBOX
)
其中参数如下
-
appPrivateKey: 是根据上述方式自生成的应用私钥
-
publicKey: 是 PayME 为每个应用提供的公钥。
-
configColor : 用于改变 PayME 钱包交易颜色的参数,数据类型为字符串,格式为
rrggbb。如果传入 2 种颜色, PayME 的界面将根据传入的 2 种颜色渐变。
connectToken 的创建方法
connectToken 用于从 PayME 调用 API,并将由应用后端系统创建。其结构如下
connectToken = AES256("{ timestamp: "2021 - 01 - 20T06:53:07.621Z",
userId: "ABC",
phone: "0909998877" }"
+ secretKey )
参数 | 必填 | 解释 |
---|---|---|
** | ||
timestamp** | 是 | 表示 connectToken 创建时间的时间戳,按照 iSO 8601 格式,用于确定 connectToken 的超时时间。例如 2021-01-20T06:53:07.621Z |
*** | ||
userId*** | 是 | 是每个客户的唯一值,通常由被集成系统的服务器提供。 |
*** | ||
phone*** | 是 | 是集成系统的电话号码,如果系统不使用电话号码,可以不传或传 null。 |
其中 AES 是根据 AES 算法进行加密。根据服务器使用的编程语言,系统使用相应的库。更多信息请参阅此处
包含 KYC 信息 的 connectToken 的创建方法(适用于有 KYC 系统的合作伙伴)
// example
connectToken = AES256("{
userId: "ABC",
phone: "0909998877",
timestamp: "2021-01-20T06:53:07.621Z",
kycInfo: {
{
fullname: "Nguyen Van A",
gender: "MALE",
birthday: "1995-01-20T06:53:07.621Z",
address: "1 Nguyen Co Thach",
identifyType: "CMND",
identifyNumber: "123456789",
issuedAt: "2012-01-20T06:53:07.621Z",
placeOfIssue: "Hai Duong",
video: "https://..../202/Co-29vnK6.mp4",
face: "https://.../photo/2015/04/_480.jpg",
image: {
front: "https://.../photo/2015/04/_480.jpg",
back: "https://.../photo/2015/04/_480.jpg",
}
}
}
}" + secretKey )
kycInfo
参数
参数 | 必填 | 解释 |
---|---|---|
fullname | 是 | 全名 |
gender | 是 | 性别(MALE/FEMALE) |
address | 是 | 地址 |
identifyType | 是 | 证件类型(CMND/CCCD) |
identifyNumber | 是 | 证件号 |
issuedAt | 是 | 注册日期 |
placeOfIssue | 是 | 颁发机构 |
video | 否 | 视频链接 |
face | 否 | 面部照片链接 |
front | 否 | 证件正面照片链接 |
back | 否 | 证件背面照片链接 |
PayME SDK 错误码
常量 | 错误码 | 解释 |
---|---|---|
EXPIRED |
401 |
token 已过期 |
DEACTIVATED_ACCOUNT |
405 |
账户已被禁用 |
NETWORK |
-1 |
网络连接出错 |
SYSTEM |
-2 |
系统错误 |
LIMIT |
-3 |
余额不足,无法执行交易 |
ACCOUNT_NOT_ACTIVATED |
-4 |
错误:账户未激活 |
ACCOUNT_NOT_KYC |
-5 |
错误:账户未进行身份验证 |
PAYMENT_ERROR |
-6 |
支付失败 |
ERROR_KEY_ENCODE |
-7 |
错误:数据加密/解密失败 |
USER_CANCELLED |
-8 |
用户操作已取消 |
ACCOUNT_NOT_LOGIN |
-9 |
错误:未登录账户 |
PAYMENT_PENDING |
-11 |
支付正在处理中 |
ACCOUNT_ERROR |
-12 |
错误:账户被锁定 |
PayME SDK 功能
login()
包含两种情况
- 用于在首次初始化
PayME
后进行登录。 - 当
accessToken
过期,调用 SDK 函数返回代码错误ResponseCode.EXPIRED 或 ResponseCode.DEACTIVATED_ACCOUNT
时,此时 app 需要再次调用login
以获取用于其他功能的accessToken
。
成功调用 login()
后,才能调用 SDK 的其他功能(openWallet
, pay
等)
public func login(
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
登录成功后,将返回一个包含以下信息的枚举 KYCState
public enum KYCState {
case NOT_ACTIVATED
case NOT_KYC
case KYC_APPROVED
}
一些功能,如充值、提现、支付,只有在激活钱包并通过身份验证后才能执行。也就是说,登录将返回枚举 KYCState
,其 case 为 KYC_APPROVED
。
logout()
public func logout()
用于从 SDK 会话中登出
close() - Đóng SDK
该函数用于在 pay()
或 openWallet()
执行期间集成应用关闭 SDK 的 UI。
public func close() -> ()
openWallet() - Mở UI chức năng PayME tổng hợp
public func openWallet(
currentVC: UIViewController,
action: Action,
amount: Int?,
description: String?,
extraData: String?,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
其中 enum Action 包含
enum Action: String {
case OPEN = "OPEN"
case DEPOSIT = "DEPOSIT"
case WITHDRAW = "WITHDRAW"
case TRANSFER = "TRANSFER"
}
当应用集成调用 PayME 的一项功能时,会通过传入上面的 Action
参数来调用该函数。
参数
| 参数 | 必填 | 说明 | | :----------------------------------------------------------- | :----------- | : ----------------------------------------------------------- | | currentVC
| 是 | PayME SDK 将据此打开 PayME 界面的 ViewController。 | | action
| 是 |
- OPEN : 用于打开 PayME WebView 界面,不执行任何特殊操作。
- DEPOSIT: 用于打开 PayME 界面并执行 PayME 充值功能,PayME 将在界面显示成功或失败的消息。此外,如果需要,也会将结果返回给集成应用以便在应用中显示和处理。
- WITHDRAW: 用于打开 PayME 界面并执行 PayME 提款功能,PayME 将在界面显示成功或失败的消息。此外,如果需要,也会将结果返回给集成应用以便在应用中显示和处理。
amount
| 否 | 在 action 为 Deposit/Withdraw 时传入金额 | | description
| 否 | 如果有,传入交易的描述 | | extraData
| 否 | 在执行 Deposit 或 Withdraw 时,集成应用需要传递其他数据,以便 PayME 后端可以反向调用集成应用的后端。例如:交易的 transactionID 或应用集成所需的其他数据。 | | onSuccess
| 是 | 用于捕获 PayME SDK 成功执行交易时的回调 | | onError
| 是 | 用以捕获在调用 PayME SDK 过程中出现的错误 |
例子
import PayMESDK
class ViewController: UIViewController {
let payME: PayME
@IBAction func click(_ sender: Any) {
payME.openWallet(
currentVC: self,
action: Action.OPEN,
amount: nil,
description: nil,
extraData: nil
)
}
override func viewDidLoad() {
super.viewDidLoad()
payME = PayME(
appID: appID,
publicKey: self.PUBLIC_KEY,
connectToken: self.connectToken,
appPrivateKey: self.PRIVATE_KEY,
env: currentEnv,
configColor: ["#75255b", "#a81308"]
)
}
}
deposit() - Nạp tiền
public func deposit(
currentVC: UIViewController,
amount: Int?,
description: String?,
extraData: String?,
closeWhenDone: Bool = false,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
此函数的含义等同于调用 openWallet
并传入 Action.DEPOSIT
动作。
| 参数 | 默认值 | 说明 | | :----------------------------------------------------------- | :----------- | : ----------------------------------------------------------- | | closeWhenDone
| false
| true
: 交易完成后关闭 SDK |
withdraw() - Rút tiền
public func withdraw(
currentVC: UIViewController,
amount: Int?,
description: String?,
extraData: String?,
closeWhenDone: Bool = false,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
此函数的含义等同于调用 openWallet
并传入 Action.WITHDRAW
动作。
| 参数 | 默认值 | 说明 | | :----------------------------------------------------------- | :----------- | : ----------------------------------------------------------- | | closeWhenDone
| false
| true
: 交易完成后关闭 SDK |
transfer() - Chuyển tiền
public func transfer(
currentVC: UIViewController,
amount: Int?,
description: String?,
extraData: String?,
closeWhenDone: Bool = false,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
此函数的含义等同于调用 openWallet
并传入 Action.TRANSFER
动作。
| 参数 | 默认值 | 说明 | | :----------------------------------------------------------- | :----------- | : ----------------------------------------------------------- | | closeWhenDone
| false
| true
: 交易完成后关闭 SDK |
openHistory() - Mở lịch sử giao dịch
public func openHistory(
currentVC: UIViewController,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
此函数的含义等同于调用 openWallet
并传入 Action.OPEN_HISTORY
动作。
pay() - Thanh toán
当应用需要从激活的 PayME 钱包支付一笔钱时使用此函数。
public func pay(
currentVC: UIViewController,
storeId: Int,
orderId: Int,
amount: Int,
note: String?,
paymentMethodID: Int?,
extraData: String?,
isShowResultUI: Bool = true,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
| 参数 | 必填 | 说明 | | : ----------------------------------------------------------- | :----------- | : ----------------------------------------------------------- | | currentVC
| 是 | PayME SDK 依赖的 ViewController,用于打开 PayME 界面。 | | amount
| 是 | 应用程序通过 SDK 传入的支付金额 | | extraData
| 是 | 实施支付时,如果需要,应用程序应传入其他数据,以便 PayME 后端系统可以 IPN 回集成的后端系统。例如:交易 ID 或任何必要的数据。 | | storeId
| 是 | 执行支付交易的收款方的 ID | | orderId
| 是 | 对手的交易码,每个交易必须是唯一的(最多 22 个字符) | | note
| 否 | 对手方的交易描述 | | isShowResultUI
| 否 | 默认值为 true
,表示在支付结果发生时将显示成功或失败界面。当传递值为 false 时,将不会显示成功或失败界面。 | | onSuccess
| 是 | 成功时返回结果的回调 | | onError
| 是 | 失败时返回结果的回调 |
若集成应用需要取余额以在 UI 上显示,则可使用 getWalletInfo%
函数,此函数不显示 PayME SDK 的 UI。
- 使用 PayME 钱包支付时,需要已激活的账户,已验证的识别和钱包中的余额必须大于支付金额。
- 通过
getAccountInfo%
函数获取账户信息。 - 通过
getWalletInfo%
函数获取余额信息。
public func pay(
currentVC: UIViewController,
storeId: Int?,
userName: String?,
orderId: Int,
amount: Int,
note: String?,
payCode: String,
extraData: String?,
isShowResultUI: Bool = true,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
| 参数 | 必填 | 值 | | : ----------------------------------------------------------- | :----------- | : ----------------------------------------------------------- | | payCode
| 是 | 支付方式列表 | | userName
| 否 | 用户名 | | storeId
| 否 | 执行交易的收款方的 ID |
注意:只有 userName 或 storeId,如果使用 userName,则将 storeId 设置为 nil,反之亦然。
scanQR() - 打开扫描 QR 码支付的功能
public func scanQR(
currentVC: UIViewController,
payCode: String,
onSuccess: @escaping (Dictionary<String, AnyObject>) -> (),
onError: @escaping (Dictionary<String, AnyObject>) -> ()
) -> ()
QR 码格式
let qrString = "{$type}|${storeId?}|${action}|${amount}|${note}|${orderId}|${userName?}"
例子
let qrString = "OPENEWALLET|54938607|PAYMENT|20000|Chuyentien|2445562323|DEMO)"
- action: 交易类型('PAYMENT' => 支付)
- amount: 支付金额
- note: 对手方的交易描述
- orderId: 对手的交易码,每个交易必须是唯一的
- storeId: 执行交易的收款方的 ID
- type:
OPENEWALLET
payQRCode() - 使用 QR 码进行支付
public func payQRCode(
currentVC: UIViewController,
qr: String,
payCode: String,
isShowResultUI: Bool,
onSuccess: @escaping (Dictionary<String, AnyObject>) -> (),
onError: @escaping (Dictionary<String, AnyObject>) -> ()
) -> ()
- qr: 进行支付用的 QR 码(格式与
scanQR%
函数相同) - isShowResultUI: 是否显示交易结果UI
openKYC() - 打开账户详情模态框
当集成应用需要打开账户详情模态框(要求账户尚未实名认证)时,此函数会被调用
public func openKYC(
currentVC: UIViewController,
onSuccess: ([Dictionary<String, AnyObject>]) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
getWalletInfo() - 获取钱包信息
public func getWalletInfo(
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
-
在出错情况下,此函数会在
onError
函数中返回错误信息,此时应用可以显示balance
为0。 -
在成功情况下,SDK会返回以下信息
{
"walletBalance": {
"balance": 111,
"detail": {
"cash": 1,
"lockCash": 2
}
}
}
balance : 集成应用可以从中使用balance键值显示,其他字段目前尚未使用。
detail.cash : 可用金额
detail.lockCash: 锁定金额
getAccountInfo()
在SDK初始化完成后,应用可以使用此功能来获取与PayME钱包的连接状态。
public func getAccountInfo(
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
getSupportedServices()
用来确定SDK可以用来支付的服务(如电费、水费、学费等)。
public func getSupportedServices(
onSuccess: ([ServiceConfig]) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
class ServiceConfig {
...
public func getCode() -> String
public func getDescription() -> String
...
}
openService()
打开Web SDK进行服务支付
public func openService(
currentVC: UIViewController,
amount: Int?,
description: String?,
extraData: String?,
service: ServiceConfig,
onSuccess: (Dictionary<String, AnyObject>) -> (),
onError: (Dictionary<String, AnyObject>) -> ()
) -> ()
setLanguage()
切换sdk的语言
public func setLanguage(language: PayME.Language) -> ()
getRemainingQuota()
获取支付交易限额
public func getRemainingQuota(
onSuccess: @escaping (Int) -> (),
onError: @escaping (Dictionary<String, AnyObject>) -> ()
) -> ()
支付方式列表
payCode | 支付方式 |
---|---|
PAYME | 将通过PayME钱包支付 |
ATM | 国内ATM支付 |
MANUAL_BANK | 银行转账支付 |
CREDIT | 信用卡支付 |
VIET_QR | 通过VietQR支付 |