禁用文本区域/输入UIWebview中的长按菜单

Sha*_* RC 4 contextmenu objective-c uiwebview cordova

这似乎是这里最常讨论的主题之一,但我找不到真正有效的解决方案.我发布这个问题是为了分享我找到的解决方案以及希望找到更好/更清洁的解决方案

情况描述:

  • 我的应用程序中有一个UIWebview

  • webview中有文本输入/区域

  • 长按文本区域/输入会显示上下文菜单,其中包含"剪切","复制","定义"等.

我们需要在不禁用用户输入的情况下禁用此菜单.


到目前为止我尝试过的东西(东西不起作用):

覆盖canPerformAction

此解决方案告诉我们要添加canPerformAction:withSender:到UIWebview的子类或UIWebview的委托中.

- (BOOL) canPerformAction:(SEL)action withSender:(id)sender
{
 if (action == @selector(defineSelection:))
 {
    return NO;
 }
 else if (action == @selector(translateSelection:))
 {
    return NO; 
 }
 else if (action == @selector(copy:))
 {
    return NO;
 }

return [super canPerformAction:action withSender:sender];
}
Run Code Online (Sandbox Code Playgroud)

不起作用,因为canPerformAction:在此类中没有调用显示的菜单项.由于sharedMenuController与Responder链中的第一个响应者进行交互,因此在容器中实现canPerformAction会跳过select和selectAll,因为它们已经由子菜单处理.

操纵CSS

将以下内容添加到CSS:

html {
    -webkit-user-select: none;
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color:rgba(0,0,0,0);
}
Run Code Online (Sandbox Code Playgroud)

这适用于图像和超链接,但不适用于输入.:(

Sha*_* RC 7

第一个解决方案不起作用的根本原因是调用的子视图UIWebBrowserView.这似乎是一个视图,其canPerformAction为action上下文菜单中显示的任何内容返回true .

由于这UIWebBrowserView是一个私有类,我们不应该尝试将其子类化(因为它会让你的应用程序被拒绝).

所以我们做的是我们制作另一种方法mightPerformAction:withSender:,就像这样 -

- (BOOL)mightPerformAction:(SEL)action withSender:(id)sender {


NSLog(@"******Action!! %@******",NSStringFromSelector(action));


  if (action == @selector(copy:))
  {
      NSLog(@"Copy Selector");
      return NO;
  }
  else if (action == @selector(cut:))
  {
      NSLog(@"cut Selector");
      return NO;
  }
  else if (action == NSSelectorFromString(@"_define:"))
  {
      NSLog(@"define Selector");
      return NO;
  }
  else if (action == @selector(paste:))
  {
      NSLog(@"paste Selector");
      return NO;
  }
  else
  {
      return [super canPerformAction:action withSender:sender];
  }


}
Run Code Online (Sandbox Code Playgroud)

并添加另一个方法来替换canPerformAction:withSender:with mightPerformAction:withSender:

- (void) replaceUIWebBrowserView: (UIView *)view
{

//Iterate through subviews recursively looking for UIWebBrowserView
for (UIView *sub in view.subviews) {
    [self replaceUIWebBrowserView:sub];
    if ([NSStringFromClass([sub class]) isEqualToString:@"UIWebBrowserView"]) {

        Class class = sub.class;

        SEL originalSelector = @selector(canPerformAction:withSender:);
        SEL swizzledSelector = @selector(mightPerformAction:withSender:);

        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(self.class, swizzledSelector);

        //add the method mightPerformAction:withSender: to UIWebBrowserView
        BOOL didAddMethod =
        class_addMethod(class,
                        originalSelector,
                        method_getImplementation(swizzledMethod),
                        method_getTypeEncoding(swizzledMethod));
        //replace canPerformAction:withSender: with mightPerformAction:withSender:
        if (didAddMethod) {
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));

        } else {

            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
    }
}
}
Run Code Online (Sandbox Code Playgroud)

最后在ViewController的viewDidLoad中调用它:

[self replaceUIWebBrowserView:self.webView];
Run Code Online (Sandbox Code Playgroud)

注意:添加#import <objc/runtime.h>到viewController然后将不显示错误(方法).

注意:我正在使用NSSelectorFromString方法来避免在审核过程中检测到私有API选择器.

这似乎在iOS7中使用Xcode 5正常工作,如果有人能在此找到任何问题,请告诉我如何改进它..