最近面试了一家公司,是做跨境电商的,刚拿到 offer。在面试的时候聊到过,因为是做跨境电商的,面向的用户群体是美国欧洲的用户,所以在支付环节不使用支付宝/微信支付等国内产品,使用的是 paypal,所以提前研究一下并且先记录下来。
这里是 paypal iOS SDK 的 github 地址:https://github.com/paypal/PayPal-iOS-SDK
其实只要好好看这里的内容,很容易就能懂。
在 paypal 的世界里,他有多种支付方式:
大多数情况下我们只需要使用直接支付就好。以下也只谈直接支付,其他方式请自行查看文档。
当然,在支付之前,我们都需要去它的开发者网站进行开发者申请,创建 application 并获取 CLIENT_ID_FOR_PRODUCTION
和 CLIENT_ID_FOR_SANDBOX
。
OK,其实 paypal 只需要一个 client id 来确认你的 App,那么为什么有 production 和 sandbox 两个呢?
在 iOS 下,paypal 的支付流程可谓是简单,比起支付宝的等,开发者不需要很多复杂的操作,比如密钥什么的,这个最讨厌。你只需要使用 paypal SDK 创建好支付的内容,然后跳转到 paypal SDK 提供的 PayPalPaymentViewController,然后用户去完成支付就 OK 了,也不需要用户安装 paypal。接着你用代理来监控用户是不是支付成功,或者失败,并且及时通知你的服务器。
如果你用 cocoapods 来管理你的三方库,那么你只需要以下两行代码:
platform :ios, '6.0'
pod 'PayPal-iOS-SDK'
如果你不使用 cocoapods,那么请看这里。
下面不管你有没有使用 cocoapods,都需要给 URL Scheme 里面加以下几行:
com.paypal.ppclient.touch.v1
com.paypal.ppclient.touch.v2
org-appextension-feature-password-management
在文档里面还说了,要添加开源的允许证书,不过怎么弄还没研究过,看了一下,好像不太影响使用,后面研究明白了再加上来 ?????????
在这里标记一下。
首先这里是直接支付 (single payment) 的文档。
当然你还以选择提供给 paypal 一个邮寄地址,paypal 会保存下来这个地址。
初始化 SDK,需要你提供 client ID,这个过程在 AppDelegate.m 里面实现。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...
[PayPalMobile initializeWithClientIdsForEnvironments:@{PayPalEnvironmentProduction : @"YOUR_CLIENT_ID_FOR_PRODUCTION",
PayPalEnvironmentSandbox : @"YOUR_CLIENT_ID_FOR_SANDBOX"}];
// ...
return YES;
}
在你的结算页面添加代理
// SomeViewController.h
#import "PayPalMobile.h"
@interface SomeViewController : UIViewController<PayPalPaymentDelegate>
// ...
@end
创建一个 PayPalConfiguration
对象,这个对象将表示在这个页面的支付类型、展示语言、是否可用信用卡、商户名称等。
// SomeViewController.m
@interface SomeViewController ()
// ...
@property (nonatomic, strong, readwrite) PayPalConfiguration *payPalConfiguration;
// ...
@end
@implementation SomeViewController
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
_payPalConfiguration = [[PayPalConfiguration alloc] init];
// See PayPalConfiguration.h for details and default values.
// Should you wish to change any of the values, you can do so here.
// For example, if you wish to accept PayPal but not payment card payments, then add:
_payPalConfiguration.acceptCreditCards = NO;
// Or if you wish to have the user choose a Shipping Address from those already
// associated with the user's PayPal account, then add:
_payPalConfiguration.payPalShippingAddressOption = PayPalShippingAddressOptionPayPal;
}
return self;
}
建立支付环境,然后和 paypal 服务器进行预连接。建议是在这个页面初始化的时候就建立预连接,但是最好不要直接建立连接,因为这个连接是有时间限制的。
// SomeViewController.m
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Start out working with the test environment! When you are ready, switch to PayPalEnvironmentProduction.
[PayPalMobile preconnectWithEnvironment:PayPalEnvironmentNoNetwork];
}
创建 PayPalPayment
对象,它必须要设置:价格、汇率代码、简介、交易意图(sale、order、authorize),当然包括可选属性:发票号和邮寄地址。
// SomeViewController.m
- (IBAction)pay {
// Create a PayPalPayment
PayPalPayment *payment = [[PayPalPayment alloc] init];
// Amount, currency, and description
payment.amount = [[NSDecimalNumber alloc] initWithString:@"39.95"];
payment.currencyCode = @"USD";
payment.shortDescription = @"Awesome saws";
// Use the intent property to indicate that this is a "sale" payment,
// meaning combined Authorization + Capture.
// To perform Authorization only, and defer Capture to your server,
// use PayPalPaymentIntentAuthorize.
// To place an Order, and defer both Authorization and Capture to
// your server, use PayPalPaymentIntentOrder.
// (PayPalPaymentIntentOrder is valid only for PayPal payments, not credit card payments.)
payment.intent = PayPalPaymentIntentSale;
// If your app collects Shipping Address information from the customer,
// or already stores that information on your server, you may provide it here.
payment.shippingAddress = address; // a previously-created PayPalShippingAddress object
// Several other optional fields that you can set here are documented in PayPalPayment.h,
// including paymentDetails, items, invoiceNumber, custom, softDescriptor, etc.
// Check whether payment is processable.
if (!payment.processable) {
// If, for example, the amount was negative or the shortDescription was empty, then
// this payment would not be processable. You would want to handle that here.
}
// continued below...
创建然后展示 PayPalPaymentViewController
页面,使用之前创建好的 PayPalPayment
和 PayPalConfiguration
。
// Create a PayPalPaymentViewController.
PayPalPaymentViewController *paymentViewController;
paymentViewController = [[PayPalPaymentViewController alloc] initWithPayment:payment
configuration:self.payPalConfiguration
delegate:self];
// Present the PayPalPaymentViewController.
[self presentViewController:paymentViewController animated:YES completion:nil];
当然不要少了代理方法的监听。
// SomeViewController.m
#pragma mark - PayPalPaymentDelegate methods
- (void)payPalPaymentViewController:(PayPalPaymentViewController *)paymentViewController
didCompletePayment:(PayPalPayment *)completedPayment {
// Payment was processed successfully; send to server for verification and fulfillment.
[self verifyCompletedPayment:completedPayment];
// Dismiss the PayPalPaymentViewController.
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)payPalPaymentDidCancel:(PayPalPaymentViewController *)paymentViewController {
// The payment was canceled; dismiss the PayPalPaymentViewController.
[self dismissViewControllerAnimated:YES completion:nil];
}
给你的服务器发送支付成功、支付失败等信息请求。
// SomeViewController.m
- (void)verifyCompletedPayment:(PayPalPayment *)completedPayment {
// Send the entire confirmation dictionary
NSData *confirmation = [NSJSONSerialization dataWithJSONObject:completedPayment.confirmation
options:0
error:nil];
// Send confirmation to your server; your server should verify the proof of payment
// and give the user their goods or services. If the server is not reachable, save
// the confirmation and try again later.
}
别被骗了,如果是直接支付,一定要确认一下支付的证明。这一步骤应该是服务器来确定。服务器需要将你收到的支付 id 给 paypal 进行验证。