Deshabilitar la selección de usuario en UIWebView

121

Tengo una aplicación donde cargo contenido a ay UIWebViewpresento esto. No puedo deshabilitar la interacción del usuario por completo porque quiero que el usuario pueda hacer clic en los enlaces. Solo necesito deshabilitar la selección de usuario. Encontré en algún lugar de Internet que puedes usar:

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

Traté de insertar esto como

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

en webViewDidFinishLoad:

Sin embargo, no funciona. Todavía puedo seleccionar y copiar texto dentro de WebView.

¿Alguna idea de lo que podría estar yendo mal?

Actualización: esto solo parece suceder a partir de iOS 4.3

Engin Kurutepe
fuente

Respuestas:

280

Aquí hay algunas formas de deshabilitar la selección:

Agregue lo siguiente a sus documentos web móviles

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

Cargue mediante programación el siguiente código Javascript:

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

Deshabilite el menú de usuario Copiar / Pegar:

- (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];
}
WrightsCS
fuente
1
Extender UIWebViewusando una categoría.
Deepak Danduprolu
44
Engin, el primero funciona en Mobile Safari, iOS 4.3.1. Pero WrightCS olvidó agregar el selector. Para aplicarlo a todos los elementos, use el asterisco, como: * {/ * css va aquí * /}
fisherwebdev
1
Agregar el estilo funcionó perfectamente al eliminar el menú que apareció al tapholding en un enlace dentro de mi aplicación PhoneGap.
espático
77
canPerformActionno deshabilita el menú Cortar, Copiar, Pegar. Y Seleccionar, Seleccionar todo el menú. ¿Cómo arreglar esto? -webkit-touch-callouty removeAllRangesromper la entrada del usuario. No se pueden usar todos los métodos proporcionados :(
Dmitry
44
El problema con poner estos estilos sin selección en *el ámbito global es que detiene la entrada del usuario en formularios web. Descubrí que obtuve mejores resultados al colocarlos dentro de la bodyetiqueta.
David Douglas
104

Puedo confirmar que el siguiente código funciona en 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';"];
}

También funciona para iOS 9 y versiones posteriores. Aquí está el código rápido:

func webViewDidFinishLoad(webView: UIWebView) {
    // Disable user selection
    webView.stringByEvaluatingJavaScriptFromString("document.documentElement.style.webkitUserSelect='none'")!
    // Disable callout
    webView.stringByEvaluatingJavaScriptFromString("document.documentElement.style.webkitTouchCallout='none'")!
}
TPoschel
fuente
2
¡Confirmado en iOS 7! Nota: es posible agrupar las dos llamadas en una concatenando las dos cadenas.
Bigood
En iOS 9.x aparece una llamada vacía en la parte superior de la pantalla después de presionar prolongadamente, incluso cuando se usa arriba.
DwarDoh
¿Cómo puedo usar el código anterior? Solo sé JS; no tienen ninguna idea de cómo puedo editar el código Objective C o el cambio PhoneGap plugin..if la ayuda de nadie lata
Lakshay
Trabaja con iOS 9 y 10 chico perfecto!
ΩlostA
25

Estoy usando esta técnica en una aplicación web para Android / iPhone (empaquetada con Trigger.IO) y descubrí que solo funcionaría con la sintaxis de encadenamiento para la pseudo-clase: 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 */

}
Johno Scott
fuente
Estoy usando jQuery Mobile y Phonegap Build y esto funcionó para mí. Lo intenté por primera vez *:not(input,textarea) {-webkit-touch-callout: none; -webkit-user-select: none;}, pero eso no me sirvió. ¡Gracias!
Mark Rummel
18

Me gusta la solución WrightsCS, pero la usaré para que los usuarios puedan seguir copiando, pegando y seleccionando acciones en las entradas.

<style type="text/css">
*:not(input,textarea) {
    -webkit-touch-callout: none;
    -webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
pablobart
fuente
2
Si vas a hacer esto, ¡no olvides textarea!
Ryan
9

No estoy seguro de cómo se realiza la configuración, pero ¿por qué no borra el PasteBoard cuando se llama a viewWillDisappear? Tal vez algo así como en su aplicaciónDelegate.m:

[UIPasteboard generalPasteboard].string = nil;

esto asegurará que cualquier información que el usuario haya copiado, no podrá pegarla fuera de la aplicación.

Además, como dijo Engin, puede anular el método canPerformSelector en la clase de controlador que contiene uiwebview.

Bittu
fuente
1
Esta es una de las mejores soluciones. Esto se puede establecer en - (vacío) applicationDidEnterBackground: (UIApplication *) controlador de eventos de la aplicación. Y esto asegura que no salgan datos de la aplicación.
Krishnan
@Krishan, ¿estás 100% seguro de que también se detendrán las capturas de pantalla?
Norman H
Me gusta esta solución, pero dado que permanece en el tablero mientras la aplicación está activa, otra aplicación (maliciosa) que se ejecuta en el subproceso en segundo plano puede acceder al tablero general mientras tiene datos.
binary_falcon
¿Esto también eliminaría datos que no sean de la aplicación? Quizás obtener los datos al aparecer y volver a configurarlos para que desaparezca funcionaría mejor
Hamzah Malik
7

La respuesta de TPoschel es actual pero en mi caso el orden fue importante.

// 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';"];
}
pawelini1
fuente
7

Puedo confirmar que esto definitivamente funcionará para ti.

<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 desea deshabilitar solo la etiqueta del botón de anclaje, use esto.

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

¡Resultado del gran trabajo de una semana! Todas las demás respuestas son incorrectas si desea guardar eventos del mouse y la entrada del usuario en muchas páginas.

1) Método Swizzle (por la biblioteca rentzsch / jrswizzle ):

[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) Coloque UIWebView en UIView y agregue un código:

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

Y éste:

- (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;
}
Dmitry
fuente
2
Alguna explicación de lo que se supone que debe hacer sería bueno. En particular, estoy confundido acerca de por qué su gesto se llama singleTap pero requiere dos toques.
arlomedia
5
    let longPress:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: nil, action: nil)
    longPress.minimumPressDuration = 0.2
    webView.addGestureRecognizer(longPress)

Simplemente agregue este código a su viewDidLoad (). El usuario puede hacer clic en el enlace pero no puede copiar el contenido.

Samrat Pramanik
fuente
4

La primera solución dada funcionó perfectamente para mí ... hasta que cargué un .pdf en mi UIWebView.

Cargar un archivo .doc funcionó perfectamente, pero cargar un .pdf resultó en que la siguiente línea de código ya no tenía el efecto deseado y el menú copiar / definir apareció nuevamente con un toque prolongado por parte del usuario.

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

Después de otro tirón de cabello, encontré esta respuesta aquí de Johnny Rockex y funcionó como un campeón. UIWebView sin copiar / pegar cuando se muestran archivos PDF

¡Muchas gracias a él por esta solución fácil de implementar y genial!

Scooter
fuente
2

Para mí, lo había pensado, en busca de las imágenes NSDatade UIWebViewporLongPressGesture .

Pero la Lupa y Copiar / Pegar / Cortar siempre ocurren antes de que se ejecute mi función.

Y encontré esto: ingrese la descripción de la imagen aquí

Significa que la Lupa y Copiar / Pegar / Cortar necesitan 0,5 segundos para ejecutarse, por lo que si su función se puede ejecutar en 0,49 segundos, ¡HECHO!

self.longPressPan.minimumPressDuration = 0.3
Kaiyuan Xu
fuente
esto funciona para mí en iOS 9 + Xcode 7 GM, otros métodos que probé son útiles en iOS 7 y 8
Kaiyuan Xu
-4

Utilice la función de interacción de vista web

   webView.userInteractionEnabled = false

Esto funciona para mi

PD: recuerde habilitar la interacción cuando desee que el usuario pueda interactuar nuevamente con la vista web

Srohr
fuente
1
Bienvenido a stackoverflow. ¿La respuesta realmente agrega valor a esta vieja pregunta? Por favor revise Cómo responder .
dbank
1
Considere expandir su respuesta (proporcionando un pequeño ejemplo de código) para aumentar el valor de su respuesta. Además, las respuestas que contienen 'funciona para mí' en realidad no inspiran confianza; es mejor presentar la respuesta tal como está y luego solucionar el problema si alguien solicita una aclaración sobre su respuesta.
Aaron D