一切阅读,皆是误读。 -----安伯托 · 艾柯
想起来上一篇iOS 集成支付宝sdk简单教程以及遇到的坑(1)还漏了两个错误情况,没列出来。
一个是:
does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE),
obtain an updated library from the vendor, or disable bitcode for this target. for architecture armv7
clang: error: unable to execute command: Segmentation fault: 11
clang: error: linker command failed due to signal (use -v to see invocation)
原因是开启了ENABLE_BITCODE,与第三方库不兼容。只要把这个关掉就行了。在build settings里搜bitcode,然后把ENABLE_BITCODE设为no。如图:
另一个是错误:
'openssl/asn1.h' file not found
解决办法也很简单:在build settings 里搜"search path",找到header search paths ,把值设为$(PROJECT_DIR)/项目名称,如图:
ok,万事具备!!我先去尿个尿。
尿完尿,正式开干。
我们把上次copy的方法提取成一个方法,在需要的地方调用。
- (void)jumpToAlipay{
Order*order = [[Order alloc]init];
order.partner= partner;//支付宝合作商家id
order.sellerID= seller;//支付宝商家id,通常就是合作商家id
order.outTradeNO= [self generateTradeNO];//订单ID(由商家自行制定)
order.subject= product.subject;//商品标题
order.body= product.body;//商品描述
order.totalFee= [NSStringstringWithFormat:@"%.2f",product.price];//商品价格
order.notifyURL=@"http://www.xxx.com";//回调URL
order.service=@"mobile.securitypay.pay";
order.paymentType=@"1";
order.inputCharset=@"utf-8";
order.itBPay=@"30m";
order.showURL=@"m.alipay.com";
//应用注册scheme,在AlixPayDemo-Info.plist定义URL types
NSString*appScheme =@"xxx";
//将商品信息拼接成字符串
NSString*orderSpec = [order description];
NSLog(@"orderSpec = %@",orderSpec);
//获取私钥并将商户信息签名,外部商户可以根据情况存放私钥和签名,只需要遵循RSA签名规范,并将签名字符串base64编码和UrlEncode
id signer =CreateRSADataSigner(privateKey);
NSString*signedString = [signer signString:orderSpec];
//将签名成功字符串格式化为订单字符串,请严格按照该格式
NSString*orderString =nil;
if(signedString !=nil) {
orderString = [NSString stringWithFormat:@"%@&sign=\"%@\"&sign_type=\"%@\"",
orderSpec, signedString,@"RSA"];
[[AlipaySDK defaultService]payOrder:orderString fromScheme:appScheme callback:^(NSDictionary*resultDic) {
NSLog(@"reslut = %@",resultDic);
}];
}
}
还有一个生成订单id的方法
- (NSString*)generateTradeNO
{
static int kNumber =15;
NSString*sourceStr =@"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
NSMutableString*resultStr = [[NSMutableString alloc]init];
srand((unsigned)time(0));
for(inti =0; i < kNumber; i++)
{
unsigned index =rand() % [sourceStr length];
NSString*oneStr = [sourceStr substringWithRange:NSMakeRange(index,1)];
[resultStr appendString:oneStr];
}
return resultStr;
}
重点看一下jumpToAlipay方法里生成订单的几个参数
order.partner= partner;//支付宝合作商家id
order.sellerID= seller;//支付宝商家id,通常就是合作商家id
order.subject= product.subject;//商品标题
order.body= product.body;//商品描述
order.totalFee= [NSStringstringWithFormat:@"%.2f",product.price];//商品价格
order.notifyURL=@"http://www.xxx.com";//回调URL
这些参数都换成自己的值。
NSString*appScheme =@"xxx"; 这个参数值在项目的info 页面的URL Types里查看
如果你没设置的,就设置一个,值的内容最好是跟项目有关的有意义的内容。
也可以在plist里查看。
如果没设置就设置一个。
id signer =CreateRSADataSigner(privateKey);
把这句里的privateKey换成自己的私钥,就是通过openssl设置的那个私钥。
perfect! 我想我们真是天才!!
运行项目,点击支付-----没反应。。。
一看控制台,提示:rsa_private read error : private key is NULL
这个问题有两种解决办法。
先看第一种:
把私钥转换成PKCS8格式(如果服务端是用PHP读取私钥不需要PKCS8转换)
参考文档:https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.ZzNd4x&treeId=44&articleId=103242&docType=1
相关命令:
openssl (进入openssl,然后执行下面的命令)
pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt (注意不要输错了)
如果已经转换成pkcs8格式了,仍然报这个错,那就试试下面的办法:
1)在RSADataSigner.m文件中 搜索代码 [result appendString:@"-----BEGIN PRIVATE KEY-----\n"]; 将其改成
[result appendString:@"-----BEGIN RSA PRIVATE KEY-----\n"];
2)在RSADataSigner.m文件中 搜索代码 [result appendString:@"\n-----END PRIVATE KEY-----"]; 将其改成 [result appendString:@"\n-----END RSA PRIVATE KEY-----"];
如图:
修改前
修改后
解决了这个问题,继续,运行项目,点击支付-----终于跳转到支付宝了!!!!!
但是,感觉不太对。。。
系统繁忙,稍后再试!!!!
hmmmmmmm。出现这个问题,通常要检查自己的参数有没有错,还有私钥公钥。我这次就是公钥不对,重新生成公钥,上传。
有个小插曲,我按照之前的做法,在原来的支付宝商家服务那上传公钥,怎么都不对,搜了一下才发现支付宝换了个上传地址。。。。。
现在是在开放平台--》账户中心--》合作伙伴密钥--》查看--》修改 (注意不要有空格换行)
然而还有一种公钥:应用公钥。根据文档,这是用于调用api2.0的。
https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.vp1syv&treeId=44&articleId=103243&docType=1
需要用到的可以看看这个文档。
ok,继续,运行项目,点击支付-----终于正常了!!!!
输入密码,支付成功!!!
剩下来的就是处理回调。这就不多说了。
至此,集成支付宝就真正大功告成。可以去吃火锅撩妹了!!!
哦,还有一个事。@风铃书简在上篇文章留言说不要直接在客户端对接,要放到服务端。我试了一下,由我们的app服务端提供一个接口,支付前,先访问这个接口,获得相关的参数值,比如商户id,合作id,私钥,标题,价格等,其实就是如下的这些参数值:
order.seller= param[@"seller_id"];
order.tradeNO= param[@"out_trade_no"];//订单ID(由商家自行制定)
order.productName= param[@"subject"];//商品标题
order.productDescription= param[@"body"];//商品描述
order.amount= param[@"total_fee"];//商品价格
order.notifyURL=param[@"notify_url"];//回调URL
order.service= param[@"service"];
order.paymentType= param[@"payment_type"];
order.inputCharset= param[@"_input_charset"];
order.itBPay= param[@"it_b_pay"];
order.showUrl= param[@"return_url"];
那么私钥,合作id,商户id都不需要保存在客户端了,生成订单id的方法generateTradeNO也不需要了,that is it.
如果不对,请指教。
最后,猫图镇楼:
如果你觉得文章不错,可以给我打赏点比特股(bts),以示支持。^_^
BTS6jUaVVkz9gN8t9sWY9NR5UbiubSz7QtVDnEtFGpujYeqQSfQ5E