iOS项目中接入PayPal支付

最近一个项目要做的是国际化版本的,其中有商城的功能,所以需要接入PayPal支付,接入的时候发现流程还是很简单的,这里做一下简单的记录。

首先这里是PayPal的iOS SDK的地址

开始接入

这里我们略过在开发者网站申请的流程,直接使用cocoapods命令行导入了到项目中。在开发者中心需要获取到CLIENT_ID_FOR_PRODUCTIONCLIENT_ID_FOR_SANDBOX,这两个参数是我们上线和沙盒测试的时候需要用到的两个参数。并且使用这个client ID 来找到你的APP。

1.导入SDK

我使用的cocoapods管理第三方库的 所以命令如下

1
2
platform :ios, '8.0'
pod 'PayPal-iOS-SDK'

导入到项目中后 我们要在AppDelegate中配置简单的参数

1
2
3
4
5
6
7
8
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...
[PayPalMobile initializeWithClientIdsForEnvironments:@{PayPalEnvironmentProduction : @"YOUR_CLIENT_ID_FOR_PRODUCTION",
PayPalEnvironmentSandbox : @"YOUR_CLIENT_ID_FOR_SANDBOX"}];
// ...
return YES;
}

然后需要我们在需要接入支付的页面导入相关的类

1
2
3
4
5
6
// SomeViewController.h
#import "PayPalMobile.h"

@interface SomeViewController : UIViewController<PayPalPaymentDelegate>
// ...
@end

并且创建一个具体的配置的参数的对象,设置支付的类型,展示的语言,和信用卡、商户名称等配置参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 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];
_paypalCOnfiguration.merchantName = @"山东蓝翔挖掘机学院";//公司名称
_paypalCOnfiguration.acceptCreditCards = NO;//不支持信用卡
_paypalCOnfiguration.merchantPrivacyPolicyURL = [NSURL URLWithString:@"https://www.paypal.com/webapps/mpp/ua/privacy-full"];
_paypalCOnfiguration.merchantUserAgreementURL = [NSURL URLWithString:@"https://www.paypal.com/webapps/mpp/ua/useragreement-full"];
_paypalCOnfiguration.payPalShippingAddressOption = PayPalShippingAddressOptionPayPal;
_paypalCOnfiguration.languageOrLocale = [NSString getPreferredLanguage];
}
return self;
}

下面是我获取当前系统的语言的代码,即上面的[NSString getPreferredLanguage]方法

1
2
3
4
5
6
7
8
/**  *得到本机现在用的语言  * en:英文  zh-Hans:简体中文   zh-Hant:繁体中文    ja:日本  ......  */
+ (NSString*)getPreferredLanguage {
NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
NSArray* languages = [defs objectForKey:@"AppleLanguages"];
NSString* preferredLang = [languages objectAtIndex:0];
NSLog(@"Preferred Language:%@", preferredLang);
return preferredLang;
}

设置支付的环境,这里PayPal提供了三种的环境,分别是PayPalEnvironmentProductionPayPalEnvironmentSandboxPayPalEnvironmentNoNetwork
在项目上线的时候必须设置为第一种环境的,我们在测试的时候可以设置为下面的两种方式,第二种方式就是沙盒环境下,第三种在我看来就是随便支付就可以成功的环境,我也使用这种方式进行了测试,跟第二种方式没有感觉出什么明显的区别,若哪位大大有了解的欢迎指点迷津。

这里需要在页面出来的时候设置这个参数

1
2
3
4
5
6
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];

// Start out working with the test environment! When you are ready, switch to PayPalEnvironmentProduction.
[PayPalMobile preconnectWithEnvironment:PayPalEnvironmentNoNetwork];
}

接下来就是我们支付的方法了 从我们服务器获取需要传入的参数,金额,商品描述,货币的币种代码,交易类型,这里还有一个预留字段是custom 可以将我们需要的参数传入,具体的代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//amount:金额
//currencyCode:获取单位 比如:USD
//shortDescription:商品标题 简短描述
- (void)PayPalWithAmount:(NSString *)amount theOrderString:(NSString *)orderString currencyCode:(NSString *)currencyCode shortDescription:(NSString *)shortDescription {
PayPalPayment *payment = [[PayPalPayment alloc] init];
payment.amount = [[NSDecimalNumber alloc] initWithString:amount];
payment.currencyCode = currencyCode;
payment.shortDescription = @"购买商品购买商品购买商品";
payment.custom = orderString;//订单号
payment.items = nil; // if not including multiple items, then leave payment.items as nil
payment.paymentDetails = nil; // if not including payment details, then leave payment.paymentDetails as nil
payment.intent = PayPalPaymentIntentSale;
if (!payment.processable) {
NSLog(@"-------------");
}
PayPalPaymentViewController *paymentViewController = [[PayPalPaymentViewController alloc] initWithPayment:payment configuration:self.paypalCOnfiguration delegate:self];

[self presentViewController:paymentViewController animated:YES completion:nil];
}

我们需要在代理方法中检测来处理我们需要进行的操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#pragma mark - PayPalPaymentDelegate methods

- (void)payPalPaymentViewController:(PayPalPaymentViewController *)paymentViewController didCompletePayment:(PayPalPayment *)completedPayment {
[self verifyCompletedPayment:completedPayment];
[self dismissViewControllerAnimated:YES completion:nil];
}

- (void)payPalPaymentDidCancel:(PayPalPaymentViewController *)paymentViewController {
NSLog(@"支付有错误 稍后重试");
[self dismissViewControllerAnimated:YES completion:nil];
}

- (void)verifyCompletedPayment:(PayPalPayment *)completedPayment {
// Send the entire confirmation dictionary
NSData *confirmation = [NSJSONSerialization dataWithJSONObject:completedPayment.confirmation options:0 error:nil];
NSLog(@"=================%@",completedPayment.confirmation);
NSLog(@"---------------------------------");
NSLog(@"==================%@",confirmation);
}

支付成功后,PayPal会返回给我们的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
"client":{
"environment":"sandbox",
"paypal_sdk_version":"2.0.0",
"platform":"iOS",
"product_name":"PayPal iOS SDK;"
},
"response":{
"create_time":"2014-02-12T22:29:49Z",
"id":"PAY-564191241M8701234KL57LXI",
"intent":"sale",
"state":"approved"
},
"response_type":"payment"
}

我们需要在获取到参数后 调用服务端的接口,校验我们的订单。一般都需要我们传入”id”:”PAY-564191241M8701234KL57LXI”,这个参数即可。

下面是官方的文档,大家也可以参考。

遇到的问题

这个SDK接入的过程中还是比较简单的,目前遇到的问题就是因为项目中设置了透明的导航条,而且PayPal的控制器又是直接封装好的,供我们直接调用的,所以在跳转过去后PayPal控制器内的界面的坐标会从最上方开始,就会挡住一部分UI界面。设置的透明的导航条会影响到UI界面的坐标,这里我们的解决方法就是在跳转完成后设置paymentViewController.navigationBar.translucent = NO;,这样就可以解决这个问题。

这次的接入的流程,大致就是这样的,如有分享的不对的地方,欢迎各位大大的指正。