支付宝集成中爬过的一系列坑

支付宝最近更新了sdk,一切都按照支付宝的要求集成。

App支付iOS集成流程

导入代码

步骤1:启动IDE(如Xcode),把iOS包中的压缩文件中以下文件拷贝到项目文件夹下,并导入到项目工程中。

AlipaySDK.bundle
AlipaySDK.framework

在Build Phases选项卡的Link Binary With Libraries中,增加以下依赖:

其中,需要注意的是:

  • 如果是Xcode 7.0之后的版本,需要添加libc++.tbd、libz.tbd;
  • 如果是Xcode 7.0之前的版本,需要添加libc++.dylib、libz.dylib(如下图)。

 

步骤2:在需要调用AlipaySDK的文件中,增加头文件引用。

import <AlipaySDK/AlipaySDK.h>

步骤3:组装请求信息。

 

TIPS:这一步应在商户服务端完成,商户服务端直接将组装和签名后的请求串orderString传给客户端,客户端直接传给SDK发起请求。文档和Demo是为了示例效果在客户端实现。

 

//将商品信息赋予AlixPayOrder的成员变量
Order* order = [Order new];

// NOTE: app_id设置
order.app_id = appID;

// NOTE: 支付接口名称
order.method = @"alipay.trade.app.pay";

// NOTE: 参数编码格式
order.charset = @"utf-8";

// NOTE: 当前时间点
NSDateFormatter* formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
order.timestamp = [formatter stringFromDate:[NSDate date]];

// NOTE: 支付版本
order.version = @"1.0";

// NOTE: sign_type设置
order.sign_type = @"RSA";

// NOTE: 商品数据
order.biz_content = [BizContent new];
order.biz_content.body = @"我是测试数据";
order.biz_content.subject = @"1";
order.biz_content.out_trade_no = [self generateTradeNO]; //订单ID(由商家自行制定)
order.biz_content.timeout_express = @"30m"; //超时时间设置
order.biz_content.total_amount = [NSString stringWithFormat:@"%.2f", 0.01]; //商品价格

//将商品信息拼接成字符串
NSString *orderInfo = [order orderInfoEncoded:NO];
NSString *orderInfoEncoded = [order orderInfoEncoded:YES];
NSLog(@"orderSpec = %@",orderInfo);

// NOTE: 获取私钥并将商户信息签名,外部商户的加签过程请务必放在服务端,防止公私钥数据泄露;
//       需要遵循RSA签名规范,并将签名字符串base64编码和UrlEncode
id<DataSigner> signer = CreateRSADataSigner(privateKey);
NSString *signedString = [signer signString:orderInfo];

// NOTE: 如果加签成功,则继续执行支付
if (signedString != nil) {
    //应用注册scheme,在AliSDKDemo-Info.plist定义URL types
    NSString *appScheme = @"alisdkdemo";
    
    // NOTE: 将签名成功字符串格式化为订单字符串,请严格按照该格式
    NSString *orderString = [NSString stringWithFormat:@"%@&sign=%@",
                             orderInfoEncoded, signedString];
    
    // NOTE: 调用支付结果开始支付
    [[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
        NSLog(@"reslut = %@",resultDic);
    }];
}

 

详细可参见Demo中示例文件

  • AliSDKDemo\APViewController.h
  • AliSDKDemo\APViewController.m
  • AliSDKDemo\Order.h
  • AliSDKDemo\Order.m

步骤4:配置支付宝客户端返回url处理方法。

(外部存在支付包钱包,支付宝钱包将处理结果通过url返回。)

如示例AliSDKDemo\APAppDelegate.m文件中,增加引用代码:

import <AlipaySDK/AlipaySDK.h>

AppDelegate中以下代码中的NSLog改为实际业务处理代码:

- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    
    if ([url.host isEqualToString:@"safepay"]) {
        //跳转支付宝钱包进行支付,处理支付结果
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
            NSLog(@"result = %@",resultDic);
        }];
    }
    return YES;
}

// NOTE: 9.0以后使用新API接口
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
{
    if ([url.host isEqualToString:@"safepay"]) {
        //跳转支付宝钱包进行支付,处理支付结果
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
            NSLog(@"result = %@",resultDic);
        }];
    }
    return YES;
}

 

针对Demo的运行注意

1、关于签名代码问题

  • AliSDKDemo\Util及下面所有文件
  • AliSDKDemo\openssl及下面所有文件
  • libcrypto.a
  • libssl.a

这些文件是为示例签名所在客户端本地使用。实际场景下请商户把私钥保存在服务端,在服务端进行支付请求参数签名。

2、如果遇到运行后报错,类似于以下提示信息:

 

Cannot find interface declaration for 'NSObject', superclass of 'Base64'

那么需要打开报错了的文件,增加头文件。

# import <Foundation/Foundation.h>

3、如果商户要在某个文件中使用支付宝的开发包类库,需增加引用头文件。

# import <AlipaySDK/AlipaySDK.h>

4、点击项目名称,点击“Build Settings”选项卡,在搜索框中,以关键字“search”搜索,对“Header Search Paths”增加头文件路径:$(SRCROOT)。如果头文件信息已增加,可不必再增加。

/***************************/

(⚠️⚠️⚠️⚠️⚠️)

      IOS openssl/asn1.h file not found的解决方法

比如 我把openssl这个文件导入到了这个工程目录下 :项目名称/公共类/工具&第三方/支付宝SDK/openssl ,中间隔了三个文件夹,那么在Header Search Paths 的设置就得改为 $(SRCROOT)/项目名 称/公共类/工具&第三方/支付宝SDK,
问题就解决了再反过来看官方的demo,原来他们把openssl这个文件放到了项目根目录下,所以“Header Search Paths”只需要设置$(SRCROOT)/项目名称
/***************************/
 
 

6、点击项目名称,点击“Info”选项卡,在“URL Types”选项中,点击“+”,在“URL Schemes”中输入“alisdkdemo”。“alisdkdemo”来自于文件“APViewController.m”的NSString *appScheme = @"alisdkdemo";。

注意:这里的URL Schemes中输入的alisdkdemo,为测试demo,实际商户的app中要填写独立的scheme,建议跟商户的app有一定的标示度,要做到和其他的商户app不重复,否则可能会导致支付宝返回的结果无法正确跳回商户app。

 

配置基本信息

打开“APViewController.m”文件,对以下2个参数进行编辑。

NSString *appid = @"";
NSString *privateKey = @"";

iOS基本信息配置表:

参数含义
appid 应用ID,调用API时用来识别开发者。请参考创建应用并获取APPID
private_key 应用私钥,pkcs8格式。请参考配置密钥

注意:这些参数配置仅作为客户端示例使用。商户实际支付过程中参数需要放置在服务端,且整个签名过程必须在服务端进行

代码示例运行逻辑

步骤1:调用order.m里的函数description将商品信息拼接成字符串作为待签名字符串,如:

app_id=2015052600090779&biz_content={"timeout_express":"30m","seller_id":"","product_code":"QUICK_MSECURITY_PAY","total_amount":"0.02","subject":"1","body":"我是测试数据","out_trade_no":"ZQLM3O56MJD4SK3"}&charset=utf-8&method=alipay.trade.app.pay&sign_type=RSA2&timestamp=2016-07-28 20:36:11&version=1.0

步骤2:使用类CreateRSADataSigner,调用signString签名函数做签名,如:

"GsSZgPloF1vn52XAItRAldwQAbzIgkDyByCxMfTZG%2FMapRoyrNIJo4U1LUGjHp6gdBZ7U8jA1kljLPqkeGv8MZigd3kH25V0UK3Jc3C94Ngxm5S%2Fz5QsNr6wnqNY9sx%2Bw6DqNdEQnnks7PKvvU0zgsynip50lAhJmflmfHvp%2Bgk%3D"

步骤3:把签名结果赋值给参数sign,并把sign加入之前的待签名数组中,此时得到的便是要请求给支付宝的全部数据。

app_id=2015052600090779&biz_content={"timeout_express":"30m","seller_id":"","product_code":"QUICK_MSECURITY_PAY","total_amount":"0.02","subject":"1","body":"我是测试数据","out_trade_no":"ZQLM3O56MJD4SK3"}&charset=utf-8&method=alipay.trade.app.pay&sign_type=RSA2&timestamp=2016-07-28 20:36:11&version=1.0&sign=*

步骤4:调用(AlipaySDK *)defaultService类下面的支付接口函数,唤起支付宝支付页面。

(void)payOrder:(NSString *)orderStr
fromScheme:(NSString *)schemeStr
callback:(CompletionBlock)completionBlock

appScheme为app在info.plist注册的scheme。

步骤5:当这笔交易被买家支付成功后支付宝收银台上显示该笔交易成功,并提示用户“返回”。此时在APAppDelegate.m的 - (BOOL)application:(UIApplication )application openURL:(NSURL )url sourceApplication:(NSString )sourceApplication annotation:(id)annotation 中调用获取返回数据的代码【iOS9.0以上(包括iOS9.0)需要在 - (BOOL)application:(UIApplication )app openURL:(NSURL )url options:(NSDictionary<NSString, id> *)options 中执行 】:

[[AlipaySDK defaultService]
processOrderWithPaymentResult:url
standbyCallback:^(NSDictionary *resultDic) {
NSLog(@"result = %@",resultDic);//返回的支付结果
}];

注意:
1.同步返回数据校验逻辑请参考……
2.SDK付款有两种模式:如果外部存在支付宝钱包,则直接跳转到支付宝钱包付款;不存在的场景下,在SDK内部进行H5支付。测试同学需要关注这两类测试场景。

 

iOS调用说明

接口名称:AlipaySDK

接口描述:提供支付功能。

Alipay接口主要为商户提供订单支付功能。接口所提供的方法,如下表所示:

方法名称方法描述
+(Alipay *)defaultService; 获取服务实例。
-(void)payOrder:(NSString *)orderStr fromScheme:(NSString *)schemeStr callback:(CompletionBlock)completionBlock; 支付并通过回调返回结果。
-(void)processOrderWithPaymentResult:(NSURL*)resultUrl standbyCallback:(CompletionBlock)completionBlock; 处理支付宝客户端返回的url(在app被杀模式下,通过这个方法获取支付结果)。

快捷订单支付iOS

方法名称:pay方法

方法原型:(void)payOrder:(NSString )orderStr fromScheme:(NSString )schemeStr callback:(CompletionBlock)completionBlock;

方法功能:提供给商户快捷订单支付功能。

参数名称参数描述
NSString* scheme 商户程序注册的URL protocol,供支付完成后回调商户程序使用。
(CompletionBlock)completionBlock 快捷支付开发包回调函数,返回免登、支付结果。本地未安装支付宝客户端,或未成功调用支付宝客户端进行支付的情况下(走H5收银台),会通过该completionBlock返回支付结果。相应的结果参考"客户端同步返回参数说明"。
NSString* orderString app支付请求参数字符串,主要包含商户的订单信息,key=value形式,以&连接。

orderStr示例如下,参数说明见"请求参数说明":

app_id=2015052600090779&biz_content=%7B%22timeout_express%22%3A%2230m%22%2C%22seller_id%22%3A%22%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22total_amount%22%3A%220.02%22%2C%22subject%22%3A%221%22%2C%22body%22%3A%22%E6%88%91%E6%98%AF%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%22%2C%22out_trade_no%22%3A%22314VYGIAGG7ZOYY%22%7D&charset=utf-8&method=alipay.trade.app.pay&sign_type=RSA2&timestamp=2016-08-15%2012%3A12%3A15&version=1.0&sign=MsbylYkCzlfYLy9PeRwUUIg9nZPeN9SfXPNavUCroGKR5Kqvx0nEnd3eRmKxJuthNUx4ERCXe552EV9PfwexqW%2B1wbKOdYtDIb4%2B7PL3Pc94RZL0zKaWcaY3tSL89%2FuAVUsQuFqEJdhIukuKygrXucvejOUgTCfoUdwTi7z%2BZzQ%3D

处理客户端返回url

方法名称:处理客户端方法

方法原型:-(void)processOrderWithPaymentResult:(NSURL*)resultUrl standbyCallback:(CompletionBlock)completionBlock;

方法功能:设备已安装支付宝客户端情况下,处理支付宝客户端返回的url。

注意:该方法必须实现,否则将会导致在安装手机支付宝的情况下,支付结果无法正常同步返回。

参数名称参数描述
NSURL *resultUrl 支付宝客户端回传的url
CompletionBlock completionBlock 本地安装了支付宝客户端,且成功调用支付宝客户端进行支付的情况下,会通过该completionBlock返回支付结果

备注:请在APPDelegate的 - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation 中调用该方法,iOS9.0以上(包括iOS9.0)请在 - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options 中调用该方法,具体可参见Demo

回调接口

在支付过程结束后,会通过callbackBlock同步返回支付结果(callbackBlock是调用支付同步的回调)。支付结果中参数的提取,必须通过CompletionBlock获取,禁止开发者私自解析支付结果返回的URL,参数说明见"客户端同步返回参数说明"。|

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2017-10-12 13:45  OIMMZC  阅读(403)  评论(0编辑  收藏  举报