web-dev-qa-db-fra.com

Désactivation de la sélection d'utilisateurs dans UIWebView

J'ai une application où je charge du contenu sur un UIWebView et le présente. Je ne peux pas désactiver complètement l'interaction de l'utilisateur, car je souhaite que l'utilisateur puisse cliquer sur les liens. Je dois juste désactiver la sélection de l'utilisateur. J'ai trouvé quelque part dans les internets que vous pouvez utiliser:

document.body.style.webkitUserSelect='none';

J'ai essayé d'insérer ceci comme

[self.contentView stringByEvaluatingJavaScriptFromString:@"document.body.style.webkitUserSelect='none';"]; 

dans webViewDidFinishLoad:

Cependant, ça ne marche pas. Je suis toujours capable de sélectionner et de copier du texte dans WebView.

Des idées sur ce qui pourrait mal tourner?

Mise à jour: Cela ne semble se produire qu'à partir de iOS 4.3

118
Engin Kurutepe

Voici quelques façons de désactiver la sélection:

Ajoutez les éléments suivants à vos documents Web mobiles

<style type="text/css">
* {
    -webkit-touch-callout: none;
    -webkit-user-select: none; /* Disable selection/copy in UIWebView */
}
</style>

Chargez par programme le code Javascript suivant:

NSString * jsCallBack = @"window.getSelection().removeAllRanges();";    
[webView stringByEvaluatingJavaScriptFromString:jsCallBack];

Désactiver le menu utilisateur Copier/Coller:

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender 
{    
    if (action == @selector(copy:) ||
        action == @selector(paste:)||
        action == @selector(cut:)) 
    {
        return _copyCutAndPasteEnabled;
    }
    return [super canPerformAction:action withSender:sender];
}
274
WrightsCS

Je peux confirmer que le code suivant fonctionne dans iOS 5.0 - 8.0.

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    // Disable user selection
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
    // Disable callout
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];
}

Fonctionne également pour iOS 9 et versions ultérieures. Voici le code Swift:

func webViewDidFinishLoad(webView: UIWebView) {
    // Disable user selection
    webView.stringByEvaluatingJavaScriptFromString("document.documentElement.style.webkitUserSelect='none'")!
    // Disable callout
    webView.stringByEvaluatingJavaScriptFromString("document.documentElement.style.webkitTouchCallout='none'")!
}
102
TPoschel

J'utilise cette technique dans une application Web pour Android/iPhone (fourni avec Trigger.IO) et je ne trouve que cela fonctionnerait qu'avec la syntaxe d'enchaînement de la pseudo-classe: not (),:

*:not(input):not(textarea) {
-webkit-user-select: none; /* disable selection/Copy of UIWebView */
    -webkit-touch-callout: none; /* disable the IOS popup when long-press on a link */

}
24
Johno Scott

J'aime la solution WrightsCS mais je vais l'utiliser pour que les utilisateurs puissent toujours utiliser les actions copier, coller et sélectionner les entrées

<style type="text/css">
*:not(input,textarea) {
    -webkit-touch-callout: none;
    -webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
18
pablobart

Je ne suis pas sûr de savoir comment la configuration est faite, mais pourquoi ne pas simplement effacer le pasteBoard lorsque viewWillDisappear est appelé. Peut-être que quelque chose comme dans votre appDelegate.m:

[UIPasteboard generalPasteboard].string = nil;

cela garantira que tout ce que l'utilisateur de données aurait pu copier, il ne pourra pas le coller en dehors de l'application.

En outre, comme Engin l'a dit, vous pouvez remplacer la méthode canPerformSelector dans la classe de contrôleur qui contient uiwebview.

9
Bittu

La réponse de TPoschel est correcte mais dans mon cas, l'ordre était important.

// this works - locks selection and callout
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];
}

// this doesn't work - locks only callout
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitTouchCallout='none';"];
    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];
}
7
pawelini1

Je peux confirmer que cela fonctionnera définitivement pour vous.

<style type="text/css">
  *:not(input):not(textarea) {
   -webkit-user-select: none; /* disable selection/Copy of UIWebView */
   -webkit-touch-callout: none; /* disable the IOS popup when long-press on a link */
   }       
</style>

Si vous voulez désactiver uniquement la balise du bouton d'ancrage, utilisez ceci.

    a {-webkit-user-select: none; /* disable selection/Copy of UIWebView */
   -webkit-touch-callout: none; /* disable the IOS popup when long-press on a link */
     }
7
Narsingh Tomar

Résultat de l'excellent travail pour une semaine! Toutes les autres réponses sont incorrectes si vous souhaitez enregistrer les événements de la souris et les entrées de l'utilisateur sur de nombreuses pages.

1) Méthode Swizzle (par rentzsch/jrswizzle bibliothèque):

[NSClassFromString(@"UIWebDocumentView") jr_swizzleMethod:@selector(canPerformAction:withSender:) withMethod:@selector(myCanPerformAction:withSender:) error:nil];

NSObject + myCanPerformAction.h:

@interface NSObject (myCanPerformAction)

- (BOOL)myCanPerformAction:(SEL)action withSender:(id)sender;

@end

NSObject + myCanPerformAction.m:

#import "NSObject+myCanPerformAction.h"

@implementation NSObject (myCanPerformAction)

- (BOOL)myCanPerformAction:(SEL)action withSender:(id)sender {
    if (action == @selector(copy:)) {
        return [self myCanPerformAction:action withSender:sender];
    }
    if (action == @selector(paste:)) {
        return [self myCanPerformAction:action withSender:sender];
    }
    return NO;
}

@end

2) Placez UIWebView sur UIView et ajoutez un code:

    UITapGestureRecognizer* singleTap = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)] autorelease];
    singleTap.numberOfTapsRequired = 2;
    singleTap.numberOfTouchesRequired = 1;
    singleTap.delegate = self;
    [self.view addGestureRecognizer:singleTap];

Et celui-là:

- (void)handleSingleTap:(UIGestureRecognizer*)gestureRecognizer {
    return;
}

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    if ([otherGestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]) {
        UITapGestureRecognizer *gesture = (UITapGestureRecognizer *)otherGestureRecognizer;
        if (gesture.numberOfTapsRequired == 2) {
            [otherGestureRecognizer.view removeGestureRecognizer:otherGestureRecognizer];
        }
    }
    return YES;
}
5
Dmitry

La première solution proposée a parfaitement fonctionné pour moi ... jusqu'à ce que je charge un fichier .pdf dans mon UIWebView.

Le chargement d'un fichier .doc fonctionnait parfaitement, mais le chargement d'un fichier .pdf avait pour résultat que la ligne de code suivante n'avait plus l'effet souhaité et que le menu de copie/définition réapparaissait de manière prolongée par l'utilisateur.

    [webView stringByEvaluatingJavaScriptFromString:@"document.documentElement.style.webkitUserSelect='none';"];

Après une nouvelle crise de cheveux, j'ai trouvé cette réponse de Johnny Rockex et cela a fonctionné comme un champion. IWebView sans copier/coller lors de l'affichage de PDF

Merci beaucoup à lui pour cette solution facile à mettre en œuvre, géniale !!

4
Scooter
    let longPress:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: nil, action: nil)
    longPress.minimumPressDuration = 0.2
    webView.addGestureRecognizer(longPress)

Ajoutez simplement ce code à votre viewDidLoad (). L'utilisateur peut cliquer sur le lien mais ne peut pas copier le contenu.

3
Samrat Pramanik

Pour moi, j'avais l'intention de récupérer les images 'NSData de UIWebView de LongPressGesture.

Mais la Loupe et Copier/Coller/Couper se produisent toujours avant que ma fonction ne soit exécutée.

Et j'ai trouvé ceci: enter image description here

Cela signifie que la Loupe et Copier/Coller/Couper a besoin de 0.5s pour s'exécuter, donc si votre fonction peut être exécutée en 0.49s, FAIT!

self.longPressPan.minimumPressDuration = 0.3
2
Kaiyuan Xu