前言
支付分APP支付、H5支付、掃碼支付等。app支付一般在app中使用,并且需要集成相應的支付SDK,H5支付多用于網頁。如果你的APP不想集成支付SDK,又想實現支付功能,你可以在項目中使用H5支付。本文主要講述如何將H5支付封裝成一個原生可調用的組件。
1.H5支付流程
注:以下為網頁H5支付流程,原生調用需要修改部分流程
1.1 微信支付
微信中間頁重新向到redirect_url
1.2 支付寶支付
2.原生封裝思路
新開一個webView加載支付中間頁,攔截中間頁支付請求并喚起支付,然后關閉webView流程結束。
webView需要加到window(或者當前控制器的view上),并設置一個大?。ㄈ庋鄄豢梢娋托校?。因為使用wkwebview時,webView不顯示的情況下,H5請求會被掛起,會導致支付寶頁面不能喚起支付請求。
3.代碼實現
具體步驟見代碼注釋
@interface HJH5WebPayManager()<UIWebViewDelegate>
@property (nonatomic,strong) UIWebView *payWebview;
@property (nonatomic,strong) void(^sendPayResult)(HJH5SendWebPayResult);
@end
@implementation HJH5WebPayManager
+(instancetype)sharedInstance{
static dispatch_once_t once ;
static HJH5WebPayManager *_instace = nil;
dispatch_once(&once, ^{
_instace = [[self alloc] init];
});
return _instace;
}
-(void)loadWebPayTransitionPage:(NSString *)html handleBlock:(void (^)(HJH5SendWebPayResult))handle{
NSMutableURLRequest *request = nil;
if ([html hasPrefix:@"https://wx.tenpay.com"]) {
//微信安全域名
NSString *wxScheme = @"";
NSString *referer = [NSString stringWithFormat:@"%@://",wxScheme];
//將redirect_url替換成scheme,微信支付完畢才能跳回APP,否則會打開Safari瀏覽器(因為redirect_url一般為一個HTTP的地址)
NSRange range = [html rangeOfString:@"redirect_url="];
NSString *reqUrl;
if (range.length>0) {
reqUrl = [html substringToIndex:range.location+range.length];
reqUrl = [reqUrl stringByAppendingString:referer];
}else{
reqUrl = [html stringByAppendingString:[NSString stringWithFormat:@"&redirect_url=%@",referer]];
}
request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:reqUrl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0];
//設置授權域名,偽造Referer頭,因為微信中間頁會檢驗Referer頭,并且Referer對應的值需要包含安全域名
[request setValue:referer forHTTPHeaderField:@"Referer"];
if (self.payWebview) {
[self.payWebview removeFromSuperview];
self.payWebview = nil;
}
self.payWebview = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 0.1, 0.1)];
self.sendPayResult = handle;
[[UIApplication sharedApplication].keyWindow addSubview:self.payWebview];
self.payWebview.delegate = self;
[self.payWebview loadRequest:request];
}else if ([html hasPrefix:@"<form"]){
//如果是支付寶,html對應的應該是一段form表單提交腳本,需要調用loadString方法加載
if (self.payWebview) {
[self.payWebview removeFromSuperview];
self.payWebview = nil;
}
self.payWebview = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 0.1, 0.1)];
self.sendPayResult = handle;
[[UIApplication sharedApplication].keyWindow addSubview:self.payWebview];
self.payWebview.delegate = self;
NSString *payStr = html;
NSString *htmlString = [NSString stringWithFormat:@"htmlString:<html> \n"
"<head> \n"
"<meta name=\"viewport\" content=\"initial-scale=1.0, maximum-scale=1.0, user-scalable=no\" /> \n"
"<style type=\"text/css\"> \n"
"body {font-size:16px;}\n"
"</style> \n"
"</head> \n"
"<body>"
"%@"
"</body>"
"</html>",payStr];
[self.payWebview loadHTMLString:htmlString baseURL:nil];
}else{
//非法html,返回錯誤
handle(HJH5SendWebPayResultOther);
return;
}
//容錯處理,20秒沒喚起支付,當錯誤處理。
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(20 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
if (weakSelf.sendPayResult) {
weakSelf.sendPayResult(HJH5SendWebPayResultOther);
}
[weakSelf endPayment];
});
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{
//頁面加載失敗,返回錯誤
if (self.sendPayResult) {
self.sendPayResult(HJH5SendWebPayResultLoadFail);
}
[self endPayment];
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSURL *url = request.URL;
NSString *newUrl = url.absoluteString;
//攔截微信支付請求,并打開微信
if([newUrl rangeOfString:@"weixin://wap/pay"].location != NSNotFound){
//判斷是否能打開微信
if ([[UIApplication sharedApplication] canOpenURL:url]) {
if (@available(iOS 10.0, *)){
[[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
}else{
[[UIApplication sharedApplication] openURL:url];
}
if (self.sendPayResult) {
self.sendPayResult(HJH5SendWebPayResultSuccess);
}
[self endPayment];
}else{
if (self.sendPayResult) {
self.sendPayResult(HJH5SendWebPayResultSendFail);
}
[self endPayment];
}
return NO;
}else if([newUrl rangeOfString:@"alipay://alipayclient/?"].location != NSNotFound){
//攔截支付寶支付請求,并且替換fromAppUrlScheme參數為當前APP的scheme,實現支付完畢返回APP功能。
NSString *aliScheme = @"支付寶支付scheme,支付完畢可通過scheme返回到當前APP";
newUrl = [HJStringHelper decodeURL:newUrl];
NSString *parameterString = [newUrl stringByReplacingOccurrencesOfString:@"alipay://alipayclient/?" withString:@""];
NSError *error = nil;
id dict = [NSJSONSerialization JSONObjectWithData:[parameterString dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingMutableContainers error:&error];
if (!error) {
if ([dict isKindOfClass:[NSMutableDictionary class]]) {
dict[@"fromAppUrlScheme"] = aliScheme;
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error];
if (!error) {
parameterString = [HJStringHelper escapeURL:[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]];
NSString *payUrl = [NSString stringWithFormat:@"alipay://alipayclient/?%@",parameterString];
dispatch_async(dispatch_get_main_queue(), ^{
//判斷是否能打開支付寶
if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:payUrl]]) {
if (@available(iOS 10.0, *)){
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:payUrl] options:@{} completionHandler:nil];
}else{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:payUrl]];
}
if (self.sendPayResult) {
self.sendPayResult(HJH5SendWebPayResultSuccess);
}
[self endPayment];
}else{
if (self.sendPayResult) {
self.sendPayResult(HJH5SendWebPayResultSendFail);
}
[self endPayment];
}
});
}
}
}
return NO;
}else{
return YES;
}
}
-(void)endPayment{
self.sendPayResult = nil;
[self.payWebview removeFromSuperview];
self.payWebview = nil;
}
@end
3.1入參說明
調用該方法喚起支付-(void)loadWebPayTransitionPage:(NSString *)html handleBlock:(void (^)(HJH5SendWebPayResult))handle.
其中html為微信中間頁地址和支付寶form表單腳本。如:
微信: https://wx.tenpay.com ?xxxx
支付寶:<form id=" alipaysubmit " name="alipaysubmit" action=xxxx></form><script>document.forms[' alipaysubmit '].submit();</script>
見1.H5支付流程,微信下單之后可以獲取中間頁地址,支付則需要form表單提交加載中間頁。
3.2錯誤處理
typedef NS_ENUM(NSUInteger,HJH5SendWebPayResult) {
HJH5SendWebPayResultSuccess = 0, //喚起登錄成功
HJH5SendWebPayResultLoadFail, //支付頁面加載失敗
HJH5SendWebPayResultSendFail, //調起支付失敗,可能是沒添加未安裝微信或者支付寶
HJH5SendWebPayResultOther //其他
};
支付請求發送成功則表示這次H5支付發起完成,具體支付結果需要查詢后臺獲得。所以需要對一些異常情況進行處理,比如頁面加載失敗,微信或支付寶未安裝等異常進行處理。
4.說明
這種方案可以統一微信和支付寶H5支付的流程,并且隱式地顯示支付中間頁,不會影響H5單頁面應用的路由。APP不需要集成支付SDK,可以繞過蘋果掃描代碼。
由于支付寶支付流程改成和微信一樣,所以支付寶網頁支付功能被砍掉,只能通過打開支付寶APP去支付。這也是這種方案的不足之處。
iOS-APP實現微信H5支付總結
到此這篇關于iOS實現H5支付(微信、支付寶)原生封裝的文章就介紹到這了,更多相關iOS H5支付內容請搜索億速云以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持億速云!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。