Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/462.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/115.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript WKWebView自定义长按菜单工作正常,但存在一些主要问题_Javascript_Ios_Objective C_Wkwebview - Fatal编程技术网

Javascript WKWebView自定义长按菜单工作正常,但存在一些主要问题

Javascript WKWebView自定义长按菜单工作正常,但存在一些主要问题,javascript,ios,objective-c,wkwebview,Javascript,Ios,Objective C,Wkwebview,当用户长按链接时,警报控制器将显示以下选项: 打开 在新选项卡中打开 抄袭 目前存在两个问题: 如果用户在WKWebView完成导航之前长按,则会显示默认(Safari)警报控制器 如果用户在弹出动画以某种方式出现后抬起手指,WKWebView会将其注册为点击,并在屏幕上仍显示警报控制器时导航到该链接 这一机制分为三个部分 首先, WKWebView完成导航后,将向页面注入javascript,以禁用默认警报控制器 - (void)webView:(WKWebView *)webView d

当用户长按链接时,警报控制器将显示以下选项:

  • 打开
  • 在新选项卡中打开
  • 抄袭
目前存在两个问题:

  • 如果用户在WKWebView完成导航之前长按,则会显示默认(Safari)警报控制器

  • 如果用户在弹出动画以某种方式出现后抬起手指,WKWebView会将其注册为点击,并在屏幕上仍显示警报控制器时导航到该链接

  • 这一机制分为三个部分

    首先,

    WKWebView完成导航后,将向页面注入javascript,以禁用默认警报控制器

    - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
    {
        [_webView evaluateJavaScript:@"document.body.style.webkitTouchCallout='none';"
                   completionHandler:^(id result, NSError *error){
    
                       NSLog(@"Javascript: {%@, %@}", result, error.description);
                   }];
    }
    
    第二,

    将UILongPressGestureRecognitor添加到WKWebView并实现,以便它根据触摸的位置查找元素的属性

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    {
        return YES;
    }
    
    - (void)longPress:(UILongPressGestureRecognizer *)longPressGestureRecognizer
    {
        if (longPressGestureRecognizer.state == UIGestureRecognizerStateBegan) {
    
            _shouldCancelNavigation = YES;
    
            CGPoint touchLocation = [longPressGestureRecognizer locationInView:_webView];
    
            NSString *javascript = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"Javascript" ofType:@"js"]
                                                             encoding:NSUTF8StringEncoding
                                                                error:nil];
    
            [_webView evaluateJavaScript:javascript
                       completionHandler:^(id result, NSError *error){
    
                           NSLog(@"Javascript: {%@, %@}", result, error.description);
                       }];
    
            [_webView evaluateJavaScript:[NSString stringWithFormat:@"MyAppGetHTMLElementsAtPoint(%f,%f);", touchLocation.x, touchLocation.y]
                       completionHandler:^(id result, NSError *error){
    
                           NSLog(@"Javascript: {%@, %@}", result, error.description);
    
                           NSString *tags = (NSString *)result;
    
                           if ([tags containsString:@",A,"]) {
    
                               [_webView evaluateJavaScript:[NSString stringWithFormat:@"MyAppGetHREFAttributeAtPoint(%f,%f);", touchLocation.x, touchLocation.y]
                                          completionHandler:^(id result, NSError *error){
    
                                              NSLog(@"Javascript: {%@, %@}", result, error.description);
    
                                              NSString *urlString = (NSString *)result;
    
                                              [_delegate webView:self didLongPressAtTouchLocation:touchLocation URL:[NSURL URLWithString:urlString]];
                                          }];
    
                               return;
                           }
    
                           if ([tags containsString:@",IMG,"]) {
    
                               [_webView evaluateJavaScript:[NSString stringWithFormat:@"MyAppGetSRCAttributeAtPoint(%f,%f);", touchLocation.x, touchLocation.y]
                                          completionHandler:^(id result, NSError *error){
    
                                              NSLog(@"Javascript: {%@, %@}", result, error.description);
    
                                              NSString *urlString = (NSString *)result;
    
                                              [_delegate webView:self didLongPressAtTouchLocation:touchLocation imageWithSourceURL:[NSURL URLWithString:urlString]];
                                          }];
    
                               return;
                           }
                       }];
        }
    }
    
    最后,

    表示警报控制器的委托方法在主ViewController上实现

    - (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation
    {
        [_webView evaluateJavaScript:@"document.body.style.webkitTouchCallout='none';"
                   completionHandler:^(id result, NSError *error){
    
                       NSLog(@"Javascript: {%@, %@}", result, error.description);
                   }];
    }
    
    我对第二个问题的解决方案是添加一个布尔值shouldCancelNavigation,该值在显示警报控制器时为YES,在解除警报控制器时为NO

    - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
    {
        if (_shouldCancelNavigation) {
    
            decisionHandler(WKNavigationActionPolicyCancel);
        }
        else {
    
            decisionHandler(WKNavigationActionPolicyAllow);
        }
    }
    
    有趣的是,网上有很多链接不需要决策的例子。他们只是发生了,我没有办法阻止他们

    例如:

    资料来源:

    资料来源2:

    编辑

    这解决了第二个问题,但我不确定它是否会在其他地方损坏某些东西

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    {
        if ([otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
    
            otherGestureRecognizer.enabled = NO;
    
            otherGestureRecognizer.enabled = YES;
        }
    
        return YES;
    }
    
    编辑2

    它确实造成了一个问题。。。您不能再选择文本,因为上面的代码会重置内部长按手势识别器

    编辑3

    如果我完全删除我的实现(全部3个步骤),并让默认警报控制器在每次我长按链接时启动,第二个问题就会得到解决


    苹果的alert控制器有一点在你抬起手指后会阻止WKWebView导航。

    如果我没说错的话,在第二部分:

    - (void)longPress:(UILongPressGestureRecognizer *)longPressGestureRecognizer
    {
        if (longPressGestureRecognizer.state == UIGestureRecognizerStateBegan) {
    
    //Rest of your code ...
        }
    }
    
    您正在注入javascript以禁用系统对话框。现在,在新闻结束后,WKWebview已经收到从web链接触发的事件。既然为时已晚,为什么不尝试检查
    LongPressGestureRecognitzer的条件。状态
    等于
    UIGestureRecognitzerStateEnded

    因此它改为下面的代码

        if (longPressGestureRecognizer.state == UIGestureRecognizerStateEnded) {
    
           //Rest of your code ...
        }
    

    我还没有测试这段代码。如果它能工作,我会更高兴。

    这个答案可以解决第二个问题,但我不确定它对App Store是否安全。

    首先,您需要断开内部长按手势识别器,以便在用户抬起手指时它们不会触发

    - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
    {
        if ([otherGestureRecognizer isKindOfClass:[UILongPressGestureRecognizer class]]) {
    
            if (otherGestureRecognizer.state == UIGestureRecognizerStateBegan) {
    
                // Warning: This will break how WKWebView handles selection of text.
    
                [otherGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer];
            }
        }
    
        return YES;
    }
    
    用户完成与自定义长按菜单的交互后,此代码将修复损坏的WKWebView:

        [_webView removeGestureRecognizer:_longPressGestureRecognizer]; // This code will remove the dependency and recover the lost functionality.
    
        _longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
    
        _longPressGestureRecognizer.numberOfTouchesRequired = 1;
    
        _longPressGestureRecognizer.delegate = self;
    
        [_webView addGestureRecognizer:_longPressGestureRecognizer];
    

    这就是一种黑客行为。

    我在页面加载完成时注入javascript以禁用系统对话框,而不是在手势识别器阶段开始时。而且,这是问题的第一部分。