iOS支付宝、微信、银联支付集成封装调用(下)
程序员文章站
2023-12-14 23:05:52
一.越来越多的app增加第三方的功能,可能app有不同的页面但调用相同的支付方式,例如界面如下:
这两个页面都会使用第三方支付支付:(微信,支付宝,银联)如果在每一个...
一.越来越多的app增加第三方的功能,可能app有不同的页面但调用相同的支付方式,例如界面如下:
这两个页面都会使用第三方支付支付:(微信,支付宝,银联)如果在每一个页面都直接调用第三方支付的接口全部代码,显然并不是很合适,更何况,可能一个app并不止两个入口。所以封装还是很有必要的。
1.新建model:-------后台返回支付方式的列表json
#import <foundation/foundation.h> @interface ioapayitemmodel : nsobject //name:代表是支付宝,微信,银联或者余额等 @property (nonatomic, copy) nsstring *name; //icon:代表是支付方式的图片 @property (nonatomic, copy) nsstring *icon; //code:代表支付方式的唯一标识 @property (nonatomic, copy) nsstring *code; //paytype:代表支付类型(自己确定的) @property (nonatomic, assign) nsinteger paytype; @end
#import "ioapayitemmodel.h" @implementation ioapayitemmodel @end
2.封装第三方支付接口以及回调接口-----直接上源代码----会有解释(相信大家的能力,肯定能看懂)
#import <foundation/foundation.h> //支付宝sdk #import <alipaysdk/alipaysdk.h> //微信接口 #import <wxapi.h> //银联接口 #import "uppaymentcontrol.h" /** 枚举:列出第三方支付方式 */ typedef ns_enum(nsinteger, paytype) { kpaytypewxpay, // 微信支付 kpaytypealipay, // 支付宝支付 kpaytypeunpay // 银联支付 }; /** ioapayrequestmodel:第三方支付需要的参数 */ @interface ioapayrequestmodel: nsobject @property (nonatomic, assign) paytype paytype; /** 支付宝和银联-后台返回是字符串类型----支付宝和银联使用此方式 */ @property (nonatomic, copy) nsstring *paystring; @property (nonatomic, copy) nsstring *appscheme; // 根据设置的paytype设置 /** 微信-后台返回是字典类型--- 微信使用此方式 */ @property (nonatomic, strong) nsdictionary *userinfo; @end /** 第三方支付接口返回的数据--- */ @interface ioapayresponsemodel: nsobject @property (nonatomic, assign) paytype paytype; //result和userinfo信息判断支付结果--(支付成功、支付失败、支付取消等) @property (nonatomic, assign) nsinteger result; @property (nonatomic, strong) nsdictionary *userinfo; @end @interface ioapayapi : nsobject //支付返回的回调方法 @property (nonatomic, copy) void (^callback)(ioapayresponsemodel *response); //支付请求model ----ioapayrequestmodel---第三方支付需要的参数 @property (nonatomic, strong) ioapayrequestmodel *payrequestmodel; //单例方法 + (instancetype)defaultpaymanager; // 是否安装了客户端 - (bool)ispayappinstalled:(paytype)paytype; // 支付 - (void)pay:(ioapayrequestmodel *)payrequestmodel callback:(void (^)(ioapayresponsemodel *response))callback; // 支付回调 - (void)paycallbackwithurl:(nsurl *)url; @end
#import "ioapayapi.h" @implementation ioapayrequestmodel - (void)setpaytype:(paytype)paytype { _paytype = paytype; if (_paytype == kpaytypealipay) { self.appscheme = @"ioaalipaysdk"; // 测试 // self.paystring = @"alipay_sdk=1.0&app_id=2018012502067343&biz_content=%7b%22subject%22%3a%22%e6%94%af%e4%bb%98%e5%ae%9d%e6%94%af%e4%bb%98%22%2c%22out_trade_no%22%3a%222018032100007%22%2c%22total_amount%22%3a%220.01%22%2c%22product_code%22%3a%22quick_msecurity_pay%22%2c%22timeout_express%22%3a%2210m%22%2c%22seller_id%22%3a%222088001065568658%22%7d&charset=utf-8&format=json&method=alipay.trade.app.pay¬ify_url=api.ioa365.net%2fapp%2fapi%2fpayment%2falipay_notify&sign_type=rsa2×tamp=2018-03-21+16%3a59%3a15&version=1.0&sign=sfyiwfqdkg98qarjfkfnjts8w2rs7atwjcrynnkyildavvfenr%2f943qjk9wfazgipx38rzurf%2bl4m74hp2po%2f%2f0zfskanttu3dmlivgt4yd42w1f2lop3ixtkl5bhppzt6yfdquecz1zreeawqxlybdvvnjbj9p67f2jt8jfqm6enz6kwwy5cshydd6ijqf0fkxdmsya%2bico6iihdiqksrlhubpb8lfsxjyy1%2fbaauysib3%2biu6hwasugadcvl769ivwhkwdjzqzuofpjcfnneyzg3%2b4f%2fnlbry1pkk3zwy2uqpttk0w0gofsf167drz47j0lw7uufym8ua%2bihz7lw%3d%3d"; return; } if (_paytype == kpaytypeunpay) { self.appscheme = @"uppay"; // 测试 // self.paystring = @"559018436594292239101"; return; } // 测试 // self.userinfo = @{ // @"appid":@"wx66a3135d1354b23b", // @"noncestr":@"j8pjbaeg6ajdq9kk", // @"partnerid":@"1497576612", // @"prepayid":@"wx20180321170621b3fbce61a20187009040", // @"result_code":@"success", // @"return_code":@"success", // @"return_msg":@"ok", // @"sign":@"29fff7b63a71d3fb4c6866bdbc443f72", // @"timestamp":@"1521623180", // @"trade_type":@"app", // }; } @end @implementation ioapayresponsemodel @end @interface ioapayapi() <wxapidelegate> @end @implementation ioapayapi //单例方法 static ioapayapi *manager = nil; + (instancetype)defaultpaymanager { static dispatch_once_t oncetoken; dispatch_once(&oncetoken, ^{ manager = [ioapayapi new]; }); return manager; } + (instancetype)allocwithzone:(struct _nszone *)zone { static dispatch_once_t oncetoken; dispatch_once(&oncetoken, ^{ manager = [super allocwithzone:zone]; }); return manager; } //copy在底层 会调用copywithzone: - (instancetype)copywithzone:(nszone *)zone { return [[self class] defaultpaymanager]; } + (instancetype)copywithzone:(struct _nszone *)zone { return [self defaultpaymanager]; } + (instancetype)mutablecopywithzone:(struct _nszone *)zone { return [self defaultpaymanager]; } - (instancetype)mutablecopywithzone:(nszone *)zone { return [[self class] defaultpaymanager]; } #pragma mark - weichatpaydelegate - (void)onresp:(baseresp *)resp { //启动微信支付的response if (self.payrequestmodel.paytype == kpaytypewxpay) { if (self.callback) { ioapayresponsemodel *payresponsemodel = [ioapayresponsemodel new]; payresponsemodel.result = 0; if([resp iskindofclass:[payresp class]]){ //支付返回结果,实际支付结果需要去微信服务器端查询 switch (resp.errcode) { case 0: // payresoult = @"支付结果:成功!"; payresponsemodel.result = 1; break; case -1: payresponsemodel.result = 0; break; case -2: payresponsemodel.result = 0; break; default: break; } } self.callback(payresponsemodel); } } } #pragma mark - public // 是否安装了客户端 - (bool)ispayappinstalled:(paytype)paytype { switch (paytype) { case kpaytypewxpay: return [wxapi iswxappinstalled]; break; case kpaytypealipay: // 未提供接口 返回no return no; break; case kpaytypeunpay: return [[uppaymentcontrol defaultcontrol] ispaymentappinstalled]; break; default: break; } return no; } - (void)pay:(ioapayrequestmodel *)payrequestmodel callback:(void (^)(ioapayresponsemodel *response))callback { if (!payrequestmodel) return; self.callback = callback; self.payrequestmodel = payrequestmodel; switch (payrequestmodel.paytype) { case kpaytypewxpay: [self wxpay:payrequestmodel]; break; case kpaytypealipay: [self alipay:payrequestmodel]; break; case kpaytypeunpay: [self unpay:payrequestmodel]; break; default: break; } } // 支付回调 - (void)paycallbackwithurl:(nsurl *)url { // 其他如支付等sdk的回调 if ([url.host isequaltostring:@"safepay"]) { [self alipaycallback:url]; } else if ([url.host isequaltostring:@"pay"]) { // 处理微信的支付结果 [self wxpaycallback:url]; } else if ([url.host isequaltostring:@"uppayresult"]) { [self unpaycallback:url]; } } #pragma mark - pay // 微信支付 - (void)wxpay:(ioapayrequestmodel *)payrequestmodel { payreq *req = [[payreq alloc] init]; nsdictionary *datadic = payrequestmodel.userinfo; //由用户微信号和appid组成的唯一标识,用于校验微信用户 req.openid = datadic[@"appid"]; // 商家id,在注册的时候给的 req.partnerid = datadic[@"partnerid"]; // 预支付订单这个是后台跟微信服务器交互后,微信服务器传给你们服务器的,你们服务器再传给你 req.prepayid = datadic[@"prepayid"]; // 根据财付通文档填写的数据和签名 req.package = @"sign=wxpay"; // 随机编码,为了防止重复的,在后台生成 req.noncestr = datadic[@"noncestr"]; // 这个是时间戳,也是在后台生成的,为了验证支付的 nsstring * stamp = datadic[@"timestamp"]; req.timestamp = stamp.intvalue; // 这个签名也是后台做的 req.sign = datadic[@"sign"]; //发送请求到微信,等待微信返回onresp [wxapi sendreq:req]; } // 支付宝 - (void)alipay:(ioapayrequestmodel *)payrequestmodel { nsstring *appscheme = payrequestmodel.appscheme; nsstring *paystring = payrequestmodel.paystring; __weak __typeof(self)weakself = self; [[alipaysdk defaultservice] payorder:paystring fromscheme:appscheme callback:^(nsdictionary *resultdic) { if (weakself.payrequestmodel.paytype == kpaytypealipay) { if (weakself.callback) { ioapayresponsemodel *payresponsemodel = [ioapayresponsemodel new]; payresponsemodel.userinfo = resultdic; payresponsemodel.result = [resultdic[@"result"] integervalue]; weakself.callback(payresponsemodel); } } }]; } // 银联支付 - (void)unpay:(ioapayrequestmodel *)payrequestmodel { nsstring *appscheme = payrequestmodel.appscheme; nsstring *paystring = payrequestmodel.paystring; [[uppaymentcontrol defaultcontrol] startpay:paystring fromscheme:appscheme mode:@"01" viewcontroller:[uiapplication sharedapplication].keywindow.rootviewcontroller]; } ////// - (void)wxpaycallback:(nsurl *)url { //跳转支付宝钱包进行支付,处理支付结果 [wxapi handleopenurl:url delegate:self]; } - (void)alipaycallback:(nsurl *)url { __weak typeof(self)weakself = self; [[alipaysdk defaultservice] processorderwithpaymentresult:url standbycallback:^(nsdictionary *resultdic) { if (weakself.payrequestmodel.paytype == kpaytypealipay) { if (weakself.callback) { ioapayresponsemodel *payresponsemodel = [ioapayresponsemodel new]; payresponsemodel.userinfo = resultdic; payresponsemodel.result = [resultdic[@"result"] integervalue]; weakself.callback(payresponsemodel); } } }]; } - (void)unpaycallback:(nsurl *)url { __weak typeof(self)weakself = self; [[uppaymentcontrol defaultcontrol]handlepaymentresult:url completeblock:^(nsstring *code, nsdictionary *data) { if (weakself.payrequestmodel.paytype == kpaytypeunpay) { if (weakself.callback) { ioapayresponsemodel *payresponsemodel = [ioapayresponsemodel new]; payresponsemodel.userinfo = data; if ([code isequaltostring:@"success"]) { [[nsnotificationcenter defaultcenter] postnotificationname:@"yinlianpays" object:nil]; payresponsemodel.result = [code boolvalue]; } else if([code isequaltostring:@"fail"]) { //交易失败 [[nsnotificationcenter defaultcenter] postnotificationname:@"yinlianpayf" object:nil]; payresponsemodel.result = [code boolvalue]; } else if([code isequaltostring:@"cancel"]) { //交易取消 [[nsnotificationcenter defaultcenter] postnotificationname:@"yinlianpayc" object:nil]; payresponsemodel.result = 0; } weakself.callback(payresponsemodel); } } }]; } @end
3.此时方法就开始封装好了,可以在需要的地方直接使用(弹框已作出)
- (void)alipay{ [self startprogress]; self.requestmodel.pay_type = @"alipaymobile"; //自己后台的接口---拿到后台返回的数据作为第三方接口的参数 [self.viewmodel requestcartsettlepay:self.requestmodel callback:^(ioaresponse *response) { dispatch_async(dispatch_get_main_queue(), ^{ [self stopprogress]; if (response.success) { nsstring *appscheme = @"ioaalipaysdk"; self.payrequestmodel.paystring = response.responseobject; self.payrequestmodel.paytype = 1; self.payrequestmodel.appscheme = appscheme; //第三方接口调用(封装) [[ioapayapi defaultpaymanager] pay:self.payrequestmodel callback:^(ioapayresponsemodel *response) { dispatch_async(dispatch_get_main_queue(), ^{ nsdictionary *userinfo = response.userinfo; if (![userinfo[@"resultstatus"] isequaltostring:@"9000"]) { //进入待付款界面(支付失败或者支付取消等) [self pushwait]; }else{ //进入订单列表界面(支付成功) [self pushlist]; } }); }]; }else{ [self.view maketoast:@"支付失败"]; } }); }]; }
4.重磅来临(一些人弹框没有作出,可以直接拷贝下面代码)
新建控制器控制弹框.h文件中
#import <uikit/uikit.h> #import "ioapayapi.h" #import "ioapayitemmodel.h" @interface ioapayviewcontroller : uiviewcontroller //点击第几行回调声明 @property (nonatomic, copy) void (^clickcallback)(nsinteger atindex); + (instancetype)show; //block回调方法 + (instancetype)show:(void (^)(nsinteger atindex))clickcallback; + (void)dismiss; - (void)setupitemtitles:(nsarray <nsstring *>*)titles; - (void)setupitems:(nsarray <ioapayitemmodel *>*)items; - (void)setuptitle:(nsstring *)title; @end
实现其方法.m文件中
#import "ioapayviewcontroller.h" #define paycellheight 50 #define paysectionheaderheight 44 @interface ioapayviewcontroller () <uitableviewdatasource, uitableviewdelegate> @property (nonatomic, strong) calayer *masklayer; @property (nonatomic, strong) uilabel *titleview; @property (nonatomic, strong) uiview *paybgview; @property (nonatomic, strong) uitableview *tableview; @property (nonatomic, strong) nsmutablearray *datasources; @property (nonatomic, assign) cgfloat payviewheight; - (void)showpayview; - (void)dismisspayview; @end @implementation ioapayviewcontroller - (void)dealloc { } + (instancetype)show { uiviewcontroller *rootvc = [uiapplication sharedapplication].keywindow.rootviewcontroller; ioapayviewcontroller *vc = [ioapayviewcontroller new]; [rootvc addchildviewcontroller:vc]; [rootvc.view addsubview:vc.view]; [vc setupitemtitles:@[@"微信支付", @"支付宝支付", @"银联支付"]]; [vc showpayview]; return vc; } + (instancetype)show:(void (^)(nsinteger atindex))clickcallback { ioapayviewcontroller *vc = [self show]; vc.clickcallback = clickcallback; return vc; } + (void)dismiss { uiviewcontroller *rootvc = [uiapplication sharedapplication].keywindow.rootviewcontroller; for (uiviewcontroller *vc in rootvc.childviewcontrollers) { if ([vc iskindofclass:[ioapayviewcontroller class]]) { ioapayviewcontroller *tempvc = (ioapayviewcontroller *)vc; [tempvc dismisspayview]; return; } } } - (void)viewdidload { [super viewdidload]; self.view.backgroundcolor = [uicolor clearcolor]; self.masklayer.frame = self.view.bounds; [self.view.layer addsublayer:self.masklayer]; [self.view addsubview:self.paybgview]; // [self.view addsubview:self.tableview]; } - (void)didreceivememorywarning { [super didreceivememorywarning]; // dispose of any resources that can be recreated. } #pragma mark - uitableviewdatasource - (nsinteger )numberofsectionsintableview:(uitableview *)tableview { return 1; } - (nsinteger)tableview:(uitableview *)tableview numberofrowsinsection:(nsinteger)section { return self.datasources.count; } - (uitableviewcell *)tableview:(uitableview *)tableview cellforrowatindexpath:(nsindexpath *)indexpath { uitableviewcell *cell = [tableview dequeuereusablecellwithidentifier:@"cell" forindexpath:indexpath]; id temp = self.datasources[indexpath.row]; if ([temp iskindofclass:[nsstring class]]) { cell.textlabel.text = temp; } else { ioapayitemmodel *item = temp; cell.textlabel.text = item.name; } cell.textlabel.font = [uifont systemfontofsize:18]; cell.textlabel.textcolor = rgb_hexstring(@"#323232"); cell.selectionstyle = uitableviewcellselectionstylenone; return cell; } #pragma mark - uitableviewdelegate - (cgfloat)tableview:(uitableview *)tableview heightforrowatindexpath:(nsindexpath *)indexpath { return paycellheight; } - (uiview *)tableview:(uitableview *)tableview viewforheaderinsection:(nsinteger)section { return self.titleview; } - (cgfloat )tableview:(uitableview *)tableview heightforheaderinsection:(nsinteger)section { return paysectionheaderheight; } - (void)tableview:(uitableview *)tableview didselectrowatindexpath:(nsindexpath *)indexpath { // ioapayrequestmodel *payrequestmodel = [ioapayrequestmodel new]; // payrequestmodel.paytype = indexpath.row; //// ws(weakself); //// __weak typeof (self)weakself = self; // __block ioapayviewcontroller *payvc = self; // [[ioapayapi defaultpaymanager] pay:payrequestmodel callback:^(ioapayresponsemodel *response) { //// __strong __typeof (weakself)strongself = weakself; // response.paytype = indexpath.row; // if (payvc.clickcallback) { // payvc.clickcallback(response); // payvc = nil; // } // }]; if (self.clickcallback) { self.clickcallback(indexpath.row); } [self dismisspayview]; } #pragma mark - touches - (void)touchesbegan:(nsset<uitouch *> *)touches withevent:(uievent *)event { [self dismisspayview]; } #pragma mark - public - (void)setupitemtitles:(nsarray<nsstring *> *)titles { if (!titles.count) { return ; } self.payviewheight = titles.count * paycellheight + paysectionheaderheight; cgrect frame = self.view.frame; frame.size.height = self.payviewheight; self.tableview.frame = frame; [self.datasources removeallobjects]; [self.datasources addobjectsfromarray:titles]; [self.tableview reloaddata]; [self setpayviewframe]; } - (void)setupitems:(nsarray <ioapayitemmodel *>*)items { if (!items.count) { return ; } for (ioapayitemmodel *item in items) { if ([item.code isequaltostring:@"appweixinpay"]) { item.paytype = 0; continue; } if ([item.code isequaltostring:@"alipaymobile"]) { item.paytype = 1; continue; } if ([item.code isequaltostring:@"unionpay"]) { item.paytype = 2; continue; } if ([item.code isequaltostring:@"ye"]) { item.paytype = 3; continue; } item.paytype = 3; } self.payviewheight = items.count * paycellheight + paysectionheaderheight; cgrect frame = self.view.frame; frame.size.height = self.payviewheight; self.tableview.frame = frame; [self.datasources removeallobjects]; [self.datasources addobjectsfromarray:items]; [self.tableview reloaddata]; [self setpayviewframe]; } - (void)setuptitle:(nsstring *)title { self.titleview.text = title; } #pragma mark - private - (void)showpayview { [self.view.layer removeallanimations]; cgfloat paybgviewheight = self.payviewheight + bottomheightoffset; cgrect frame = self.view.frame; frame.origin.y = self.view.frame.origin.y + self.view.frame.size.height; frame.size.height = paybgviewheight; self.paybgview.frame = frame; frame.origin.y = self.view.frame.size.height - paybgviewheight; [uiview animatewithduration:0.25 animations:^{ self.paybgview.frame = frame; }]; } - (void)setpayviewframe { cgfloat paybgviewheight = self.payviewheight + bottomheightoffset; cgrect frame = self.view.frame; frame.origin.y = self.view.frame.origin.y + self.view.frame.size.height; frame.size.height = paybgviewheight; frame.origin.y = self.view.frame.size.height - paybgviewheight; self.paybgview.frame = frame; } - (void)dismisspayview { cgfloat paybgviewheight = self.payviewheight + bottomheightoffset; cgrect frame = self.view.frame; frame.origin.y = self.view.frame.origin.y + self.view.frame.size.height; frame.size.height = paybgviewheight; [uiview animatewithduration:0.25 animations:^{ self.paybgview.frame = frame; } completion:^(bool finished) { [self.view removefromsuperview]; [self removefromparentviewcontroller]; }]; } #pragma mark - setter / getter - (calayer *)masklayer { if (_masklayer == nil) { _masklayer = [calayer layer]; _masklayer.backgroundcolor = [uicolor blackcolor].cgcolor; _masklayer.opacity = 0.2; } return _masklayer; } - (uilabel *)titleview { if (!_titleview) { _titleview = [uilabel new]; _titleview.textalignment = nstextalignmentcenter; _titleview.text = @"请选择支付方式"; _titleview.font = [uifont systemfontofsize:16]; _titleview.textcolor = [uicolor blackcolor]; _titleview.backgroundcolor = rgb_hexstring(@"#f2f2f2");//[uicolor whitecolor]; } return _titleview; } - (uiview *)paybgview { if (!_paybgview) { _paybgview = [uiview new]; _paybgview.backgroundcolor = [uicolor whitecolor]; [_paybgview addsubview:self.tableview]; } return _paybgview; } - (uitableview *)tableview{ if (!_tableview) { _tableview = [[uitableview alloc]initwithframe:cgrectzero style:uitableviewstyleplain]; _tableview.delegate = self; _tableview.datasource = self; _tableview.showsverticalscrollindicator = no; _tableview.showshorizontalscrollindicator = no; _tableview.separatorstyle = uitableviewcellseparatorstylesingleline; _tableview.separatorcolor = rgb_hexstring(@"#f2f2f2"); if ([_tableview respondstoselector:@selector(setseparatorinset:)]) { [_tableview setseparatorinset:uiedgeinsetszero]; } if ([_tableview respondstoselector:@selector(setlayoutmargins:)]) { [_tableview setlayoutmargins:uiedgeinsetszero]; } // [_tableview registerclass:[uitableviewcell class] forcellreuseidentifier:@"cell"]; } return _tableview; } - (nsmutablearray *)datasources { if (!_datasources) { _datasources = [nsmutablearray array]; } return _datasources; } - (void)setpayviewheight:(cgfloat)payviewheight { _payviewheight = payviewheight; cgfloat height = self.view.frame.size.height * 0.6; self.tableview.scrollenabled = no; if (_payviewheight > height) { _payviewheight = height; self.tableview.scrollenabled = yes; } } @end
举例方法
利用请求的数据进行赋值传值。
ioaorderbasemodel *datasourcemodel = self.datasource[indexpath.section]; ioaorderselectableitemmodel *itemmodel = (ioaorderselectableitemmodel *) datasourcemodel.items[row]; ioapayviewcontroller *vc = [ioapayviewcontroller show:^(nsinteger atindex) { ioapayitemmodel *payitem = itemmodel.items[atindex]; itemmodel.selectedindex = atindex; weakself.requestmodel.pay_type = payitem.code; weakself.payitem = payitem; [weakself.tableview reloadsections:[nsindexset indexsetwithindex:section] withrowanimation:uitableviewrowanimationnone]; }]; [vc setupitems:self.confirmorderinfo.payment_list]; [vc setuptitle:@"请选择支付方式"];
最后的举例方法并不是所有的适用,对于上面1.2.3还是可以直接拿过去使用,这些都是原创,如果第一次接入还是希望各位读者读一下上篇文章,集成的整个过程,链接为,这个代码的整个demo。