AlipaySDKHelper.m 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. //
  2. // AlipaySDKHelper.m
  3. // MingMen
  4. //
  5. // Created by 尚旅客户端 on 2017/8/18.
  6. // Copyright © 2017年 尚旅客户端. All rights reserved.
  7. //
  8. #import "AlipaySDKHelper.h"
  9. #import <AlipaySDK/AlipaySDK.h>
  10. #import "Order.h"
  11. #import "APAuthV2Info.h"
  12. #import "RSADataSigner.h"
  13. @implementation AlipaySDKHelper
  14. static AlipaySDKHelper *sharedObj = nil;
  15. + (instancetype)sharedInstance
  16. {
  17. static dispatch_once_t onceToken = 0;
  18. dispatch_once(&onceToken, ^{
  19. sharedObj = [[super allocWithZone: NULL] init];
  20. });
  21. return sharedObj;
  22. // static NIMSDKHelper *instance = nil;
  23. // static dispatch_once_t onceToken;
  24. // dispatch_once(&onceToken, ^{
  25. // instance = [[NIMSDKHelper alloc] init];
  26. // });
  27. // return instance;
  28. }
  29. + (id) allocWithZone:(struct _NSZone *)zone
  30. {
  31. return [self sharedInstance];
  32. }
  33. - (id) copyWithZone:(NSZone *) zone
  34. {
  35. return self;
  36. }
  37. #pragma mark - iOS9.0以后使用新API回调
  38. - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options
  39. {
  40. // 支付跳转支付宝钱包进行支付,处理支付结果
  41. [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
  42. //NSLog(@"支付结果 result = %@",resultDic);
  43. _NewAlipayCallback(resultDic);
  44. }];
  45. // 授权跳转支付宝钱包,处理授权结果
  46. [[AlipaySDK defaultService] processAuth_V2Result:url standbyCallback:^(NSDictionary *resultDic) {
  47. //NSLog(@"授权结果结果 result = %@",resultDic);
  48. _NewAliauthCallback(resultDic);
  49. /*
  50. // 解析 auth code
  51. NSString *result = resultDic[@"result"];
  52. NSString *authCode = nil;
  53. if (result.length>0) {
  54. NSArray *resultArr = [result componentsSeparatedByString:@"&"];
  55. for (NSString *subResult in resultArr) {
  56. if (subResult.length > 10 && [subResult hasPrefix:@"auth_code="]) {
  57. authCode = [subResult substringFromIndex:10];
  58. break;
  59. }
  60. }
  61. }
  62. NSLog(@"授权结果 authCode = %@", authCode?:@"");
  63. */
  64. }];
  65. return YES;
  66. }
  67. #pragma mark - iOS9.0之前使用旧API回调
  68. - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
  69. {
  70. // 支付跳转支付宝钱包进行支付,处理支付结果
  71. [[AlipaySDK defaultService] processOrderWithPaymentResult:url standbyCallback:^(NSDictionary *resultDic) {
  72. //NSLog(@"支付结果 result = %@",resultDic);
  73. _NewAlipayCallback(resultDic);
  74. }];
  75. // 授权跳转支付宝钱包,处理授权结果
  76. [[AlipaySDK defaultService] processAuth_V2Result:url standbyCallback:^(NSDictionary *resultDic) {
  77. //NSLog(@"授权结果结果 result = %@",resultDic);
  78. _NewAliauthCallback(resultDic);
  79. /*
  80. // 解析 auth code
  81. NSString *result = resultDic[@"result"];
  82. NSString *authCode = nil;
  83. if (result.length>0) {
  84. NSArray *resultArr = [result componentsSeparatedByString:@"&"];
  85. for (NSString *subResult in resultArr) {
  86. if (subResult.length > 10 && [subResult hasPrefix:@"auth_code="]) {
  87. authCode = [subResult substringFromIndex:10];
  88. break;
  89. }
  90. }
  91. }
  92. NSLog(@"授权结果 authCode = %@", authCode?:@"");
  93. */
  94. }];
  95. return YES;
  96. }
  97. - (NSString *)generateTradeNO
  98. {
  99. static int kNumber = 15;
  100. NSString *sourceStr = @"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
  101. NSMutableString *resultStr = [[NSMutableString alloc] init];
  102. srand((unsigned)time(0));
  103. for (int i = 0; i < kNumber; i++)
  104. {
  105. unsigned index = rand() % [sourceStr length];
  106. NSString *oneStr = [sourceStr substringWithRange:NSMakeRange(index, 1)];
  107. [resultStr appendString:oneStr];
  108. }
  109. return resultStr;
  110. }
  111. #pragma mark -
  112. #pragma mark ==============点击订单支付==============
  113. //
  114. //选中商品调用支付宝极简支付
  115. //
  116. - (void)alipayPay:(NSDictionary *)payDictionary order:(NSDictionary *)orderDictionary
  117. {
  118. //重要说明
  119. //这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;
  120. //真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;
  121. //防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;
  122. /*============================================================================*/
  123. /*=======================需要填写商户app申请的===================================*/
  124. /*============================================================================*/
  125. NSString *appID = payDictionary[@"AlipayAppid"];
  126. // 如下私钥,rsa2PrivateKey 或者 rsaPrivateKey 只需要填入一个
  127. // 如果商户两个都设置了,优先使用 rsa2PrivateKey
  128. // rsa2PrivateKey 可以保证商户交易在更加安全的环境下进行,建议使用 rsa2PrivateKey
  129. // 获取 rsa2PrivateKey,建议使用支付宝提供的公私钥生成工具生成,
  130. // 工具地址:https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=106097&docType=1
  131. NSString *rsa2PrivateKey = payDictionary[@"AlipayPrivateKey"];//私钥
  132. NSString *rsaPrivateKey = payDictionary[@"AlipayPublicKey"];//公钥
  133. /*============================================================================*/
  134. /*============================================================================*/
  135. /*============================================================================*/
  136. //partner和seller获取失败,提示 //message:@"缺少pid或者appID或者私钥。"
  137. if ([appID length] == 0 ||
  138. ([rsa2PrivateKey length] == 0 && [rsaPrivateKey length] == 0))
  139. {
  140. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示"
  141. message:@"提交订单信息发生错误,请稍后再试"
  142. delegate:self
  143. cancelButtonTitle:@"确定"
  144. otherButtonTitles:nil];
  145. [alert show];
  146. return;
  147. }
  148. /*
  149. *生成订单信息及签名
  150. */
  151. //将商品信息赋予AlixPayOrder的成员变量
  152. Order* order = [Order new];
  153. // NOTE: app_id设置
  154. order.app_id = appID;
  155. // NOTE: 支付接口名称
  156. order.method = @"alipay.trade.app.pay";
  157. // NOTE: 参数编码格式
  158. order.charset = @"utf-8";
  159. // NOTE: 当前时间点
  160. NSDateFormatter* formatter = [NSDateFormatter new];
  161. [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
  162. order.timestamp = [formatter stringFromDate:[NSDate date]];
  163. // NOTE: 支付版本
  164. order.version = @"1.0";
  165. // NOTE: sign_type 根据商户设置的私钥来决定
  166. order.sign_type = (rsa2PrivateKey.length > 1)?@"RSA2":@"RSA";
  167. // NOTE: 商品数据
  168. order.biz_content = [BizContent new];
  169. order.biz_content.body = orderDictionary[@"body"];
  170. order.biz_content.subject = orderDictionary[@"subject"];
  171. order.biz_content.out_trade_no = orderDictionary[@"out_trade_no"]; //订单ID(由商家自行制定)[self generateTradeNO]
  172. order.biz_content.timeout_express = orderDictionary[@"timeout_express"]; //超时时间设置
  173. order.biz_content.total_amount = orderDictionary[@"total_amount"]; //商品价格 [NSString stringWithFormat:@"%.2f", 0.01]
  174. //将商品信息拼接成字符串
  175. NSString *orderInfo = [order orderInfoEncoded:NO];
  176. NSString *orderInfoEncoded = [order orderInfoEncoded:YES];
  177. NSLog(@"orderSpec = %@",orderInfo);
  178. // NOTE: 获取私钥并将商户信息签名,外部商户的加签过程请务必放在服务端,防止公私钥数据泄露;
  179. // 需要遵循RSA签名规范,并将签名字符串base64编码和UrlEncode
  180. NSString *signedString = nil;
  181. RSADataSigner* signer = [[RSADataSigner alloc] initWithPrivateKey:((rsa2PrivateKey.length > 1)?rsa2PrivateKey:rsaPrivateKey)];
  182. if ((rsa2PrivateKey.length > 1)) {
  183. signedString = [signer signString:orderInfo withRSA2:YES];
  184. } else {
  185. signedString = [signer signString:orderInfo withRSA2:NO];
  186. }
  187. // NOTE: 如果加签成功,则继续执行支付
  188. if (signedString != nil) {
  189. //应用注册scheme,在AliSDKDemo-Info.plist定义URL types
  190. NSString *appScheme = @"iosbjmingmen";
  191. // NOTE: 将签名成功字符串格式化为订单字符串,请严格按照该格式
  192. NSString *orderString = [NSString stringWithFormat:@"%@&sign=%@",
  193. orderInfoEncoded, signedString];
  194. // NOTE: 调用支付结果开始支付
  195. [[AlipaySDK defaultService] payOrder:orderString fromScheme:appScheme callback:^(NSDictionary *resultDic) {
  196. //NSLog(@"支付结果 result = %@",resultDic);
  197. _NewAlipayCallback(resultDic);
  198. }];
  199. }
  200. }
  201. #pragma mark ==============点击授权==============
  202. - (void)alipayAuth:(NSDictionary *)authDictionary
  203. {
  204. //重要说明
  205. //这里只是为了方便直接向商户展示支付宝的整个支付流程;所以Demo中加签过程直接放在客户端完成;
  206. //真实App里,privateKey等数据严禁放在客户端,加签过程务必要放在服务端完成;
  207. //防止商户私密数据泄露,造成不必要的资金损失,及面临各种安全风险;
  208. /*============================================================================*/
  209. /*=======================需要填写商户app申请的===================================*/
  210. /*============================================================================*/
  211. NSString *pid = authDictionary[@"AlipayPid"];
  212. NSString *appID = authDictionary[@"AlipayAppid"];
  213. // 如下私钥,rsa2PrivateKey 或者 rsaPrivateKey 只需要填入一个
  214. // 如果商户两个都设置了,优先使用 rsa2PrivateKey
  215. // rsa2PrivateKey 可以保证商户交易在更加安全的环境下进行,建议使用 rsa2PrivateKey
  216. // 获取 rsa2PrivateKey,建议使用支付宝提供的公私钥生成工具生成,
  217. // 工具地址:https://doc.open.alipay.com/docs/doc.htm?treeId=291&articleId=106097&docType=1
  218. NSString *rsa2PrivateKey = authDictionary[@"AlipayPrivateKey"];//私钥
  219. NSString *rsaPrivateKey = authDictionary[@"AlipayPublicKey"];//公钥
  220. /*============================================================================*/
  221. /*============================================================================*/
  222. /*============================================================================*/
  223. //pid和appID获取失败,提示
  224. if ([pid length] == 0 ||
  225. [appID length] == 0 ||
  226. ([rsa2PrivateKey length] == 0 && [rsaPrivateKey length] == 0))
  227. {
  228. //message:@"缺少pid或者appID或者私钥。"
  229. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"提示"
  230. message:@"申请授权发生错误,请稍后再试"
  231. delegate:self
  232. cancelButtonTitle:@"确定"
  233. otherButtonTitles:nil];
  234. [alert show];
  235. return;
  236. }
  237. /*
  238. //生成 auth info 对象
  239. APAuthV2Info *authInfo = [APAuthV2Info new];
  240. authInfo.pid = pid;
  241. authInfo.appID = appID;
  242. authInfo.targetID = authDictionary[@"targetID"];
  243. //授权类型,AUTHACCOUNT:授权;LOGIN:登录
  244. NSString *authType = [[NSUserDefaults standardUserDefaults] objectForKey:@"authType"];
  245. if (authType) {
  246. authInfo.authType = authType;
  247. }
  248. // 将授权信息拼接成字符串
  249. NSString *authInfoStr = [authInfo description];
  250. NSLog(@"authInfoStr = %@",authInfoStr);
  251. // 获取私钥并将商户信息签名,外部商户可以根据情况存放私钥和签名,只需要遵循RSA签名规范,并将签名字符串base64编码和UrlEncode
  252. NSString *signedString = nil;
  253. RSADataSigner* signer = [[RSADataSigner alloc] initWithPrivateKey:((rsa2PrivateKey.length > 1)?rsa2PrivateKey:rsaPrivateKey)];
  254. if ((rsa2PrivateKey.length > 1)) {
  255. signedString = [signer signString:authInfoStr withRSA2:YES];
  256. } else {
  257. signedString = [signer signString:authInfoStr withRSA2:NO];
  258. }
  259. */
  260. //应用注册scheme,在AlixPayDemo-Info.plist定义URL types
  261. NSString *appScheme = @"iosbjmingmen";
  262. // 将签名成功字符串格式化为订单字符串,请严格按照该格式
  263. // signedString.length > 0
  264. if ([authDictionary[@"sign_url"] length] > 0) {
  265. //authInfoStr = [NSString stringWithFormat:@"%@&sign=%@&sign_type=%@", authInfoStr, signedString, ((rsa2PrivateKey.length > 1)?@"RSA2":@"RSA")];
  266. //如果APP处于前台,则通过此方法拿到支付宝的回调信息
  267. [[AlipaySDK defaultService] auth_V2WithInfo:authDictionary[@"sign_url"]
  268. fromScheme:appScheme
  269. callback:^(NSDictionary *resultDic) {
  270. //NSLog(@"授权结果结果 result = %@",resultDic);
  271. _NewAliauthCallback(resultDic);
  272. /*
  273. // 解析 auth code
  274. NSString *result = resultDic[@"result"];
  275. NSString *authCode = nil;
  276. if (result.length>0) {
  277. NSArray *resultArr = [result componentsSeparatedByString:@"&"];
  278. for (NSString *subResult in resultArr) {
  279. if (subResult.length > 10 && [subResult hasPrefix:@"auth_code="]) {
  280. authCode = [subResult substringFromIndex:10];
  281. break;
  282. }
  283. }
  284. }
  285. NSLog(@"授权结果 authCode = %@", authCode?:@"");
  286. */
  287. }];
  288. }
  289. }
  290. @end