作者:PLDLYY | 来源:互联网 | 2023-07-24 18:26
Swift与H5交互:跳转拦截完成支付功能-这是我参与更文挑战的第7天,活动详情查看:[更文挑战]与H5交互不得不说的事最近上班一直都在和公司的其他项目的人员忙活App原生(双
这是我参与更文挑战的第7天,活动详情查看: [更文挑战]
与H5交互不得不说的事
最近上班一直都在和公司的其他项目的人员忙活App原生(双端)与H5交互的事情,因为遇到了需求方非常质疑的态度(主要是感觉方案不可行),导致需要进行验证与尝试。
虽然,在原生与H5的交互上,我基本都了解情况,不过在此机会也记录一下,就当存档的吧。
后面再遇到这类问题,给自己抑或掘友们一点点启发与思路。
今天说先说一个业务需求。
App内嵌H5页面进行支付
事情大概是这样的,我们团队的前端做了一个Web页面,是一个商城类型,有支付功能,可以进行微信和支付宝支付。
这个Web页面在浏览器中支付跳转,不管是跳转到微信支付或者是支付宝支付都是好好的,但集成到移动端App里面的WebView后,就不生效了。
前端的同事感到疑惑后找到了我,寻求如何在App端跳转微信或者支付宝进行支付的方案。
我直接就下了结论:App什么都不做,这明摆着不能的呀?虽然H5大部分时间都能都为所欲为,但这类Web页面在App中需要进行跳转,必须在App端进行跳转拦截与处理呀。
说到这里,必须上代码来演示了。
在iOS中WKWebKit中的WebView有一个代理属性WKNavigationDelegate
,其中有这样一个代理方法:
/// 根据WebView对于即将跳转的HTTP请求头信息和相关信息来决定是否跳转
///
/// - Parameters:
/// - webView: 实现该代理的webview
/// - navigationAction: 当前navigation
/// - decisionHandler: 是否跳转block
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
decisionHandler(.allow)
}
这里面,一个非常重要的参数,navigationAction,我们来看看它的类WKNavigationAction
里面有哪些属性:
@available(iOS 8.0, *)
open class WKNavigationAction : NSObject {
/** @abstract The frame requesting the navigation.
*/
@NSCopying open var sourceFrame: WKFrameInfo { get }
/** @abstract The target frame, or nil if this is a new window navigation.
*/
@NSCopying open var targetFrame: WKFrameInfo? { get }
/** @abstract The type of action that triggered the navigation.
@discussion The value is one of the constants of the enumerated type WKNavigationType.
*/
open var navigationType: WKNavigationType { get }
/** @abstract The navigation's request.
*/
open var request: URLRequest { get }
/** @abstract A value indicating whether the web content used a download attribute to indicate that this should be downloaded.
*/
@available(iOS 14.5, *)
open var shouldPerformDownload: Bool { get }
}
注意看其中有一个属性是open var request: URLRequest { get }
通过这个属性,我们可以获取到需要跳转的URL的内容,针对我们跳转微信支付或者支付宝支付,我们只用判断request中的scheme和url字符串就可以了。
而这方面支付宝的官方文档中就给出了明确的例子:
App通过监听alipays://或者alipay:// 开头的路由来唤醒支付宝。
支付宝文档
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
__weak APWebViewController* wself = self;
NSString * reqUrl = navigationAction.request.URL.absoluteString;
if ([reqUrl hasPrefix:@"alipays://"] || [reqUrl hasPrefix:@"alipay://"]) {
// NOTE: 跳转支付宝App
BOOL bSucc = [[UIApplication sharedApplication]openURL:navigationAction.request.URL];
// NOTE: 如果跳转失败,则跳转itune下载支付宝App
if (!bSucc) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"提示"
message:@"未检测到支付宝客户端,请安装后重试。"
delegate:wself
cancelButtonTitle:@"立即安装"
otherButtonTitles:nil];
[alert show];
}
decisionHandler(WKNavigationActionPolicyCancel);
return;
}
decisionHandler(WKNavigationActionPolicyAllow);
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// NOTE: 跳转itune下载支付宝App
NSString* urlStr = @"https://itunes.apple.com/cn/app/zhi-fu-bao-qian-bao-yu-e-bao/id333206289?mt=8";
NSURL *downloadUrl = [NSURL URLWithString:urlStr];
[[UIApplication sharedApplication]openURL:downloadUrl];
}
而微信文档中明确说明了不建议App调用H5支付,见下图:
虽然微信文档不建议,但通过支付宝给出的代码,完全可以照抄,通过判断url中是否包含weixin://来进行跳转。
其实这类拦截跳转到最后,都会调用UIApplication.shared的一个函数:
open func open(_ url: URL, options: [UIApplication.OpenExternalURLOptionsKey : Any] = [:], completionHandler completion: ((Bool) -> Void)? = nil)
这个函数可以认为是一个系统级路由方法,可以在iOS系统层面进行App的切换。
结论
App通过WebView加载H5页面,进行支付功能是可行的,同时App端(双端)都需要进行WebView的跳转拦截,通过系统级路由去跳转到微信或者支付宝完成支付。
通过H5调用其他功能,比如打电话,也可以通过在上面所示的代理方法中判断是否包含tel://
来进行处理。
微信支付不建议App调用H5支付,我个人认为是处于安全考虑,因为可能涉及恶意重定向拦截的request的url,导致指向其他订单,出现支付的异常扣款的情况。
明日继续
明天会继续更新原生调用js,和js调用原生的分析与例子。大家加油!