iOS WKWebView 判断跳转链接是否是用户点击

899 阅读2分钟

背景

CSDN APP 中H5页面,有部分链接的跳转是需要拦截,并且用新页面的方式打开。 WKWebView 中提供了以下方法,供我们使用。

-(void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction preferences:(WKWebpagePreferences *)preferences decisionHandler:(void (^)(WKNavigationActionPolicy, WKWebpagePreferences * _Nonnull))decisionHandler
{
    if (判断是否需要跳转){
        //跳转的逻辑
        decisionHandler(WKNavigationActionPolicyCancel,preferences);
    }else{
        decisionHandler(WKNavigationActionPolicyAllow,preferences);
    }
}

一般我们判断用户是否是点击链接,直接用WKNavigationType来判断,它有以下枚举状态

typedef NS_ENUM(NSInteger, WKNavigationType) {
    WKNavigationTypeLinkActivated,//链接的href属性被用户激活。
    WKNavigationTypeFormSubmitted,//一个表单提交。
    WKNavigationTypeBackForward,//回到前面的条目列表请求。
    WKNavigationTypeReload,//网页加载。
    WKNavigationTypeFormResubmitted,//一个表单提交(例如通过前进,后退,或重新加载)。
    WKNavigationTypeOther = -1,//导航是发生一些其他原因。
} NS_ENUM_AVAILABLE(10_10, 8_0);

navigationAction.navigationType == WKNavigationTypeLinkActivated 时,可以知道,这次跳转是点击链接跳转。 但是,我们在使用中发现,很多跳转中navigationAction.navigationType == WKNavigationTypeOther,这时,我们的判断就不会生效。 如下图:我们需要的是跳转新页面,并不是当前页面刷新。 请添加图片描述

解决方案

1、首先,我们通过原生是无法拿到判断状态是点击跳转还是主动reload,那我们就通过用JS监听点击事件的方式,来获取用户是否有点击页面的操作。如果用户有点击操作,那就通过window.webkit.messageHandlers 与原生通信,告诉原生页面有点击事件操作。

/// 监听用户有没有点击页面
-(NSString *)setJSTouchString{
    NSString *touchJs = @"\
    document.addEventListener('touchstart',e => {\
    this.move = false;\
    this.start = e.changedTouches[0].pageY;\
    });\
    document.addEventListener('touchmove',e => {\
        this.move = true;\
    });\
    document.addEventListener('touchend',e => {\
        this.end = e.changedTouches[0].pageY;\
        if(!this.move){\
         window.webkit.messageHandlers.TouchEvent.postMessage(true);\
        }else{\
         window.webkit.messageHandlers.TouchEvent.postMessage(false);\
        }\
    });\
    ";
    return touchJs;
}

2、原生通过- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message 获取到用户点击状态

//  MARK: - js调用原生方法 可在此方法中获得传递回来的参数
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
     if([message.name isEqualToString:@"TouchEvent"]){
        self.isTouchWeb = [message.body boolValue];
    }
}

3、提供以下方法,来判断是否是点击链接跳转

/// 返回给定的导航是否由用户链接单击触发
/// @param navigationType
- (BOOL)isLinkNavigation:(WKNavigationType)navigationType {
  switch (navigationType) {
    case WKNavigationTypeLinkActivated:
      return YES;
    case WKNavigationTypeOther:
      return self.isTouchWeb;
    default:
      return NO;
  }
}

这样,就解决了无法判断用户是否是点击链接的问题。最后实现的效果如下图: 请添加图片描述

需要注意的是,如果WKWebView有下拉刷新或者双击Tab刷新功能的话,需要在刷新前将点击状态重置。即self.isTouchWeb = NO