iOS 開發支付篇
隨著互聯網的發展,電商平臺已經成為人們的習慣一種生活方式,電商個人認為站在開發的角度看,也就多了一個購物車和支付,而支付稱為很多剛接觸電商平臺開發人員很向往的一個技術點,那么現在我講自己了解的當前所有支付方式以及如何使用分享給大家。
支付寶支付:
支付流程 :
(1)先與支付寶簽約,獲取商戶id(partner)和賬號id(seller)
(2)下載相應的公私鑰文件(加密簽名使用),在客戶端我們可能只需要私鑰
(3)下載支付寶sdk
(4)生成訂單信息,可以直接客戶端或者自己服務端生存都可以,但是大多是服務端生存的。
(5)調用支付寶客戶端,有支付寶客戶端跟支付寶打交道
(6)支付完畢之后返回結果給客戶端和服務端。
//回到本應用urlScheme
NSString *appScheme=@"Practice";
NSString * orderInfo=[self getOrderInfo:indexPath.row];
NSString * signedStr=[self doRsa:orderInfo];
NSString*orderString=[NSString stringWithFormat:@"%@&sign=\"%@\"&sign_type=\"%@\"",orderInfo,signedStr,@"RSA"];
[AlixLibService payOrder:orderString AndScheme:appScheme seletor:_result target:self];
-(NSString *)doRsa:(NSString *)orderInfo
{
idsigner;
signer=CreateRSADataSigner(PartnerPrivKey);
NSString * signedString=[signer signString:orderInfo];
return signedString;
}
-(NSString *)getOrderInfo:(NSInteger)index
{
//點擊獲取product實例,并初始化訂單信息
Pruduct *pruduct=[_dataArray objectAtIndex:index];
AlixPayOrder * order=[[AlixPayOrder alloc]init];
order.partner=PartnerID;
order.seller=SellerID;
//訂單ID
order.tradeNO=[self generateTradeNO];
// 商品標題
order.productName=pruduct.subject;
// 商品描述
order.productDescription =pruduct.body;
//商品價格
order.amount=[NSString stringWithFormat:@"%.2f",pruduct.price];
order.notifyURL = @"http%3A%2F%2Fwwww.xxx.com"; //回調URL
return order.description;
}
-(NSString *)generateTradeNO
{
const int N =15;
NSString * sourceString=@"SSSSSSSSSSSSSSSS";
NSMutableString *re=[[NSMutableString alloc]init];
srand(time(0));
for (int i=0; i unsigned index=rand()%[sourceString length];
NSString * s=[sourceString substringWithRange:NSMakeRange(index, 1)];
[re appendString:s];
}
return re;
}
-(void)paymentResultDelegate:(NSString *)result
{
NSLog(@"%@",result);
}
//支付寶也就這么幾行代碼而已,所謂的高大上是不是讓朋友們失望了
微信支付:
支付流程:
(1)注冊微信開放平臺,創建應用獲取appid,appSecret,申請支付功能,申請成功之后會返回一些參數詳情見圖
(2)下載微信支付sdk
(3)客戶端請求訂單,后臺與微信后臺交互,返回給客戶端支付參數;
(4)調用微信客戶端,由微信客戶端和微信服務器打交道;
(5)客戶端和服務端都會收到支付結果;(前臺消息不可靠,我們需要去后臺驗證,如果后臺沒有收到支付通知,后臺去微信服務器驗證然后將結果返回給客戶端)
//需要的依賴庫,環境搭建可以參見文檔,或者直接用cocoapods倒入
/**
*? 微信開放平臺申請得到的 appid, 需要同時添加在 URL schema
*/
NSString * const WXAppId = @"wxd930ea5d5a258f4f";
/**
* 微信開放平臺和商戶約定的支付密鑰
*
* 注意:不能hardcode在客戶端,建議genSign這個過程由服務器端完成
*/
NSString * const WXAppKey = @"L8LrMqqeGRxST5reouB0K66CaYAWpqhAVsq7ggKkxHCOastWksvuX1uvmvQclxaHoYd3ElNBrNO2DHnnzgfVG9Qs473M3DTOZug5er46FhuGofumV8H2FVR9qkjSlC5K";
/**
* 微信開放平臺和商戶約定的密鑰
*
* 注意:不能hardcode在客戶端,建議genSign這個過程由服務器端完成
*/
NSString * const WXAppSecret = @"db426a9829e4b49a0dcac7b4162da6b6";
/**
* 微信開放平臺和商戶約定的支付密鑰
*
* 注意:不能hardcode在客戶端,建議genSign這個過程由服務器端完成
*/
NSString * const WXPartnerKey = @"8934e7d15453e97507ef794cf7b0519d";
/**
*? 微信公眾平臺商戶模塊生成的ID
*/
NSString * const WXPartnerId = @"1900000109";
調用支付的代碼就比較簡單了,如下所示
#pragma mark - 主體流程
- (void)getAccessToken
{
NSString *getAccessTokenUrl = [NSString stringWithFormat:@"https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%@&secret=%@", WXAppId, WXAppSecret];
NSLog(@"--- GetAccessTokenUrl: %@", getAccessTokenUrl);
self.request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:getAccessTokenUrl]];
__weak WXPayClient *weakSelf = self;
__weak ASIHTTPRequest *weakRequest = self.request;
[self.request setCompletionBlock:^{
NSError *error = nil;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:[weakRequest responseData]
options:kNilOptions
error:&error];
if (error) {
[weakSelf showAlertWithTitle:@"錯誤" msg:@"獲取 AccessToken 失敗"];
return;
} else {
NSLog(@"--- %@", [weakRequest responseString]);
}
NSString *accessToken = dict[AccessTokenKey];
if (accessToken) {
NSLog(@"--- AccessToken: %@", accessToken);
__strong WXPayClient *strongSelf = weakSelf;
[strongSelf getPrepayId:accessToken];
} else {
NSString *strMsg = [NSString stringWithFormat:@"errcode: %@, errmsg:%@", dict[errcodeKey], dict[errmsgKey]];
[weakSelf showAlertWithTitle:@"錯誤" msg:strMsg];
}
}];
[self.request setFailedBlock:^{
[weakSelf showAlertWithTitle:@"錯誤" msg:@"獲取 AccessToken 失敗"];
}];
[self.request startAsynchronous];
}
- (void)getPrepayId:(NSString *)accessToken
{
//token傳入到此鏈接
NSString *getPrepayIdUrl = [NSString stringWithFormat:@"https://api.weixin.qq.com/pay/genprepay?access_token=%@", accessToken];
NSLog(@"--- GetPrepayIdUrl: %@", getPrepayIdUrl);
NSMutableData *postData = [self getProductArgs];
// 文檔: 詳細的訂單數據放在 PostData 中,格式為 json
self.request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:getPrepayIdUrl]];
[self.request addRequestHeader:@"Content-Type" value:@"application/json"];
[self.request addRequestHeader:@"Accept" value:@"application/json"];
[self.request setRequestMethod:@"POST"];
[self.request setPostBody:postData];
__weak WXPayClient *weakSelf = self;
__weak ASIHTTPRequest *weakRequest = self.request;
[self.request setCompletionBlock:^{
NSError *error = nil;
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:[weakRequest responseData]
options:kNilOptions
error:&error];
//獲取到了支付參數
if (error) {
[weakSelf showAlertWithTitle:@"錯誤" msg:@"獲取 PrePayId 失敗"];
return;
} else {
NSLog(@"--- %@", [weakRequest responseString]);
}
NSString *prePayId = dict[PrePayIdKey];
if (prePayId) {
NSLog(@"--- PrePayId: %@", prePayId);
// 調起微信支付
//將支付參數傳入到sdk,喚起微信客戶端
PayReq *request? = [[PayReq alloc] init];
request.partnerId = WXPartnerId;
request.prepayId? = prePayId;
request.package? = @"Sign=WXPay";? ? ? // 文檔為 `Request.package = _package;` , 但如果填寫上面生成的 `package` 將不能支付成功
request.nonceStr? = weakSelf.nonceStr;
request.timeStamp = [weakSelf.timeStamp longLongValue];
// 構造參數列表
NSMutableDictionary *params = [NSMutableDictionary dictionary];
[params setObject:WXAppId forKey:@"appid"];
[params setObject:WXAppKey forKey:@"appkey"];
[params setObject:request.nonceStr forKey:@"noncestr"];
[params setObject:request.package forKey:@"package"];
[params setObject:request.partnerId forKey:@"partnerid"];
[params setObject:request.prepayId forKey:@"prepayid"];
[params setObject:weakSelf.timeStamp forKey:@"timestamp"];
request.sign = [weakSelf genSign:params];
// 在支付之前,如果應用沒有注冊到微信,應該先調用 [WXApi registerApp:appId] 將應用注冊到微信
[WXApi safeSendReq:request];
} else {
NSString *strMsg = [NSString stringWithFormat:@"errcode: %@, errmsg:%@", dict[errcodeKey], dict[errmsgKey]];
[weakSelf showAlertWithTitle:@"錯誤" msg:strMsg];
}
}];
[self.request setFailedBlock:^{
[weakSelf showAlertWithTitle:@"錯誤" msg:@"獲取 PrePayId 失敗"];
}];
[self.request startAsynchronous];
}
//這是微信官方給的demo,直接調用getAccessToken方法即可完成支付
銀聯支付:
支付流程:
(1)注冊申請就不是前端的事了,直接介入sdk
(2)從自己的服務端獲取流水號
(3)然后調用銀聯sdk,不用跳轉,銀聯sdk直接是內嵌的
(4)支付完成之后會回調代理方法
銀聯支付在客戶端實現起來最簡單的,現在介紹一下客戶端如何實現 ,以及實現代碼
- (void)viewDidLoad {
[super viewDidLoad];
//開始支付
//第一個參數是流水號,又后臺返回給我們 第二個參數傳00,01,00標示正式環境,01標示測試環境,第三個參數是支付完成回到的控制器,第四個參數是設置代理
[UPPayPlugin startPay:@"57855654" mode:@"01" viewController:self.navigationController delegate:self];
// Do any additional setup after loading the view, typically from a nib.
}
//監聽支付結果
- (void)UPPayPluginResult:(NSString *)result
{
}
//銀聯支付將復雜操作全部放在了后臺,我們使用相當方便
當然下面才是最常用的,它集成所有支付功能于一身:Ping++
支付流程:
4,ping++,支持支付寶支付,微信支付,銀聯支付,百度錢包支付,applepay
(1)根據呢需要介入的支付方式去對應的支付平臺申請賬號和參數
(2)(恨不得直接上代碼了),傳說中的7行代碼搞定支付
Ping++有著前所未有的簡單,號稱7行代碼搞定支付
NSDictionary* dict = @{? ? @"channel" : channel, // 渠道 alipay, wx, upacp, bfb
@"amount"? : amount? // 金額};
NSData* data = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil];
NSString *bodyData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[postRequest setHTTPBody:[NSData dataWithBytes:[bodyData UTF8String] length:strlen([bodyData UTF8String])]];
[postRequest setHTTPMethod:@"POST"];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[NSURLConnection sendAsynchronousRequest:postRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
NSString* charge = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];? ? // ...
[Pingpp createPayment:charge viewController:viewController appURLScheme:kUrlScheme withCompletion:^(NSString *result, PingppError *error) {? ?
?if ([result isEqualToString:@"success"]) {? ? ? ? // ...
} else {? ? ??
? NSLog(@"PingppError: code=%lu msg=%@", error.code, [error getMsg]);
}
}];
}];
//AppDelegate添加這行代碼適用于監聽支付結果的
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
[Pingpp handleOpenURL:url withCompletion:^(NSString *result, PingppError *error) {? ? ? ? if ([result isEqualToString:@"success"]) {? ? ? ? ? ? // ...
} else {? ? ? ? ? ? NSLog(@"PingppError: code=%lu msg=%@", error.code, [error getMsg]);
}
}];? ? return? YES;
}
綜上所述,你可以跟你的個人需求來選擇接入支付方式
第三方支付,終究還是第三方,第三方站著公司和開發者的角度上考慮問題,減少開發難度和成本,不必要如此擔心。