Preface
Payment is divided into APP payment, H5 payment, QR code payment, etc. App payment is generally used in apps, and the corresponding payment SDK is required. H5 payment is mostly used for web pages. If your APP does not want to integrate the payment SDK and wants to implement the payment function, you can use H5 payment in your project. This article mainly talks about how to encapsulate H5 payment into a native callable component.
1.H5 payment process
Note: The following is the web page H5 payment process, and some processes need to be modified by native calls
1.1 WeChat Payment
- Unify the order and get the address of the WeChat middle page mweb_url
- Page redirect to WeChat middle page
- WeChat middle page initiates payment request
- Safari browser intercepts payment requests and opens the WeChat APP to start payment (if it is in the app, you need to intercept payment requests in the shouldStartLoadWithRequest: method and opens WeChat)
Redirect to redirect_url on WeChat middle page
1.2 Alipay payment
- Initiate a web payment request, and H5 submits it for a form form.
- Page redirection to Alipay cashier page
- Initiate an APP payment request and start counting. If you open the Alipay timeout page and jump to the web payment interface, if you call Alipay, the countdown will end.
- The payment completed page jumps to the return_url page, which needs to be triggered manually by the user.
2. Native packaging ideas
A new webView loads the payment intermediate page, intercepts the payment request on the intermediate page and calls the payment, and then closes the webView process to end.
The webView needs to be added to the window (or the current controller's view) and set a size (just not visible to the naked eye). Because when using wkwebview, if the webView is not displayed, the H5 request will be suspended, which will cause the Alipay page to fail to evoke the payment request.
3. Code implementation
See the code comment for specific steps
@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:@""]) { //WeChat security domain name NSString *wxScheme = @""; NSString *referer = [NSString stringWithFormat:@"%@://",wxScheme]; //Replace redirect_url with scheme, and you can only jump back to the APP after WeChat payment, otherwise the Safari browser will be opened (because redirect_url is generally an HTTP address) NSRange range = [html rangeOfString:@"redirect_url="]; NSString *reqUrl; if (>0) { reqUrl = [html substringToIndex:+]; reqUrl = [reqUrl stringByAppendingString:referer]; }else{ reqUrl = [html stringByAppendingString:[NSString stringWithFormat:@"&redirect_url=%@",referer]]; } request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:reqUrl] cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:60.0]; //Set the authorized domain name and forge the Referer header, because the WeChat middle page will check the Referer header, and the corresponding value of the Referer needs to include a secure domain name [request setValue:referer forHTTPHeaderField:@"Referer"]; if () { [ removeFromSuperview]; = nil; } = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 0.1, 0.1)]; = handle; [[UIApplication sharedApplication].keyWindow addSubview:]; = self; [ loadRequest:request]; }else if ([html hasPrefix:@"<form"]){ //If it is Alipay, the corresponding html should be a form form submission script, and you need to call the loadString method to load if () { [ removeFromSuperview]; = nil; } = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 0.1, 0.1)]; = handle; [[UIApplication sharedApplication].keyWindow addSubview:]; = 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]; [ loadHTMLString:htmlString baseURL:nil]; }else{ //Illegal html, return an error handle(HJH5SendWebPayResultOther); return; } //Fault-tolerant processing, payment is not called for 20 seconds, when error processing is handled. __weak typeof(self) weakSelf = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(20 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ if () { (HJH5SendWebPayResultOther); } [weakSelf endPayment]; }); } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error{ //The page failed to load, return an error if () { (HJH5SendWebPayResultLoadFail); } [self endPayment]; } - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{ NSURL *url = ; NSString *newUrl = ; //Intercept WeChat payment requests and open WeChat if([newUrl rangeOfString:@"weixin://wap/pay"].location != NSNotFound){ //Judge whether you can open WeChat if ([[UIApplication sharedApplication] canOpenURL:url]) { if (@available(iOS 10.0, *)){ [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; }else{ [[UIApplication sharedApplication] openURL:url]; } if () { (HJH5SendWebPayResultSuccess); } [self endPayment]; }else{ if () { (HJH5SendWebPayResultSendFail); } [self endPayment]; } return NO; }else if([newUrl rangeOfString:@"alipay://alipayclient/?"].location != NSNotFound){ //Intercept Alipay payment request and replace fromAppUrlScheme parameter with the scheme of the current APP to realize the function of returning to the APP after payment is completed. NSString *aliScheme = @"Alipay payment scheme, after payment, you can return to the current APP through the scheme"; 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(), ^{ //Judge whether Alipay can be opened 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 () { (HJH5SendWebPayResultSuccess); } [self endPayment]; }else{ if () { (HJH5SendWebPayResultSendFail); } [self endPayment]; } }); } } } return NO; }else{ return YES; } } -(void)endPayment{ = nil; [ removeFromSuperview]; = nil; } @end
3.1 Instructions for entry
Calling this method to evoke payment - (void)loadWebPayTransitionPage:(NSString *)html handleBlock:(void (^)(HJH5SendWebPayResult))handle.
Among them, html is the WeChat middle page address and the Alipay form script. like:
WeChat: ? xxxx
Alipay: <form name="alipaysubmit" action=xxxx></form><script>[' alipaysubmit '].submit();</script>
See 1.H5 payment process. After placing an order on WeChat, you can get the address of the intermediate page. For payment, you need to submit the form form to load the intermediate page.
3.2 Error handling
typedef NS_ENUM(NSUInteger,HJH5SendWebPayResult) { HJH5SendWebPayResultSuccess = 0, //Login successfully called HJH5SendWebPayResultLoadFail, //Payment page failed to load HJH5SendWebPayResultSendFail, //The payment was failed, it may be that WeChat or Alipay was not added or installed. HJH5SendWebPayResultOther //other};
If the payment request is sent successfully, it means that the H5 payment is initiated this time, and the specific payment results need to be checked for the background. Therefore, some exceptions need to be handled, such as page loading failure, WeChat or Alipay not installed, etc.
4. Explanation
This solution can unify the payment process of WeChat and Alipay H5 and implicitly display the payment intermediate page, which will not affect the routing of the H5 single page application. The APP does not require an integrated payment SDK, and can bypass Apple's scanning code.
Since the Alipay payment process is changed to the same as WeChat, the Alipay web payment function has been cut off, and you can only pay by opening the Alipay APP. This is also the shortcoming of this solution.
iOS-APP implements WeChat H5 payment summary
This is the article about iOS realizing native packaging of H5 payment (WeChat, Alipay). For more related iOS H5 payment content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!