UIWebView without Copy/Paste when displaying PDF files
Asked Answered
A

8

4

I have tried to disable Copy/Paste in UIWebView by using a category and overriding canPerformAction and returning NO for copy, cut and paste selectors.

It worked as expected when I loaded a webpage or all other document formats (e.g. docx, pptx, rtf, txt) but not when I loaded a PDF document into the UIWebView.

It seems like there is some different mechanism that handles PDF documents in UIWebView which handles/responds to Copy selector, and therefore I can not block it.

I also tried to disable user interaction for all the subviews of the UIWebView's UIScrollView, which worked fine for other document formats except PDF.

Can anyone help figuring out how to disable Copy in UIWebView for PDF documents as well?

Auxiliary answered 7/10, 2012 at 10:57 Comment(0)
W
17

OK, so I've been experiencing the same problem myself and seem to find a solution, even if it's partial.

What I do is use a UILongPressGestureRecognizer to disable long press gestures that can lead to copy/paste.

The code:

UILongPressGestureRecognizer* longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; // allocating the UILongPressGestureRecognizer

longPress.allowableMovement=100; // Making sure the allowable movement isn't too narrow

longPress.minimumPressDuration=0.3; // This is important - the duration must be long enough to allow taps but not longer than the period in which the scroll view opens the magnifying glass

longPress.delegate=self; // initialization stuff
longPress.delaysTouchesBegan=YES;
longPress.delaysTouchesEnded=YES;

longPress.cancelsTouchesInView=YES; // That's when we tell the gesture recognizer to block the gestures we want 

[webView addGestureRecognizer:longPress]; // Add the gesture recognizer to the view and scroll view then release
[[webView scrollView] addGestureRecognizer:longPress]; 
[longPress release];
Wirer answered 15/10, 2012 at 3:59 Comment(1)
Well, I don't think there is any other way to handle this. So this is a complete answer, not at all partial! +1 for this!Closet
M
5

This solution worked for me:

METHOD 1 - Detect Custom Long Presses

A) Create a subclass of UILongPressGestureRecogniser.

B) Include the canBePreventedByGestureRecognizer: method in your subclass, like this:

Header:

#import <UIKit/UIKit.h> 

@interface CustomLongPress : UILongPressGestureRecognizer

@end    

Implementation:

#import "CustomLongPress.h"

@implementation CustomLongPress

- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer*)preventedGestureRecognizer {
 return NO;
}

@end

That's the only code you need in the subclass.

C) Open up the view containing your uiwebview/pdf reader. Include your subclass: #import "CustomLongPress.h" and then add the custom UILongPressGestureRecogniser to your UIWebView, like this:

- (void)viewDidLoad
{ 
   [super viewDidLoad];

   //Load UIWebView etc

   //Add your custom gesture recogniser
   CustomLongPress * longPress = [[CustomLongPress alloc] initWithTarget:self action:@selector(longPressDetected)];
   [pdfWebView addGestureRecognizer:longPress];

}

D) Detect the long press and switch your UIWebView's userInteraction Off then back On:

-(void)longPressDetected {

NSLog(@"long press detected");
[pdfWebView setUserInteractionEnabled:NO];
[pdfWebView setUserInteractionEnabled:YES];
}

Apparently the reason this works is because the UIWebView captures long presses with its own gesture recognisers, to the exclusion of any additional gesture recongisers you've added. But subclassing your gesture recognisers and preventing their exclusion by returning "NO" to the canBePreventedByGestureRecognizer: method overrides the default behaviour.

Once you can detect the long presses on PDFs, switching the userInteraction Off then On again prevents the UIWebView from actioning its default behaviour, i.e. launching a "Copy/Define" UIMenu or, if long pressing over a link, launching a pop-up actionsheet with "Copy" and "Open" actions.

METHOD 2 - Catch UIMenu NSNotification

Alternatively, if you just want to block the "Copy/Define" UIMenu, (but not affect long presses), you can add this line (listening for UIMenuControllerDidShowMenuNotification) to your ViewDidLoad:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuShown) name:UIMenuControllerDidShowMenuNotification object:nil];

and then add this method, using the same userInteraction Off/On method as above:

-(void)menuShown {
    NSLog(@"menu shown");
    [pdfWebView setUserInteractionEnabled:NO];
    [pdfWebView setUserInteractionEnabled:YES];   
}

First method taken from: https://devforums.apple.com/thread/72521?start=25&tstart=0, and second method from somewhere on Stack, sorry forgotten where. Please include if you know.

Mosher answered 19/12, 2012 at 19:57 Comment(1)
if tried with doubletap and then long press. Some times copy is allowed.Dianetics
M
3

Great answer Zubaba. I’m using a webView to display colored and bolded text and I had the same problem. I put your solution into a method and call it just after I initialize the webView. I don’t seem to need the delegate.

self.textView = [[UIWebView alloc] initWithFrame:textFrame];
[self longPress:self.textView];

- (void)longPress:(UIView *)webView {

UILongPressGestureRecognizer* longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress)]; // allocating the UILongPressGestureRecognizer

longPress.allowableMovement=100; // Making sure the allowable movement isn't too narrow
longPress.minimumPressDuration=0.3; // This is important - the duration must be long enough to allow taps but not longer than the period in which the scroll view opens the magnifying glass

longPress.delaysTouchesBegan=YES;
longPress.delaysTouchesEnded=YES;

longPress.cancelsTouchesInView=YES; // That's when we tell the gesture recognizer to block the gestures we want

[webView addGestureRecognizer:longPress]; // Add the gesture recognizer to the view and scroll view then release
[webView addGestureRecognizer:longPress];

}

- (void)handleLongPress {

}
Maestro answered 12/2, 2013 at 1:54 Comment(1)
used it. but few times allow copy.Dianetics
P
3

In case someone needs Zubaba's answer in Swift 3;

let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
longPress.allowableMovement = 100
longPress.minimumPressDuration = 0.3
longPress.delegate = self
longPress.delaysTouchesBegan = true
longPress.delaysTouchesEnded = true
longPress.cancelsTouchesInView = true
yourWebView.addGestureRecognizer(longPress)
yourWebView.scrollView.addGestureRecognizer(longPress)


func handleLongPress() {
     // Show some alert to inform user or do nothing.
}
Pantie answered 13/1, 2017 at 8:27 Comment(3)
It works for me from SECOND TIME. First time If I do long press it shows Open/Copy action sheet but after that it doesn't. Do you know fix for it?Feck
I just tried the code and it works as expected. Are you sure your file type is pdf? Because for different file types there is different solution. Just check if your file's extension in viewDidLoad() like this if fileExtension == "pdf" { disableUIMenuContOpeningForPDFs() }Pantie
I am doing essentially the same thing with Xamarin and I also get it to work after the first time per PDF page. Has anybody fixed the second time issue?Maestoso
I
1

Here is a modification to Zubaba's answer in Swift 3 that ended up working for me to eliminate warning. I changed assignment longPress.delegate = self to longPress.delegate = self as? UIGestureRecognizerDelegate.

    let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
    longPress.allowableMovement = 100
    longPress.minimumPressDuration = 0.3
    longPress.delegate = self as? UIGestureRecognizerDelegate
    longPress.delaysTouchesBegan = true
    longPress.delaysTouchesEnded = true
    longPress.cancelsTouchesInView = true
    webView.addGestureRecognizer(longPress)
    webView.scrollView.addGestureRecognizer(longPress)

    webView.loadRequest(request)
Itinerancy answered 27/6, 2017 at 16:39 Comment(0)
C
0

The UILongPressGestureRecognizer is located in the UIPDFPageView. To get access to this view look at the view hierarchy in the Debug menu, currently you can access this view like so once you load the pdf to the web view:

let pdfPageView = myWebView.scrollview?.subviews[0]?.subviews[0]

Then to remove the Long Press use this method while passing in the pdfPageView:

func removeLongPressFromView(view: UIView){
  if let gestures = view.gestureRecognizers{
    for gesture in gestures{
      if gesture is UILongPressGestureRecognzier{
        view.removeGestureRecognizer(gesture)
      }
    }
  }
}
Climate answered 15/3, 2016 at 22:8 Comment(0)
M
0

Looking for a Xamarin.iOS solution.

var longPressGestureRecognizer = new CustomLongPressGestureRecognizer ((UILongPressGestureRecognizer obj) => 
{
  Console.WriteLine ("CustomLongPressGestureRecognizer action");
});
webView.AddGestureRecognizer (longPressGestureRecognizer);

The approach given by Zubaba might look like this:

public class ZubabaLongPressGestureRecognizer : UIKit.UILongPressGestureRecognizer
{
    public ZubabaLongPressGestureRecognizer (Action<UILongPressGestureRecognizer> action)
      : base (action)
    {
        AllowableMovement = 100;
        MinimumPressDuration = 0.3;
        DelaysTouchesBegan = true;
        DelaysTouchesEnded = true;
        CancelsTouchesInView = true;
    }
}

The open/copy/cancel menu still shows the first time a link is long held per PDF page. After that first long press, however, it properly does not show up for that page. That this is PDF page dependent does not give me confidence that there is a solution available.

Johnny Rockex's solutions might look like this:

public class RockexLongPressGestureRecognizer : UIKit.UILongPressGestureRecognizer
{
    public RockexLongPressGestureRecognizer(UIKit.UIWebView webView, Action<UILongPressGestureRecognizer> action) :
        base(UserInteractionAction(webView) + action)
    {

    }

    private static Action<UILongPressGestureRecognizer> UserInteractionAction(UIKit.UIWebView webView)
    {
        return (UILongPressGestureRecognizer obj) =>
         {
             webView.UserInteractionEnabled = false;
             webView.UserInteractionEnabled = true;
         };
    }

    public override bool CanPreventGestureRecognizer(UIGestureRecognizer preventedGestureRecognizer)
    {
        return false;
    }
}

and

notificationToken1 = UIMenuController.Notifications.ObserveMenuFrameDidChange (Callback);
notificationToken2 = NSNotificationCenter.DefaultCenter.AddObserver(UIMenuController.DidShowMenuNotification, Callback);

I was not able to get either to do anything. Helpfully someone else has done better with a Xamarin.iOS fix

Maestoso answered 9/5, 2017 at 17:32 Comment(0)
B
0

1.ios11 iphone6 Object-C Without Copy/Paste/lookUp/share

2.

viewDidLoad{
    .......
    [self setupExclude];
}

- (void)setupExclude{
    UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPG)];
    longPress.minimumPressDuration = 0.2;
    [self.webview addGestureRecognizer:longPress];

    UITapGestureRecognizer *singleTapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:nil];
    singleTapGesture.numberOfTapsRequired = 1;
    singleTapGesture.numberOfTouchesRequired  = 1;
    [self.webview addGestureRecognizer:singleTapGesture];

    UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(longPG)];
    doubleTapGesture.numberOfTapsRequired = 2;
    doubleTapGesture.numberOfTouchesRequired = 1;
    [self.webview addGestureRecognizer:doubleTapGesture];
    [singleTapGesture requireGestureRecognizerToFail:doubleTapGesture];
}
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender{
    BOOL res = [super canPerformAction:action withSender:sender];
    UIMenuController.sharedMenuController.menuVisible = NO;
    self.webview.userInteractionEnabled = NO;
    self.webview.userInteractionEnabled = YES;
    return res;
}
- (void)longPG{
    UIMenuController.sharedMenuController.menuVisible = NO;
    self.webview.userInteractionEnabled = NO;
    self.webview.userInteractionEnabled = YES;
}

3. Done!

Biparty answered 31/10, 2017 at 6:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.