Disable entire UIMenuController edit menu in WKWebView












18















Requirement



I have a WKWebView and would like to remove the system menu items (Copy, Define, Share...) from the Edit Menu and present my own.



I am targeting iOS 8 and 9. I am currently testing with the Xcode 7.0.1 simulator (iOS 9) and my iPhone 6 running iOS 9.0.2.



Standard Method Does Not Work



I know the standard way of achieving this is by subclassing WKWebView and implementing
-canPerformAction:withSender:. However, I have found that with WKWebView -canPerformAction:withSender: is not being called for the copy: or define: actions. This appears to be a known bug (WKWebView and UIMenuController).



Example app: https://github.com/dwieringa/WKWebViewCustomEditMenuBug



@implementation MyWKWebView

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
NSLog(@"ACTION: %@", NSStringFromSelector(action));

if (action == @selector(delete:))
{
// adding Delete as test (works)
return YES;
}

// trying to remove everything else (does NOT work for Copy, Define, Share...)
return NO;
}

- (void)delete:(id)sender
{
NSLog(@"Delete menu item selected");
}

@end


Output: (note no copy: or define: action)



2015-10-20 12:28:32.864 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: cut:
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: select:
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: selectAll:
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: paste:
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: delete:
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _promptForReplace:
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _transliterateChinese:
2015-10-20 12:28:32.867 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _showTextStyleOptions:
2015-10-20 12:28:32.907 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _addShortcut:
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilitySpeak:
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilitySpeakLanguageSelection:
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilityPauseSpeaking:
2015-10-20 12:28:32.909 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: makeTextWritingDirectionRightToLeft:
2015-10-20 12:28:32.909 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: makeTextWritingDirectionLeftToRight:


Planned Workaround



My desire now is to completely hide the edit menu and replace it with a custom menu using QBPopupMenu.



My problem is that I have not been able to find a way to hide or disable the standard Edit menu. I have found some suggestions to hide it with [UIMenuController sharedMenuController].menuVisible = NO; on UIMenuControllerWillShowMenuNotification, but I have not been able to get this to work. It has no affect with WillShowMenu. I can hide it in DidShowMenu but by that point it is too late and I get a menu flash.



I have also tried to locate it outside the visible area using [[UIMenuController sharedMenuController] setTargetRect:CGRectMake(0, 0, 1, 1) inView:self.extraView];, but again doing so with WillShowMenu has no affect and with DidShowMenu it is too late.



Experiments available here: https://github.com/dwieringa/WKWebViewEditMenuHidingTest



What am I missing? Is there another way to disable or hide the standard editting menu for WKWebView?










share|improve this question

























  • Out of curiosity have you filed a bug report with Apple for this?

    – Ryan
    Nov 19 '15 at 0:48











  • @Ryan, no not yet. Thanks for your answer below. I just tried it and I'm still seeing the menu when I long press on text under iOS 9 on my iPhone 6. Have you tried it with WKWebView on iOS? I verified with Web Inspector that the new CSS setting is applied to body.

    – davew
    Nov 19 '15 at 1:58











  • @davew any success with this?

    – Jed Grant
    Nov 29 '15 at 1:48











  • @JedGrant no, I've been living with the standard Editing menu for now. On Nov 19, I briefly tried Ryan's suggestion, but didn't get it to work and haven't had time to dig deeper.

    – davew
    Dec 1 '15 at 21:01
















18















Requirement



I have a WKWebView and would like to remove the system menu items (Copy, Define, Share...) from the Edit Menu and present my own.



I am targeting iOS 8 and 9. I am currently testing with the Xcode 7.0.1 simulator (iOS 9) and my iPhone 6 running iOS 9.0.2.



Standard Method Does Not Work



I know the standard way of achieving this is by subclassing WKWebView and implementing
-canPerformAction:withSender:. However, I have found that with WKWebView -canPerformAction:withSender: is not being called for the copy: or define: actions. This appears to be a known bug (WKWebView and UIMenuController).



Example app: https://github.com/dwieringa/WKWebViewCustomEditMenuBug



@implementation MyWKWebView

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
NSLog(@"ACTION: %@", NSStringFromSelector(action));

if (action == @selector(delete:))
{
// adding Delete as test (works)
return YES;
}

// trying to remove everything else (does NOT work for Copy, Define, Share...)
return NO;
}

- (void)delete:(id)sender
{
NSLog(@"Delete menu item selected");
}

@end


Output: (note no copy: or define: action)



2015-10-20 12:28:32.864 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: cut:
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: select:
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: selectAll:
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: paste:
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: delete:
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _promptForReplace:
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _transliterateChinese:
2015-10-20 12:28:32.867 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _showTextStyleOptions:
2015-10-20 12:28:32.907 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _addShortcut:
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilitySpeak:
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilitySpeakLanguageSelection:
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilityPauseSpeaking:
2015-10-20 12:28:32.909 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: makeTextWritingDirectionRightToLeft:
2015-10-20 12:28:32.909 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: makeTextWritingDirectionLeftToRight:


Planned Workaround



My desire now is to completely hide the edit menu and replace it with a custom menu using QBPopupMenu.



My problem is that I have not been able to find a way to hide or disable the standard Edit menu. I have found some suggestions to hide it with [UIMenuController sharedMenuController].menuVisible = NO; on UIMenuControllerWillShowMenuNotification, but I have not been able to get this to work. It has no affect with WillShowMenu. I can hide it in DidShowMenu but by that point it is too late and I get a menu flash.



I have also tried to locate it outside the visible area using [[UIMenuController sharedMenuController] setTargetRect:CGRectMake(0, 0, 1, 1) inView:self.extraView];, but again doing so with WillShowMenu has no affect and with DidShowMenu it is too late.



Experiments available here: https://github.com/dwieringa/WKWebViewEditMenuHidingTest



What am I missing? Is there another way to disable or hide the standard editting menu for WKWebView?










share|improve this question

























  • Out of curiosity have you filed a bug report with Apple for this?

    – Ryan
    Nov 19 '15 at 0:48











  • @Ryan, no not yet. Thanks for your answer below. I just tried it and I'm still seeing the menu when I long press on text under iOS 9 on my iPhone 6. Have you tried it with WKWebView on iOS? I verified with Web Inspector that the new CSS setting is applied to body.

    – davew
    Nov 19 '15 at 1:58











  • @davew any success with this?

    – Jed Grant
    Nov 29 '15 at 1:48











  • @JedGrant no, I've been living with the standard Editing menu for now. On Nov 19, I briefly tried Ryan's suggestion, but didn't get it to work and haven't had time to dig deeper.

    – davew
    Dec 1 '15 at 21:01














18












18








18


4






Requirement



I have a WKWebView and would like to remove the system menu items (Copy, Define, Share...) from the Edit Menu and present my own.



I am targeting iOS 8 and 9. I am currently testing with the Xcode 7.0.1 simulator (iOS 9) and my iPhone 6 running iOS 9.0.2.



Standard Method Does Not Work



I know the standard way of achieving this is by subclassing WKWebView and implementing
-canPerformAction:withSender:. However, I have found that with WKWebView -canPerformAction:withSender: is not being called for the copy: or define: actions. This appears to be a known bug (WKWebView and UIMenuController).



Example app: https://github.com/dwieringa/WKWebViewCustomEditMenuBug



@implementation MyWKWebView

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
NSLog(@"ACTION: %@", NSStringFromSelector(action));

if (action == @selector(delete:))
{
// adding Delete as test (works)
return YES;
}

// trying to remove everything else (does NOT work for Copy, Define, Share...)
return NO;
}

- (void)delete:(id)sender
{
NSLog(@"Delete menu item selected");
}

@end


Output: (note no copy: or define: action)



2015-10-20 12:28:32.864 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: cut:
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: select:
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: selectAll:
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: paste:
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: delete:
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _promptForReplace:
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _transliterateChinese:
2015-10-20 12:28:32.867 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _showTextStyleOptions:
2015-10-20 12:28:32.907 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _addShortcut:
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilitySpeak:
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilitySpeakLanguageSelection:
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilityPauseSpeaking:
2015-10-20 12:28:32.909 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: makeTextWritingDirectionRightToLeft:
2015-10-20 12:28:32.909 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: makeTextWritingDirectionLeftToRight:


Planned Workaround



My desire now is to completely hide the edit menu and replace it with a custom menu using QBPopupMenu.



My problem is that I have not been able to find a way to hide or disable the standard Edit menu. I have found some suggestions to hide it with [UIMenuController sharedMenuController].menuVisible = NO; on UIMenuControllerWillShowMenuNotification, but I have not been able to get this to work. It has no affect with WillShowMenu. I can hide it in DidShowMenu but by that point it is too late and I get a menu flash.



I have also tried to locate it outside the visible area using [[UIMenuController sharedMenuController] setTargetRect:CGRectMake(0, 0, 1, 1) inView:self.extraView];, but again doing so with WillShowMenu has no affect and with DidShowMenu it is too late.



Experiments available here: https://github.com/dwieringa/WKWebViewEditMenuHidingTest



What am I missing? Is there another way to disable or hide the standard editting menu for WKWebView?










share|improve this question
















Requirement



I have a WKWebView and would like to remove the system menu items (Copy, Define, Share...) from the Edit Menu and present my own.



I am targeting iOS 8 and 9. I am currently testing with the Xcode 7.0.1 simulator (iOS 9) and my iPhone 6 running iOS 9.0.2.



Standard Method Does Not Work



I know the standard way of achieving this is by subclassing WKWebView and implementing
-canPerformAction:withSender:. However, I have found that with WKWebView -canPerformAction:withSender: is not being called for the copy: or define: actions. This appears to be a known bug (WKWebView and UIMenuController).



Example app: https://github.com/dwieringa/WKWebViewCustomEditMenuBug



@implementation MyWKWebView

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
{
NSLog(@"ACTION: %@", NSStringFromSelector(action));

if (action == @selector(delete:))
{
// adding Delete as test (works)
return YES;
}

// trying to remove everything else (does NOT work for Copy, Define, Share...)
return NO;
}

- (void)delete:(id)sender
{
NSLog(@"Delete menu item selected");
}

@end


Output: (note no copy: or define: action)



2015-10-20 12:28:32.864 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: cut:
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: select:
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: selectAll:
2015-10-20 12:28:32.865 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: paste:
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: delete:
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _promptForReplace:
2015-10-20 12:28:32.866 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _transliterateChinese:
2015-10-20 12:28:32.867 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _showTextStyleOptions:
2015-10-20 12:28:32.907 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _addShortcut:
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilitySpeak:
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilitySpeakLanguageSelection:
2015-10-20 12:28:32.908 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: _accessibilityPauseSpeaking:
2015-10-20 12:28:32.909 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: makeTextWritingDirectionRightToLeft:
2015-10-20 12:28:32.909 WKWebViewCustomEditMenuBug[45804:21121480] ACTION: makeTextWritingDirectionLeftToRight:


Planned Workaround



My desire now is to completely hide the edit menu and replace it with a custom menu using QBPopupMenu.



My problem is that I have not been able to find a way to hide or disable the standard Edit menu. I have found some suggestions to hide it with [UIMenuController sharedMenuController].menuVisible = NO; on UIMenuControllerWillShowMenuNotification, but I have not been able to get this to work. It has no affect with WillShowMenu. I can hide it in DidShowMenu but by that point it is too late and I get a menu flash.



I have also tried to locate it outside the visible area using [[UIMenuController sharedMenuController] setTargetRect:CGRectMake(0, 0, 1, 1) inView:self.extraView];, but again doing so with WillShowMenu has no affect and with DidShowMenu it is too late.



Experiments available here: https://github.com/dwieringa/WKWebViewEditMenuHidingTest



What am I missing? Is there another way to disable or hide the standard editting menu for WKWebView?







ios wkwebview uimenucontroller






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited May 23 '17 at 11:47









Community

11




11










asked Oct 20 '15 at 17:37









davewdavew

763825




763825













  • Out of curiosity have you filed a bug report with Apple for this?

    – Ryan
    Nov 19 '15 at 0:48











  • @Ryan, no not yet. Thanks for your answer below. I just tried it and I'm still seeing the menu when I long press on text under iOS 9 on my iPhone 6. Have you tried it with WKWebView on iOS? I verified with Web Inspector that the new CSS setting is applied to body.

    – davew
    Nov 19 '15 at 1:58











  • @davew any success with this?

    – Jed Grant
    Nov 29 '15 at 1:48











  • @JedGrant no, I've been living with the standard Editing menu for now. On Nov 19, I briefly tried Ryan's suggestion, but didn't get it to work and haven't had time to dig deeper.

    – davew
    Dec 1 '15 at 21:01



















  • Out of curiosity have you filed a bug report with Apple for this?

    – Ryan
    Nov 19 '15 at 0:48











  • @Ryan, no not yet. Thanks for your answer below. I just tried it and I'm still seeing the menu when I long press on text under iOS 9 on my iPhone 6. Have you tried it with WKWebView on iOS? I verified with Web Inspector that the new CSS setting is applied to body.

    – davew
    Nov 19 '15 at 1:58











  • @davew any success with this?

    – Jed Grant
    Nov 29 '15 at 1:48











  • @JedGrant no, I've been living with the standard Editing menu for now. On Nov 19, I briefly tried Ryan's suggestion, but didn't get it to work and haven't had time to dig deeper.

    – davew
    Dec 1 '15 at 21:01

















Out of curiosity have you filed a bug report with Apple for this?

– Ryan
Nov 19 '15 at 0:48





Out of curiosity have you filed a bug report with Apple for this?

– Ryan
Nov 19 '15 at 0:48













@Ryan, no not yet. Thanks for your answer below. I just tried it and I'm still seeing the menu when I long press on text under iOS 9 on my iPhone 6. Have you tried it with WKWebView on iOS? I verified with Web Inspector that the new CSS setting is applied to body.

– davew
Nov 19 '15 at 1:58





@Ryan, no not yet. Thanks for your answer below. I just tried it and I'm still seeing the menu when I long press on text under iOS 9 on my iPhone 6. Have you tried it with WKWebView on iOS? I verified with Web Inspector that the new CSS setting is applied to body.

– davew
Nov 19 '15 at 1:58













@davew any success with this?

– Jed Grant
Nov 29 '15 at 1:48





@davew any success with this?

– Jed Grant
Nov 29 '15 at 1:48













@JedGrant no, I've been living with the standard Editing menu for now. On Nov 19, I briefly tried Ryan's suggestion, but didn't get it to work and haven't had time to dig deeper.

– davew
Dec 1 '15 at 21:01





@JedGrant no, I've been living with the standard Editing menu for now. On Nov 19, I briefly tried Ryan's suggestion, but didn't get it to work and haven't had time to dig deeper.

– davew
Dec 1 '15 at 21:01












10 Answers
10






active

oldest

votes


















6














Try making your view controller become first responder and stop it from resigning first responder



- (BOOL)canResignFirstResponder {
return NO;
}

- (BOOL)canBecomeFirstResponder {
return YES;
}


https://github.com/dwieringa/WKWebViewEditMenuHidingTest/pull/1






share|improve this answer
























  • This appears to have solved it for me.

    – Jon Brooks
    Feb 26 '16 at 2:00











  • This is correct answer. I have used the same in swift 3, xcode 8.2 and worked fine. Here is the swift code. override var canBecomeFirstResponder: Bool { return true } override var canResignFirstResponder: Bool { return false }

    – Vijay
    Jan 13 '17 at 3:17











  • Does not work for WkWebView

    – Vitaliy Litvinov
    Apr 26 '17 at 14:20











  • This is problematic if you have text input in your WKWebView.

    – André Morujão
    Dec 19 '17 at 16:54



















5














Based on your workaround, I found out that:



-(void)menuWillShow:(NSNotification *)notification
{
NSLog(@"MENU WILL SHOW");

dispatch_async(dispatch_get_main_queue(), ^{
[[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
});

}


Will prevent the menu from flashing 90% of the times.. Still not good enough, but it's another workaround before we find a decent solution.






share|improve this answer
























  • I'm OK with this. +1

    – Ahmed Khalaf
    Oct 24 '17 at 8:39






  • 1





    Not sure if this changed since you posted, but for me this is working (as in, the menu is never actually displayed) 100% of the time after trying at least 30 times :)

    – André Morujão
    Jan 9 '18 at 16:08











  • I don't even work on that project anymore, but that's good to know :)

    – Paulo Cesar
    Jan 10 '18 at 15:15



















2














Hey guys after spending a hours on it, i found dirty solution with %100 success rate.



Logic is; detect when UIMenuController did shown and update it.



In your ViewController(containing WKWebView) add UIMenuControllerDidShowMenu observer in viewDidLoad() like this;



override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(
self,
selector: #selector(uiMenuViewControllerDidShowMenu),
name: NSNotification.Name.UIMenuControllerDidShowMenu,
object: nil)
}


Don't forget to remove observer in deinit.



    deinit {
NotificationCenter.default.removeObserver(
self,
name: NSNotification.Name.UIMenuControllerDidShowMenu,
object: nil)
}


And in your selector, update UIMenuController like this:



func uiMenuViewControllerDidShowMenu() {
if longPress {
let menuController = UIMenuController.shared
menuController.setMenuVisible(false, animated: false)
menuController.update() //You can only call this and it will still work as expected but i also call setMenuVisible just to make sure.
}
}


In your ViewController who ever calls the UIMenuController, this method will get called. I am developing browser app so i have also searchBar and user may want to paste text to there. Because of that i detect longPress in my webview and check if UIMenuController is summoned by WKWebView.



This solution will behave like in gif. You can see menu for a second but you can't tap it. You can try to tap it before it fades away but you won't succeed. Please try and tell me your results.



I hope it helps someone.



Cheers.



enter image description here






share|improve this answer
























  • hi how can we do this in objective c?

    – coder
    Nov 23 '17 at 9:08











  • Paulo Cesar's solution avoids showing the menu for that fraction of a second: stackoverflow.com/a/34228687/374516

    – André Morujão
    Jan 9 '18 at 15:24



















2














This bug is actually caused by the actions being added in the WKContentView, which is a private class. You could add a UIView extension to work around it like this:



import UIKit

extension UIView {

open override class func initialize() {
guard NSStringFromClass(self) == "WKContentView" else { return }

swizzleMethod(#selector(canPerformAction), withSelector: #selector(swizzledCanPerformAction))
}

fileprivate class func swizzleMethod(_ selector: Selector, withSelector: Selector) {
let originalSelector = class_getInstanceMethod(self, selector)
let swizzledSelector = class_getInstanceMethod(self, withSelector)
method_exchangeImplementations(originalSelector, swizzledSelector)
}

@objc fileprivate func swizzledCanPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
return false
}
}





share|improve this answer



















  • 1





    This solution does not compile in Swift 4. I get the following error message: "Method 'initialize()' defines Objective-C class method 'initialize', which is not permitted by Swift"

    – Frédéric Adda
    Mar 6 '18 at 13:22











  • @FrédéricAdda did you find any solution to this?. regarding Method initialize().

    – Srini
    Jan 8 at 11:58













  • @Srini, yes, I posted it below: stackoverflow.com/a/54095482/1552730

    – Frédéric Adda
    Jan 8 at 16:04



















1














I Fixed it after some observation.



In -canPerformAction:withSender: I am returning NO for _share and _define options as I don't need them in my project. It works as expected on selection of word for first time, but shows up the options from second time.



Simple fix: Add [self becomeFirstResponder]; in tapGuesture or Touch delegate methods



-(BOOL)canPerformAction:(SEL)action withSender:(id)sender {
SEL defineSEL = NSSelectorFromString(@"_define:");
if(action == defineSEL){
return NO;
}

SEL shareSEL = NSSelectorFromString(@"_share:");
if(action == shareSEL){
return NO;
}
return YES;
}

// Tap gesture delegate method
- (void)singleTap:(UITapGestureRecognizer *)sender {
lastTouchPoint = [sender locationInView:self.webView];
[self becomeFirstResponder]; //added this line to fix the issue//
}





share|improve this answer

































    1














    Here's my final solution, adapted from the solutions posted here. The key is to listen for the UIMenuControllerWillShowMenu notification and then Dispatch.main.async to hide the menu. This seems to do the trick to avoid the flashing menu.



    My example uses a UITextField, but it should be easily adapted to a WKWebView.



    class NoMenuTextField: UITextField {

    override func didMoveToSuperview() {
    super.didMoveToSuperview()
    if superview == nil {
    deregisterForMenuNotifications()
    } else {
    registerForMenuNotifications()
    }
    }

    func registerForMenuNotifications() {
    NotificationCenter.default.addObserver(forName: Notification.Name.UIMenuControllerWillShowMenu,
    object: nil,
    queue: OperationQueue.main)
    { _ in
    DispatchQueue.main.async {
    UIMenuController.shared.setMenuVisible(false, animated: false)
    UIMenuController.shared.update()
    }
    }
    }

    func deregisterForMenuNotifications() {
    NotificationCenter.default.removeObserver(self,
    name: Notification.Name.UIMenuControllerWillShowMenu,
    object: nil)
    }
    }





    share|improve this answer































      1














      I tried the solution from Stephan Heilner but it didn't compile in Swift 4.



      This is my implementation to disable the menuController in a WKWebView that works with Swift 4.



      In my WKWebView subclass, I added these property and function :



      var wkContentView: UIView? {
      return self.subviewWithClassName("WKContentView")
      }


      private func swizzleResponderChainAction() {
      wkContentView?.swizzlePerformAction()
      }


      Then, I added an extension in the same file, but out of the WKWebView subclass :



      // MARK: - Extension used for the swizzling part linked to wkContentView (see above)
      extension UIView {

      /// Find a subview corresponding to the className parameter, recursively.
      func subviewWithClassName(_ className: String) -> UIView? {

      if NSStringFromClass(type(of: self)) == className {
      return self
      } else {
      for subview in subviews {
      return subview.subviewWithClassName(className)
      }
      }
      return nil
      }

      func swizzlePerformAction() {
      swizzleMethod(#selector(canPerformAction), withSelector: #selector(swizzledCanPerformAction))
      }

      private func swizzleMethod(_ currentSelector: Selector, withSelector newSelector: Selector) {
      if let currentMethod = self.instanceMethod(for: currentSelector),
      let newMethod = self.instanceMethod(for:newSelector) {
      let newImplementation = method_getImplementation(newMethod)
      method_setImplementation(currentMethod, newImplementation)
      } else {
      print("Could not find originalSelector")
      }
      }

      private func instanceMethod(for selector: Selector) -> Method? {
      let classType = type(of: self)
      return class_getInstanceMethod(classType, selector)
      }

      @objc private func swizzledCanPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
      return false
      }
      }


      And finally, I called the swizzleResponderChainAction() function from the initializer (you can either override the designated initializer, or create a convenience one):



      override init(frame: CGRect, configuration: WKWebViewConfiguration) {
      super.init(frame: frame, configuration: configuration)

      swizzleResponderChainAction()
      }


      Now, the WKWebView does not crash anymore when using a UIMenuController.






      share|improve this answer


























      • I tried your solution in my code, but the UIMenuController not disabled.Still it appears on selection. Also the swizzleMethod not called.

        – Srini
        Jan 25 at 6:45











      • Sorry, I forgot to precise that you have to call the new swizzled function from the initializer. That's fixed now. Thanks!

        – Frédéric Adda
        Jan 26 at 7:16











      • Thank you so much. it is working fine now

        – Srini
        Jan 29 at 7:15



















      0














      One way that I've used is to simply disable the menu using CSS. The CSS property is called -webkit-touch-callout: none;. You can apply it to the top level element and disable it for the whole page or any child element and disable it with more precision. Hope that helps.






      share|improve this answer































        0














        pragma mark - WKNavigationDelegate



        - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
        // Add:
        // Disable LongPress and Selection, no more UIMenucontroller
        [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none'" completionHandler:nil];
        [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none'" completionHandler:nil]; }





        share|improve this answer
























        • always show after doing this

          – Shauket Sheikh
          Oct 31 '18 at 3:18



















        0














        In iOS 11, I have found a simple solution by an extension of WKWebView. I have not checked to see if this will work in earlier versions of iOS. The following is a simple example with one menu item.



        import UIKit
        import WebKit

        extension WKWebView {

        override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        switch action {
        case #selector(highlightHandler):
        return true
        default:
        return false
        }
        }

        func createEditMenu() { // Should be called once
        let highlight = UIMenuItem(title: "Highlight", action: #selector(highlightHandler))
        menuItems.append(highlight)
        UIMenuController.shared.menuItems = [highlight]
        }

        @objc func highlightHandler(sender: UIMenuItem) {
        print("highlight clicked")
        }
        }





        share|improve this answer























          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f33243230%2fdisable-entire-uimenucontroller-edit-menu-in-wkwebview%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          10 Answers
          10






          active

          oldest

          votes








          10 Answers
          10






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          6














          Try making your view controller become first responder and stop it from resigning first responder



          - (BOOL)canResignFirstResponder {
          return NO;
          }

          - (BOOL)canBecomeFirstResponder {
          return YES;
          }


          https://github.com/dwieringa/WKWebViewEditMenuHidingTest/pull/1






          share|improve this answer
























          • This appears to have solved it for me.

            – Jon Brooks
            Feb 26 '16 at 2:00











          • This is correct answer. I have used the same in swift 3, xcode 8.2 and worked fine. Here is the swift code. override var canBecomeFirstResponder: Bool { return true } override var canResignFirstResponder: Bool { return false }

            – Vijay
            Jan 13 '17 at 3:17











          • Does not work for WkWebView

            – Vitaliy Litvinov
            Apr 26 '17 at 14:20











          • This is problematic if you have text input in your WKWebView.

            – André Morujão
            Dec 19 '17 at 16:54
















          6














          Try making your view controller become first responder and stop it from resigning first responder



          - (BOOL)canResignFirstResponder {
          return NO;
          }

          - (BOOL)canBecomeFirstResponder {
          return YES;
          }


          https://github.com/dwieringa/WKWebViewEditMenuHidingTest/pull/1






          share|improve this answer
























          • This appears to have solved it for me.

            – Jon Brooks
            Feb 26 '16 at 2:00











          • This is correct answer. I have used the same in swift 3, xcode 8.2 and worked fine. Here is the swift code. override var canBecomeFirstResponder: Bool { return true } override var canResignFirstResponder: Bool { return false }

            – Vijay
            Jan 13 '17 at 3:17











          • Does not work for WkWebView

            – Vitaliy Litvinov
            Apr 26 '17 at 14:20











          • This is problematic if you have text input in your WKWebView.

            – André Morujão
            Dec 19 '17 at 16:54














          6












          6








          6







          Try making your view controller become first responder and stop it from resigning first responder



          - (BOOL)canResignFirstResponder {
          return NO;
          }

          - (BOOL)canBecomeFirstResponder {
          return YES;
          }


          https://github.com/dwieringa/WKWebViewEditMenuHidingTest/pull/1






          share|improve this answer













          Try making your view controller become first responder and stop it from resigning first responder



          - (BOOL)canResignFirstResponder {
          return NO;
          }

          - (BOOL)canBecomeFirstResponder {
          return YES;
          }


          https://github.com/dwieringa/WKWebViewEditMenuHidingTest/pull/1







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Feb 7 '16 at 1:16









          ranunezranunez

          31829




          31829













          • This appears to have solved it for me.

            – Jon Brooks
            Feb 26 '16 at 2:00











          • This is correct answer. I have used the same in swift 3, xcode 8.2 and worked fine. Here is the swift code. override var canBecomeFirstResponder: Bool { return true } override var canResignFirstResponder: Bool { return false }

            – Vijay
            Jan 13 '17 at 3:17











          • Does not work for WkWebView

            – Vitaliy Litvinov
            Apr 26 '17 at 14:20











          • This is problematic if you have text input in your WKWebView.

            – André Morujão
            Dec 19 '17 at 16:54



















          • This appears to have solved it for me.

            – Jon Brooks
            Feb 26 '16 at 2:00











          • This is correct answer. I have used the same in swift 3, xcode 8.2 and worked fine. Here is the swift code. override var canBecomeFirstResponder: Bool { return true } override var canResignFirstResponder: Bool { return false }

            – Vijay
            Jan 13 '17 at 3:17











          • Does not work for WkWebView

            – Vitaliy Litvinov
            Apr 26 '17 at 14:20











          • This is problematic if you have text input in your WKWebView.

            – André Morujão
            Dec 19 '17 at 16:54

















          This appears to have solved it for me.

          – Jon Brooks
          Feb 26 '16 at 2:00





          This appears to have solved it for me.

          – Jon Brooks
          Feb 26 '16 at 2:00













          This is correct answer. I have used the same in swift 3, xcode 8.2 and worked fine. Here is the swift code. override var canBecomeFirstResponder: Bool { return true } override var canResignFirstResponder: Bool { return false }

          – Vijay
          Jan 13 '17 at 3:17





          This is correct answer. I have used the same in swift 3, xcode 8.2 and worked fine. Here is the swift code. override var canBecomeFirstResponder: Bool { return true } override var canResignFirstResponder: Bool { return false }

          – Vijay
          Jan 13 '17 at 3:17













          Does not work for WkWebView

          – Vitaliy Litvinov
          Apr 26 '17 at 14:20





          Does not work for WkWebView

          – Vitaliy Litvinov
          Apr 26 '17 at 14:20













          This is problematic if you have text input in your WKWebView.

          – André Morujão
          Dec 19 '17 at 16:54





          This is problematic if you have text input in your WKWebView.

          – André Morujão
          Dec 19 '17 at 16:54













          5














          Based on your workaround, I found out that:



          -(void)menuWillShow:(NSNotification *)notification
          {
          NSLog(@"MENU WILL SHOW");

          dispatch_async(dispatch_get_main_queue(), ^{
          [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
          });

          }


          Will prevent the menu from flashing 90% of the times.. Still not good enough, but it's another workaround before we find a decent solution.






          share|improve this answer
























          • I'm OK with this. +1

            – Ahmed Khalaf
            Oct 24 '17 at 8:39






          • 1





            Not sure if this changed since you posted, but for me this is working (as in, the menu is never actually displayed) 100% of the time after trying at least 30 times :)

            – André Morujão
            Jan 9 '18 at 16:08











          • I don't even work on that project anymore, but that's good to know :)

            – Paulo Cesar
            Jan 10 '18 at 15:15
















          5














          Based on your workaround, I found out that:



          -(void)menuWillShow:(NSNotification *)notification
          {
          NSLog(@"MENU WILL SHOW");

          dispatch_async(dispatch_get_main_queue(), ^{
          [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
          });

          }


          Will prevent the menu from flashing 90% of the times.. Still not good enough, but it's another workaround before we find a decent solution.






          share|improve this answer
























          • I'm OK with this. +1

            – Ahmed Khalaf
            Oct 24 '17 at 8:39






          • 1





            Not sure if this changed since you posted, but for me this is working (as in, the menu is never actually displayed) 100% of the time after trying at least 30 times :)

            – André Morujão
            Jan 9 '18 at 16:08











          • I don't even work on that project anymore, but that's good to know :)

            – Paulo Cesar
            Jan 10 '18 at 15:15














          5












          5








          5







          Based on your workaround, I found out that:



          -(void)menuWillShow:(NSNotification *)notification
          {
          NSLog(@"MENU WILL SHOW");

          dispatch_async(dispatch_get_main_queue(), ^{
          [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
          });

          }


          Will prevent the menu from flashing 90% of the times.. Still not good enough, but it's another workaround before we find a decent solution.






          share|improve this answer













          Based on your workaround, I found out that:



          -(void)menuWillShow:(NSNotification *)notification
          {
          NSLog(@"MENU WILL SHOW");

          dispatch_async(dispatch_get_main_queue(), ^{
          [[UIMenuController sharedMenuController] setMenuVisible:NO animated:NO];
          });

          }


          Will prevent the menu from flashing 90% of the times.. Still not good enough, but it's another workaround before we find a decent solution.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Dec 11 '15 at 16:57









          Paulo CesarPaulo Cesar

          1,42011829




          1,42011829













          • I'm OK with this. +1

            – Ahmed Khalaf
            Oct 24 '17 at 8:39






          • 1





            Not sure if this changed since you posted, but for me this is working (as in, the menu is never actually displayed) 100% of the time after trying at least 30 times :)

            – André Morujão
            Jan 9 '18 at 16:08











          • I don't even work on that project anymore, but that's good to know :)

            – Paulo Cesar
            Jan 10 '18 at 15:15



















          • I'm OK with this. +1

            – Ahmed Khalaf
            Oct 24 '17 at 8:39






          • 1





            Not sure if this changed since you posted, but for me this is working (as in, the menu is never actually displayed) 100% of the time after trying at least 30 times :)

            – André Morujão
            Jan 9 '18 at 16:08











          • I don't even work on that project anymore, but that's good to know :)

            – Paulo Cesar
            Jan 10 '18 at 15:15

















          I'm OK with this. +1

          – Ahmed Khalaf
          Oct 24 '17 at 8:39





          I'm OK with this. +1

          – Ahmed Khalaf
          Oct 24 '17 at 8:39




          1




          1





          Not sure if this changed since you posted, but for me this is working (as in, the menu is never actually displayed) 100% of the time after trying at least 30 times :)

          – André Morujão
          Jan 9 '18 at 16:08





          Not sure if this changed since you posted, but for me this is working (as in, the menu is never actually displayed) 100% of the time after trying at least 30 times :)

          – André Morujão
          Jan 9 '18 at 16:08













          I don't even work on that project anymore, but that's good to know :)

          – Paulo Cesar
          Jan 10 '18 at 15:15





          I don't even work on that project anymore, but that's good to know :)

          – Paulo Cesar
          Jan 10 '18 at 15:15











          2














          Hey guys after spending a hours on it, i found dirty solution with %100 success rate.



          Logic is; detect when UIMenuController did shown and update it.



          In your ViewController(containing WKWebView) add UIMenuControllerDidShowMenu observer in viewDidLoad() like this;



          override func viewDidLoad() {
          super.viewDidLoad()
          NotificationCenter.default.addObserver(
          self,
          selector: #selector(uiMenuViewControllerDidShowMenu),
          name: NSNotification.Name.UIMenuControllerDidShowMenu,
          object: nil)
          }


          Don't forget to remove observer in deinit.



              deinit {
          NotificationCenter.default.removeObserver(
          self,
          name: NSNotification.Name.UIMenuControllerDidShowMenu,
          object: nil)
          }


          And in your selector, update UIMenuController like this:



          func uiMenuViewControllerDidShowMenu() {
          if longPress {
          let menuController = UIMenuController.shared
          menuController.setMenuVisible(false, animated: false)
          menuController.update() //You can only call this and it will still work as expected but i also call setMenuVisible just to make sure.
          }
          }


          In your ViewController who ever calls the UIMenuController, this method will get called. I am developing browser app so i have also searchBar and user may want to paste text to there. Because of that i detect longPress in my webview and check if UIMenuController is summoned by WKWebView.



          This solution will behave like in gif. You can see menu for a second but you can't tap it. You can try to tap it before it fades away but you won't succeed. Please try and tell me your results.



          I hope it helps someone.



          Cheers.



          enter image description here






          share|improve this answer
























          • hi how can we do this in objective c?

            – coder
            Nov 23 '17 at 9:08











          • Paulo Cesar's solution avoids showing the menu for that fraction of a second: stackoverflow.com/a/34228687/374516

            – André Morujão
            Jan 9 '18 at 15:24
















          2














          Hey guys after spending a hours on it, i found dirty solution with %100 success rate.



          Logic is; detect when UIMenuController did shown and update it.



          In your ViewController(containing WKWebView) add UIMenuControllerDidShowMenu observer in viewDidLoad() like this;



          override func viewDidLoad() {
          super.viewDidLoad()
          NotificationCenter.default.addObserver(
          self,
          selector: #selector(uiMenuViewControllerDidShowMenu),
          name: NSNotification.Name.UIMenuControllerDidShowMenu,
          object: nil)
          }


          Don't forget to remove observer in deinit.



              deinit {
          NotificationCenter.default.removeObserver(
          self,
          name: NSNotification.Name.UIMenuControllerDidShowMenu,
          object: nil)
          }


          And in your selector, update UIMenuController like this:



          func uiMenuViewControllerDidShowMenu() {
          if longPress {
          let menuController = UIMenuController.shared
          menuController.setMenuVisible(false, animated: false)
          menuController.update() //You can only call this and it will still work as expected but i also call setMenuVisible just to make sure.
          }
          }


          In your ViewController who ever calls the UIMenuController, this method will get called. I am developing browser app so i have also searchBar and user may want to paste text to there. Because of that i detect longPress in my webview and check if UIMenuController is summoned by WKWebView.



          This solution will behave like in gif. You can see menu for a second but you can't tap it. You can try to tap it before it fades away but you won't succeed. Please try and tell me your results.



          I hope it helps someone.



          Cheers.



          enter image description here






          share|improve this answer
























          • hi how can we do this in objective c?

            – coder
            Nov 23 '17 at 9:08











          • Paulo Cesar's solution avoids showing the menu for that fraction of a second: stackoverflow.com/a/34228687/374516

            – André Morujão
            Jan 9 '18 at 15:24














          2












          2








          2







          Hey guys after spending a hours on it, i found dirty solution with %100 success rate.



          Logic is; detect when UIMenuController did shown and update it.



          In your ViewController(containing WKWebView) add UIMenuControllerDidShowMenu observer in viewDidLoad() like this;



          override func viewDidLoad() {
          super.viewDidLoad()
          NotificationCenter.default.addObserver(
          self,
          selector: #selector(uiMenuViewControllerDidShowMenu),
          name: NSNotification.Name.UIMenuControllerDidShowMenu,
          object: nil)
          }


          Don't forget to remove observer in deinit.



              deinit {
          NotificationCenter.default.removeObserver(
          self,
          name: NSNotification.Name.UIMenuControllerDidShowMenu,
          object: nil)
          }


          And in your selector, update UIMenuController like this:



          func uiMenuViewControllerDidShowMenu() {
          if longPress {
          let menuController = UIMenuController.shared
          menuController.setMenuVisible(false, animated: false)
          menuController.update() //You can only call this and it will still work as expected but i also call setMenuVisible just to make sure.
          }
          }


          In your ViewController who ever calls the UIMenuController, this method will get called. I am developing browser app so i have also searchBar and user may want to paste text to there. Because of that i detect longPress in my webview and check if UIMenuController is summoned by WKWebView.



          This solution will behave like in gif. You can see menu for a second but you can't tap it. You can try to tap it before it fades away but you won't succeed. Please try and tell me your results.



          I hope it helps someone.



          Cheers.



          enter image description here






          share|improve this answer













          Hey guys after spending a hours on it, i found dirty solution with %100 success rate.



          Logic is; detect when UIMenuController did shown and update it.



          In your ViewController(containing WKWebView) add UIMenuControllerDidShowMenu observer in viewDidLoad() like this;



          override func viewDidLoad() {
          super.viewDidLoad()
          NotificationCenter.default.addObserver(
          self,
          selector: #selector(uiMenuViewControllerDidShowMenu),
          name: NSNotification.Name.UIMenuControllerDidShowMenu,
          object: nil)
          }


          Don't forget to remove observer in deinit.



              deinit {
          NotificationCenter.default.removeObserver(
          self,
          name: NSNotification.Name.UIMenuControllerDidShowMenu,
          object: nil)
          }


          And in your selector, update UIMenuController like this:



          func uiMenuViewControllerDidShowMenu() {
          if longPress {
          let menuController = UIMenuController.shared
          menuController.setMenuVisible(false, animated: false)
          menuController.update() //You can only call this and it will still work as expected but i also call setMenuVisible just to make sure.
          }
          }


          In your ViewController who ever calls the UIMenuController, this method will get called. I am developing browser app so i have also searchBar and user may want to paste text to there. Because of that i detect longPress in my webview and check if UIMenuController is summoned by WKWebView.



          This solution will behave like in gif. You can see menu for a second but you can't tap it. You can try to tap it before it fades away but you won't succeed. Please try and tell me your results.



          I hope it helps someone.



          Cheers.



          enter image description here







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Feb 28 '17 at 14:01









          Yasin NazlıcanYasin Nazlıcan

          304414




          304414













          • hi how can we do this in objective c?

            – coder
            Nov 23 '17 at 9:08











          • Paulo Cesar's solution avoids showing the menu for that fraction of a second: stackoverflow.com/a/34228687/374516

            – André Morujão
            Jan 9 '18 at 15:24



















          • hi how can we do this in objective c?

            – coder
            Nov 23 '17 at 9:08











          • Paulo Cesar's solution avoids showing the menu for that fraction of a second: stackoverflow.com/a/34228687/374516

            – André Morujão
            Jan 9 '18 at 15:24

















          hi how can we do this in objective c?

          – coder
          Nov 23 '17 at 9:08





          hi how can we do this in objective c?

          – coder
          Nov 23 '17 at 9:08













          Paulo Cesar's solution avoids showing the menu for that fraction of a second: stackoverflow.com/a/34228687/374516

          – André Morujão
          Jan 9 '18 at 15:24





          Paulo Cesar's solution avoids showing the menu for that fraction of a second: stackoverflow.com/a/34228687/374516

          – André Morujão
          Jan 9 '18 at 15:24











          2














          This bug is actually caused by the actions being added in the WKContentView, which is a private class. You could add a UIView extension to work around it like this:



          import UIKit

          extension UIView {

          open override class func initialize() {
          guard NSStringFromClass(self) == "WKContentView" else { return }

          swizzleMethod(#selector(canPerformAction), withSelector: #selector(swizzledCanPerformAction))
          }

          fileprivate class func swizzleMethod(_ selector: Selector, withSelector: Selector) {
          let originalSelector = class_getInstanceMethod(self, selector)
          let swizzledSelector = class_getInstanceMethod(self, withSelector)
          method_exchangeImplementations(originalSelector, swizzledSelector)
          }

          @objc fileprivate func swizzledCanPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
          return false
          }
          }





          share|improve this answer



















          • 1





            This solution does not compile in Swift 4. I get the following error message: "Method 'initialize()' defines Objective-C class method 'initialize', which is not permitted by Swift"

            – Frédéric Adda
            Mar 6 '18 at 13:22











          • @FrédéricAdda did you find any solution to this?. regarding Method initialize().

            – Srini
            Jan 8 at 11:58













          • @Srini, yes, I posted it below: stackoverflow.com/a/54095482/1552730

            – Frédéric Adda
            Jan 8 at 16:04
















          2














          This bug is actually caused by the actions being added in the WKContentView, which is a private class. You could add a UIView extension to work around it like this:



          import UIKit

          extension UIView {

          open override class func initialize() {
          guard NSStringFromClass(self) == "WKContentView" else { return }

          swizzleMethod(#selector(canPerformAction), withSelector: #selector(swizzledCanPerformAction))
          }

          fileprivate class func swizzleMethod(_ selector: Selector, withSelector: Selector) {
          let originalSelector = class_getInstanceMethod(self, selector)
          let swizzledSelector = class_getInstanceMethod(self, withSelector)
          method_exchangeImplementations(originalSelector, swizzledSelector)
          }

          @objc fileprivate func swizzledCanPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
          return false
          }
          }





          share|improve this answer



















          • 1





            This solution does not compile in Swift 4. I get the following error message: "Method 'initialize()' defines Objective-C class method 'initialize', which is not permitted by Swift"

            – Frédéric Adda
            Mar 6 '18 at 13:22











          • @FrédéricAdda did you find any solution to this?. regarding Method initialize().

            – Srini
            Jan 8 at 11:58













          • @Srini, yes, I posted it below: stackoverflow.com/a/54095482/1552730

            – Frédéric Adda
            Jan 8 at 16:04














          2












          2








          2







          This bug is actually caused by the actions being added in the WKContentView, which is a private class. You could add a UIView extension to work around it like this:



          import UIKit

          extension UIView {

          open override class func initialize() {
          guard NSStringFromClass(self) == "WKContentView" else { return }

          swizzleMethod(#selector(canPerformAction), withSelector: #selector(swizzledCanPerformAction))
          }

          fileprivate class func swizzleMethod(_ selector: Selector, withSelector: Selector) {
          let originalSelector = class_getInstanceMethod(self, selector)
          let swizzledSelector = class_getInstanceMethod(self, withSelector)
          method_exchangeImplementations(originalSelector, swizzledSelector)
          }

          @objc fileprivate func swizzledCanPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
          return false
          }
          }





          share|improve this answer













          This bug is actually caused by the actions being added in the WKContentView, which is a private class. You could add a UIView extension to work around it like this:



          import UIKit

          extension UIView {

          open override class func initialize() {
          guard NSStringFromClass(self) == "WKContentView" else { return }

          swizzleMethod(#selector(canPerformAction), withSelector: #selector(swizzledCanPerformAction))
          }

          fileprivate class func swizzleMethod(_ selector: Selector, withSelector: Selector) {
          let originalSelector = class_getInstanceMethod(self, selector)
          let swizzledSelector = class_getInstanceMethod(self, withSelector)
          method_exchangeImplementations(originalSelector, swizzledSelector)
          }

          @objc fileprivate func swizzledCanPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
          return false
          }
          }






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Mar 23 '17 at 19:35









          Stephan HeilnerStephan Heilner

          50239




          50239








          • 1





            This solution does not compile in Swift 4. I get the following error message: "Method 'initialize()' defines Objective-C class method 'initialize', which is not permitted by Swift"

            – Frédéric Adda
            Mar 6 '18 at 13:22











          • @FrédéricAdda did you find any solution to this?. regarding Method initialize().

            – Srini
            Jan 8 at 11:58













          • @Srini, yes, I posted it below: stackoverflow.com/a/54095482/1552730

            – Frédéric Adda
            Jan 8 at 16:04














          • 1





            This solution does not compile in Swift 4. I get the following error message: "Method 'initialize()' defines Objective-C class method 'initialize', which is not permitted by Swift"

            – Frédéric Adda
            Mar 6 '18 at 13:22











          • @FrédéricAdda did you find any solution to this?. regarding Method initialize().

            – Srini
            Jan 8 at 11:58













          • @Srini, yes, I posted it below: stackoverflow.com/a/54095482/1552730

            – Frédéric Adda
            Jan 8 at 16:04








          1




          1





          This solution does not compile in Swift 4. I get the following error message: "Method 'initialize()' defines Objective-C class method 'initialize', which is not permitted by Swift"

          – Frédéric Adda
          Mar 6 '18 at 13:22





          This solution does not compile in Swift 4. I get the following error message: "Method 'initialize()' defines Objective-C class method 'initialize', which is not permitted by Swift"

          – Frédéric Adda
          Mar 6 '18 at 13:22













          @FrédéricAdda did you find any solution to this?. regarding Method initialize().

          – Srini
          Jan 8 at 11:58







          @FrédéricAdda did you find any solution to this?. regarding Method initialize().

          – Srini
          Jan 8 at 11:58















          @Srini, yes, I posted it below: stackoverflow.com/a/54095482/1552730

          – Frédéric Adda
          Jan 8 at 16:04





          @Srini, yes, I posted it below: stackoverflow.com/a/54095482/1552730

          – Frédéric Adda
          Jan 8 at 16:04











          1














          I Fixed it after some observation.



          In -canPerformAction:withSender: I am returning NO for _share and _define options as I don't need them in my project. It works as expected on selection of word for first time, but shows up the options from second time.



          Simple fix: Add [self becomeFirstResponder]; in tapGuesture or Touch delegate methods



          -(BOOL)canPerformAction:(SEL)action withSender:(id)sender {
          SEL defineSEL = NSSelectorFromString(@"_define:");
          if(action == defineSEL){
          return NO;
          }

          SEL shareSEL = NSSelectorFromString(@"_share:");
          if(action == shareSEL){
          return NO;
          }
          return YES;
          }

          // Tap gesture delegate method
          - (void)singleTap:(UITapGestureRecognizer *)sender {
          lastTouchPoint = [sender locationInView:self.webView];
          [self becomeFirstResponder]; //added this line to fix the issue//
          }





          share|improve this answer






























            1














            I Fixed it after some observation.



            In -canPerformAction:withSender: I am returning NO for _share and _define options as I don't need them in my project. It works as expected on selection of word for first time, but shows up the options from second time.



            Simple fix: Add [self becomeFirstResponder]; in tapGuesture or Touch delegate methods



            -(BOOL)canPerformAction:(SEL)action withSender:(id)sender {
            SEL defineSEL = NSSelectorFromString(@"_define:");
            if(action == defineSEL){
            return NO;
            }

            SEL shareSEL = NSSelectorFromString(@"_share:");
            if(action == shareSEL){
            return NO;
            }
            return YES;
            }

            // Tap gesture delegate method
            - (void)singleTap:(UITapGestureRecognizer *)sender {
            lastTouchPoint = [sender locationInView:self.webView];
            [self becomeFirstResponder]; //added this line to fix the issue//
            }





            share|improve this answer




























              1












              1








              1







              I Fixed it after some observation.



              In -canPerformAction:withSender: I am returning NO for _share and _define options as I don't need them in my project. It works as expected on selection of word for first time, but shows up the options from second time.



              Simple fix: Add [self becomeFirstResponder]; in tapGuesture or Touch delegate methods



              -(BOOL)canPerformAction:(SEL)action withSender:(id)sender {
              SEL defineSEL = NSSelectorFromString(@"_define:");
              if(action == defineSEL){
              return NO;
              }

              SEL shareSEL = NSSelectorFromString(@"_share:");
              if(action == shareSEL){
              return NO;
              }
              return YES;
              }

              // Tap gesture delegate method
              - (void)singleTap:(UITapGestureRecognizer *)sender {
              lastTouchPoint = [sender locationInView:self.webView];
              [self becomeFirstResponder]; //added this line to fix the issue//
              }





              share|improve this answer















              I Fixed it after some observation.



              In -canPerformAction:withSender: I am returning NO for _share and _define options as I don't need them in my project. It works as expected on selection of word for first time, but shows up the options from second time.



              Simple fix: Add [self becomeFirstResponder]; in tapGuesture or Touch delegate methods



              -(BOOL)canPerformAction:(SEL)action withSender:(id)sender {
              SEL defineSEL = NSSelectorFromString(@"_define:");
              if(action == defineSEL){
              return NO;
              }

              SEL shareSEL = NSSelectorFromString(@"_share:");
              if(action == shareSEL){
              return NO;
              }
              return YES;
              }

              // Tap gesture delegate method
              - (void)singleTap:(UITapGestureRecognizer *)sender {
              lastTouchPoint = [sender locationInView:self.webView];
              [self becomeFirstResponder]; //added this line to fix the issue//
              }






              share|improve this answer














              share|improve this answer



              share|improve this answer








              edited Mar 8 '16 at 23:54









              Borys Verebskyi

              3,31362234




              3,31362234










              answered Jan 14 '16 at 21:01









              LaxLax

              528




              528























                  1














                  Here's my final solution, adapted from the solutions posted here. The key is to listen for the UIMenuControllerWillShowMenu notification and then Dispatch.main.async to hide the menu. This seems to do the trick to avoid the flashing menu.



                  My example uses a UITextField, but it should be easily adapted to a WKWebView.



                  class NoMenuTextField: UITextField {

                  override func didMoveToSuperview() {
                  super.didMoveToSuperview()
                  if superview == nil {
                  deregisterForMenuNotifications()
                  } else {
                  registerForMenuNotifications()
                  }
                  }

                  func registerForMenuNotifications() {
                  NotificationCenter.default.addObserver(forName: Notification.Name.UIMenuControllerWillShowMenu,
                  object: nil,
                  queue: OperationQueue.main)
                  { _ in
                  DispatchQueue.main.async {
                  UIMenuController.shared.setMenuVisible(false, animated: false)
                  UIMenuController.shared.update()
                  }
                  }
                  }

                  func deregisterForMenuNotifications() {
                  NotificationCenter.default.removeObserver(self,
                  name: Notification.Name.UIMenuControllerWillShowMenu,
                  object: nil)
                  }
                  }





                  share|improve this answer




























                    1














                    Here's my final solution, adapted from the solutions posted here. The key is to listen for the UIMenuControllerWillShowMenu notification and then Dispatch.main.async to hide the menu. This seems to do the trick to avoid the flashing menu.



                    My example uses a UITextField, but it should be easily adapted to a WKWebView.



                    class NoMenuTextField: UITextField {

                    override func didMoveToSuperview() {
                    super.didMoveToSuperview()
                    if superview == nil {
                    deregisterForMenuNotifications()
                    } else {
                    registerForMenuNotifications()
                    }
                    }

                    func registerForMenuNotifications() {
                    NotificationCenter.default.addObserver(forName: Notification.Name.UIMenuControllerWillShowMenu,
                    object: nil,
                    queue: OperationQueue.main)
                    { _ in
                    DispatchQueue.main.async {
                    UIMenuController.shared.setMenuVisible(false, animated: false)
                    UIMenuController.shared.update()
                    }
                    }
                    }

                    func deregisterForMenuNotifications() {
                    NotificationCenter.default.removeObserver(self,
                    name: Notification.Name.UIMenuControllerWillShowMenu,
                    object: nil)
                    }
                    }





                    share|improve this answer


























                      1












                      1








                      1







                      Here's my final solution, adapted from the solutions posted here. The key is to listen for the UIMenuControllerWillShowMenu notification and then Dispatch.main.async to hide the menu. This seems to do the trick to avoid the flashing menu.



                      My example uses a UITextField, but it should be easily adapted to a WKWebView.



                      class NoMenuTextField: UITextField {

                      override func didMoveToSuperview() {
                      super.didMoveToSuperview()
                      if superview == nil {
                      deregisterForMenuNotifications()
                      } else {
                      registerForMenuNotifications()
                      }
                      }

                      func registerForMenuNotifications() {
                      NotificationCenter.default.addObserver(forName: Notification.Name.UIMenuControllerWillShowMenu,
                      object: nil,
                      queue: OperationQueue.main)
                      { _ in
                      DispatchQueue.main.async {
                      UIMenuController.shared.setMenuVisible(false, animated: false)
                      UIMenuController.shared.update()
                      }
                      }
                      }

                      func deregisterForMenuNotifications() {
                      NotificationCenter.default.removeObserver(self,
                      name: Notification.Name.UIMenuControllerWillShowMenu,
                      object: nil)
                      }
                      }





                      share|improve this answer













                      Here's my final solution, adapted from the solutions posted here. The key is to listen for the UIMenuControllerWillShowMenu notification and then Dispatch.main.async to hide the menu. This seems to do the trick to avoid the flashing menu.



                      My example uses a UITextField, but it should be easily adapted to a WKWebView.



                      class NoMenuTextField: UITextField {

                      override func didMoveToSuperview() {
                      super.didMoveToSuperview()
                      if superview == nil {
                      deregisterForMenuNotifications()
                      } else {
                      registerForMenuNotifications()
                      }
                      }

                      func registerForMenuNotifications() {
                      NotificationCenter.default.addObserver(forName: Notification.Name.UIMenuControllerWillShowMenu,
                      object: nil,
                      queue: OperationQueue.main)
                      { _ in
                      DispatchQueue.main.async {
                      UIMenuController.shared.setMenuVisible(false, animated: false)
                      UIMenuController.shared.update()
                      }
                      }
                      }

                      func deregisterForMenuNotifications() {
                      NotificationCenter.default.removeObserver(self,
                      name: Notification.Name.UIMenuControllerWillShowMenu,
                      object: nil)
                      }
                      }






                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Apr 22 '18 at 22:35









                      LewisJiLewisJi

                      111




                      111























                          1














                          I tried the solution from Stephan Heilner but it didn't compile in Swift 4.



                          This is my implementation to disable the menuController in a WKWebView that works with Swift 4.



                          In my WKWebView subclass, I added these property and function :



                          var wkContentView: UIView? {
                          return self.subviewWithClassName("WKContentView")
                          }


                          private func swizzleResponderChainAction() {
                          wkContentView?.swizzlePerformAction()
                          }


                          Then, I added an extension in the same file, but out of the WKWebView subclass :



                          // MARK: - Extension used for the swizzling part linked to wkContentView (see above)
                          extension UIView {

                          /// Find a subview corresponding to the className parameter, recursively.
                          func subviewWithClassName(_ className: String) -> UIView? {

                          if NSStringFromClass(type(of: self)) == className {
                          return self
                          } else {
                          for subview in subviews {
                          return subview.subviewWithClassName(className)
                          }
                          }
                          return nil
                          }

                          func swizzlePerformAction() {
                          swizzleMethod(#selector(canPerformAction), withSelector: #selector(swizzledCanPerformAction))
                          }

                          private func swizzleMethod(_ currentSelector: Selector, withSelector newSelector: Selector) {
                          if let currentMethod = self.instanceMethod(for: currentSelector),
                          let newMethod = self.instanceMethod(for:newSelector) {
                          let newImplementation = method_getImplementation(newMethod)
                          method_setImplementation(currentMethod, newImplementation)
                          } else {
                          print("Could not find originalSelector")
                          }
                          }

                          private func instanceMethod(for selector: Selector) -> Method? {
                          let classType = type(of: self)
                          return class_getInstanceMethod(classType, selector)
                          }

                          @objc private func swizzledCanPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
                          return false
                          }
                          }


                          And finally, I called the swizzleResponderChainAction() function from the initializer (you can either override the designated initializer, or create a convenience one):



                          override init(frame: CGRect, configuration: WKWebViewConfiguration) {
                          super.init(frame: frame, configuration: configuration)

                          swizzleResponderChainAction()
                          }


                          Now, the WKWebView does not crash anymore when using a UIMenuController.






                          share|improve this answer


























                          • I tried your solution in my code, but the UIMenuController not disabled.Still it appears on selection. Also the swizzleMethod not called.

                            – Srini
                            Jan 25 at 6:45











                          • Sorry, I forgot to precise that you have to call the new swizzled function from the initializer. That's fixed now. Thanks!

                            – Frédéric Adda
                            Jan 26 at 7:16











                          • Thank you so much. it is working fine now

                            – Srini
                            Jan 29 at 7:15
















                          1














                          I tried the solution from Stephan Heilner but it didn't compile in Swift 4.



                          This is my implementation to disable the menuController in a WKWebView that works with Swift 4.



                          In my WKWebView subclass, I added these property and function :



                          var wkContentView: UIView? {
                          return self.subviewWithClassName("WKContentView")
                          }


                          private func swizzleResponderChainAction() {
                          wkContentView?.swizzlePerformAction()
                          }


                          Then, I added an extension in the same file, but out of the WKWebView subclass :



                          // MARK: - Extension used for the swizzling part linked to wkContentView (see above)
                          extension UIView {

                          /// Find a subview corresponding to the className parameter, recursively.
                          func subviewWithClassName(_ className: String) -> UIView? {

                          if NSStringFromClass(type(of: self)) == className {
                          return self
                          } else {
                          for subview in subviews {
                          return subview.subviewWithClassName(className)
                          }
                          }
                          return nil
                          }

                          func swizzlePerformAction() {
                          swizzleMethod(#selector(canPerformAction), withSelector: #selector(swizzledCanPerformAction))
                          }

                          private func swizzleMethod(_ currentSelector: Selector, withSelector newSelector: Selector) {
                          if let currentMethod = self.instanceMethod(for: currentSelector),
                          let newMethod = self.instanceMethod(for:newSelector) {
                          let newImplementation = method_getImplementation(newMethod)
                          method_setImplementation(currentMethod, newImplementation)
                          } else {
                          print("Could not find originalSelector")
                          }
                          }

                          private func instanceMethod(for selector: Selector) -> Method? {
                          let classType = type(of: self)
                          return class_getInstanceMethod(classType, selector)
                          }

                          @objc private func swizzledCanPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
                          return false
                          }
                          }


                          And finally, I called the swizzleResponderChainAction() function from the initializer (you can either override the designated initializer, or create a convenience one):



                          override init(frame: CGRect, configuration: WKWebViewConfiguration) {
                          super.init(frame: frame, configuration: configuration)

                          swizzleResponderChainAction()
                          }


                          Now, the WKWebView does not crash anymore when using a UIMenuController.






                          share|improve this answer


























                          • I tried your solution in my code, but the UIMenuController not disabled.Still it appears on selection. Also the swizzleMethod not called.

                            – Srini
                            Jan 25 at 6:45











                          • Sorry, I forgot to precise that you have to call the new swizzled function from the initializer. That's fixed now. Thanks!

                            – Frédéric Adda
                            Jan 26 at 7:16











                          • Thank you so much. it is working fine now

                            – Srini
                            Jan 29 at 7:15














                          1












                          1








                          1







                          I tried the solution from Stephan Heilner but it didn't compile in Swift 4.



                          This is my implementation to disable the menuController in a WKWebView that works with Swift 4.



                          In my WKWebView subclass, I added these property and function :



                          var wkContentView: UIView? {
                          return self.subviewWithClassName("WKContentView")
                          }


                          private func swizzleResponderChainAction() {
                          wkContentView?.swizzlePerformAction()
                          }


                          Then, I added an extension in the same file, but out of the WKWebView subclass :



                          // MARK: - Extension used for the swizzling part linked to wkContentView (see above)
                          extension UIView {

                          /// Find a subview corresponding to the className parameter, recursively.
                          func subviewWithClassName(_ className: String) -> UIView? {

                          if NSStringFromClass(type(of: self)) == className {
                          return self
                          } else {
                          for subview in subviews {
                          return subview.subviewWithClassName(className)
                          }
                          }
                          return nil
                          }

                          func swizzlePerformAction() {
                          swizzleMethod(#selector(canPerformAction), withSelector: #selector(swizzledCanPerformAction))
                          }

                          private func swizzleMethod(_ currentSelector: Selector, withSelector newSelector: Selector) {
                          if let currentMethod = self.instanceMethod(for: currentSelector),
                          let newMethod = self.instanceMethod(for:newSelector) {
                          let newImplementation = method_getImplementation(newMethod)
                          method_setImplementation(currentMethod, newImplementation)
                          } else {
                          print("Could not find originalSelector")
                          }
                          }

                          private func instanceMethod(for selector: Selector) -> Method? {
                          let classType = type(of: self)
                          return class_getInstanceMethod(classType, selector)
                          }

                          @objc private func swizzledCanPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
                          return false
                          }
                          }


                          And finally, I called the swizzleResponderChainAction() function from the initializer (you can either override the designated initializer, or create a convenience one):



                          override init(frame: CGRect, configuration: WKWebViewConfiguration) {
                          super.init(frame: frame, configuration: configuration)

                          swizzleResponderChainAction()
                          }


                          Now, the WKWebView does not crash anymore when using a UIMenuController.






                          share|improve this answer















                          I tried the solution from Stephan Heilner but it didn't compile in Swift 4.



                          This is my implementation to disable the menuController in a WKWebView that works with Swift 4.



                          In my WKWebView subclass, I added these property and function :



                          var wkContentView: UIView? {
                          return self.subviewWithClassName("WKContentView")
                          }


                          private func swizzleResponderChainAction() {
                          wkContentView?.swizzlePerformAction()
                          }


                          Then, I added an extension in the same file, but out of the WKWebView subclass :



                          // MARK: - Extension used for the swizzling part linked to wkContentView (see above)
                          extension UIView {

                          /// Find a subview corresponding to the className parameter, recursively.
                          func subviewWithClassName(_ className: String) -> UIView? {

                          if NSStringFromClass(type(of: self)) == className {
                          return self
                          } else {
                          for subview in subviews {
                          return subview.subviewWithClassName(className)
                          }
                          }
                          return nil
                          }

                          func swizzlePerformAction() {
                          swizzleMethod(#selector(canPerformAction), withSelector: #selector(swizzledCanPerformAction))
                          }

                          private func swizzleMethod(_ currentSelector: Selector, withSelector newSelector: Selector) {
                          if let currentMethod = self.instanceMethod(for: currentSelector),
                          let newMethod = self.instanceMethod(for:newSelector) {
                          let newImplementation = method_getImplementation(newMethod)
                          method_setImplementation(currentMethod, newImplementation)
                          } else {
                          print("Could not find originalSelector")
                          }
                          }

                          private func instanceMethod(for selector: Selector) -> Method? {
                          let classType = type(of: self)
                          return class_getInstanceMethod(classType, selector)
                          }

                          @objc private func swizzledCanPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
                          return false
                          }
                          }


                          And finally, I called the swizzleResponderChainAction() function from the initializer (you can either override the designated initializer, or create a convenience one):



                          override init(frame: CGRect, configuration: WKWebViewConfiguration) {
                          super.init(frame: frame, configuration: configuration)

                          swizzleResponderChainAction()
                          }


                          Now, the WKWebView does not crash anymore when using a UIMenuController.







                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Jan 26 at 7:15

























                          answered Jan 8 at 16:03









                          Frédéric AddaFrédéric Adda

                          3,81813857




                          3,81813857













                          • I tried your solution in my code, but the UIMenuController not disabled.Still it appears on selection. Also the swizzleMethod not called.

                            – Srini
                            Jan 25 at 6:45











                          • Sorry, I forgot to precise that you have to call the new swizzled function from the initializer. That's fixed now. Thanks!

                            – Frédéric Adda
                            Jan 26 at 7:16











                          • Thank you so much. it is working fine now

                            – Srini
                            Jan 29 at 7:15



















                          • I tried your solution in my code, but the UIMenuController not disabled.Still it appears on selection. Also the swizzleMethod not called.

                            – Srini
                            Jan 25 at 6:45











                          • Sorry, I forgot to precise that you have to call the new swizzled function from the initializer. That's fixed now. Thanks!

                            – Frédéric Adda
                            Jan 26 at 7:16











                          • Thank you so much. it is working fine now

                            – Srini
                            Jan 29 at 7:15

















                          I tried your solution in my code, but the UIMenuController not disabled.Still it appears on selection. Also the swizzleMethod not called.

                          – Srini
                          Jan 25 at 6:45





                          I tried your solution in my code, but the UIMenuController not disabled.Still it appears on selection. Also the swizzleMethod not called.

                          – Srini
                          Jan 25 at 6:45













                          Sorry, I forgot to precise that you have to call the new swizzled function from the initializer. That's fixed now. Thanks!

                          – Frédéric Adda
                          Jan 26 at 7:16





                          Sorry, I forgot to precise that you have to call the new swizzled function from the initializer. That's fixed now. Thanks!

                          – Frédéric Adda
                          Jan 26 at 7:16













                          Thank you so much. it is working fine now

                          – Srini
                          Jan 29 at 7:15





                          Thank you so much. it is working fine now

                          – Srini
                          Jan 29 at 7:15











                          0














                          One way that I've used is to simply disable the menu using CSS. The CSS property is called -webkit-touch-callout: none;. You can apply it to the top level element and disable it for the whole page or any child element and disable it with more precision. Hope that helps.






                          share|improve this answer




























                            0














                            One way that I've used is to simply disable the menu using CSS. The CSS property is called -webkit-touch-callout: none;. You can apply it to the top level element and disable it for the whole page or any child element and disable it with more precision. Hope that helps.






                            share|improve this answer


























                              0












                              0








                              0







                              One way that I've used is to simply disable the menu using CSS. The CSS property is called -webkit-touch-callout: none;. You can apply it to the top level element and disable it for the whole page or any child element and disable it with more precision. Hope that helps.






                              share|improve this answer













                              One way that I've used is to simply disable the menu using CSS. The CSS property is called -webkit-touch-callout: none;. You can apply it to the top level element and disable it for the whole page or any child element and disable it with more precision. Hope that helps.







                              share|improve this answer












                              share|improve this answer



                              share|improve this answer










                              answered Nov 19 '15 at 0:47









                              RyanRyan

                              3,71852943




                              3,71852943























                                  0














                                  pragma mark - WKNavigationDelegate



                                  - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
                                  // Add:
                                  // Disable LongPress and Selection, no more UIMenucontroller
                                  [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none'" completionHandler:nil];
                                  [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none'" completionHandler:nil]; }





                                  share|improve this answer
























                                  • always show after doing this

                                    – Shauket Sheikh
                                    Oct 31 '18 at 3:18
















                                  0














                                  pragma mark - WKNavigationDelegate



                                  - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
                                  // Add:
                                  // Disable LongPress and Selection, no more UIMenucontroller
                                  [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none'" completionHandler:nil];
                                  [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none'" completionHandler:nil]; }





                                  share|improve this answer
























                                  • always show after doing this

                                    – Shauket Sheikh
                                    Oct 31 '18 at 3:18














                                  0












                                  0








                                  0







                                  pragma mark - WKNavigationDelegate



                                  - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
                                  // Add:
                                  // Disable LongPress and Selection, no more UIMenucontroller
                                  [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none'" completionHandler:nil];
                                  [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none'" completionHandler:nil]; }





                                  share|improve this answer













                                  pragma mark - WKNavigationDelegate



                                  - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
                                  // Add:
                                  // Disable LongPress and Selection, no more UIMenucontroller
                                  [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitUserSelect='none'" completionHandler:nil];
                                  [self.wkWebView evaluateJavaScript:@"document.documentElement.style.webkitTouchCallout='none'" completionHandler:nil]; }






                                  share|improve this answer












                                  share|improve this answer



                                  share|improve this answer










                                  answered Nov 29 '17 at 3:12









                                  RomeRome

                                  11




                                  11













                                  • always show after doing this

                                    – Shauket Sheikh
                                    Oct 31 '18 at 3:18



















                                  • always show after doing this

                                    – Shauket Sheikh
                                    Oct 31 '18 at 3:18

















                                  always show after doing this

                                  – Shauket Sheikh
                                  Oct 31 '18 at 3:18





                                  always show after doing this

                                  – Shauket Sheikh
                                  Oct 31 '18 at 3:18











                                  0














                                  In iOS 11, I have found a simple solution by an extension of WKWebView. I have not checked to see if this will work in earlier versions of iOS. The following is a simple example with one menu item.



                                  import UIKit
                                  import WebKit

                                  extension WKWebView {

                                  override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
                                  switch action {
                                  case #selector(highlightHandler):
                                  return true
                                  default:
                                  return false
                                  }
                                  }

                                  func createEditMenu() { // Should be called once
                                  let highlight = UIMenuItem(title: "Highlight", action: #selector(highlightHandler))
                                  menuItems.append(highlight)
                                  UIMenuController.shared.menuItems = [highlight]
                                  }

                                  @objc func highlightHandler(sender: UIMenuItem) {
                                  print("highlight clicked")
                                  }
                                  }





                                  share|improve this answer




























                                    0














                                    In iOS 11, I have found a simple solution by an extension of WKWebView. I have not checked to see if this will work in earlier versions of iOS. The following is a simple example with one menu item.



                                    import UIKit
                                    import WebKit

                                    extension WKWebView {

                                    override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
                                    switch action {
                                    case #selector(highlightHandler):
                                    return true
                                    default:
                                    return false
                                    }
                                    }

                                    func createEditMenu() { // Should be called once
                                    let highlight = UIMenuItem(title: "Highlight", action: #selector(highlightHandler))
                                    menuItems.append(highlight)
                                    UIMenuController.shared.menuItems = [highlight]
                                    }

                                    @objc func highlightHandler(sender: UIMenuItem) {
                                    print("highlight clicked")
                                    }
                                    }





                                    share|improve this answer


























                                      0












                                      0








                                      0







                                      In iOS 11, I have found a simple solution by an extension of WKWebView. I have not checked to see if this will work in earlier versions of iOS. The following is a simple example with one menu item.



                                      import UIKit
                                      import WebKit

                                      extension WKWebView {

                                      override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
                                      switch action {
                                      case #selector(highlightHandler):
                                      return true
                                      default:
                                      return false
                                      }
                                      }

                                      func createEditMenu() { // Should be called once
                                      let highlight = UIMenuItem(title: "Highlight", action: #selector(highlightHandler))
                                      menuItems.append(highlight)
                                      UIMenuController.shared.menuItems = [highlight]
                                      }

                                      @objc func highlightHandler(sender: UIMenuItem) {
                                      print("highlight clicked")
                                      }
                                      }





                                      share|improve this answer













                                      In iOS 11, I have found a simple solution by an extension of WKWebView. I have not checked to see if this will work in earlier versions of iOS. The following is a simple example with one menu item.



                                      import UIKit
                                      import WebKit

                                      extension WKWebView {

                                      override open func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
                                      switch action {
                                      case #selector(highlightHandler):
                                      return true
                                      default:
                                      return false
                                      }
                                      }

                                      func createEditMenu() { // Should be called once
                                      let highlight = UIMenuItem(title: "Highlight", action: #selector(highlightHandler))
                                      menuItems.append(highlight)
                                      UIMenuController.shared.menuItems = [highlight]
                                      }

                                      @objc func highlightHandler(sender: UIMenuItem) {
                                      print("highlight clicked")
                                      }
                                      }






                                      share|improve this answer












                                      share|improve this answer



                                      share|improve this answer










                                      answered Nov 16 '18 at 7:49









                                      Gary NorrisGary Norris

                                      112




                                      112






























                                          draft saved

                                          draft discarded




















































                                          Thanks for contributing an answer to Stack Overflow!


                                          • Please be sure to answer the question. Provide details and share your research!

                                          But avoid



                                          • Asking for help, clarification, or responding to other answers.

                                          • Making statements based on opinion; back them up with references or personal experience.


                                          To learn more, see our tips on writing great answers.




                                          draft saved


                                          draft discarded














                                          StackExchange.ready(
                                          function () {
                                          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f33243230%2fdisable-entire-uimenucontroller-edit-menu-in-wkwebview%23new-answer', 'question_page');
                                          }
                                          );

                                          Post as a guest















                                          Required, but never shown





















































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown

































                                          Required, but never shown














                                          Required, but never shown












                                          Required, but never shown







                                          Required, but never shown







                                          Popular posts from this blog

                                          Xamarin.iOS Cant Deploy on Iphone

                                          Glorious Revolution

                                          Dulmage-Mendelsohn matrix decomposition in Python