Disabilitazione della selezione dell'utente in UIWebView


121

Ho un'app in cui carico il contenuto su un UIWebViewe lo presento. Non posso disabilitare completamente l'interazione dell'utente perché desidero che l'utente possa fare clic sui collegamenti. Devo solo disabilitare la selezione dell'utente. Ho trovato da qualche parte in Internet che puoi usare:

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

Ho provato a inserirlo come

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

nel webViewDidFinishLoad:

Comunque, non funziona. Sono ancora in grado di selezionare e copiare il testo all'interno del WebView.

Qualche idea su cosa potrebbe andare storto?

Aggiornamento: questo sembra accadere solo a partire da iOS 4.3

Risposte:


280

Ecco alcuni modi per disabilitare la selezione:

Aggiungi quanto segue ai tuoi documenti Web mobile

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

Carica a livello di codice il seguente codice Javascript:

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

Disabilita il menu utente Copia / Incolla:

- (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];
}

1
Estendi UIWebViewutilizzando una categoria.
Deepak Danduprolu

4
Engin, il primo funziona in Mobile Safari, iOS 4.3.1. Ma WrightCS ha dimenticato di aggiungere il selettore. Per applicarlo a tutti gli elementi, usa l'asterisco, come: * {/ * css va qui * /}
fisherwebdev

1
L'aggiunta dello stile ha funzionato perfettamente nella rimozione del menu che appariva quando si teneva premuto su un collegamento all'interno della mia app PhoneGap.
spaziale

7
canPerformActionnon disabilita il menu Taglia, Copia, Incolla. E Seleziona, Seleziona tutto dal menu. Come risolvere questo problema? -webkit-touch-calloute removeAllRangesinterrompere l'input dell'utente. Non è possibile utilizzare tutti i metodi forniti :(
Dmitry

4
Il problema con l'inserimento di questi stili senza selezione nell'ambito *globale è che interrompe l'input dell'utente nei moduli Web. Ho scoperto di ottenere risultati migliori inserendo invece all'interno del bodytag.
David Douglas

104

Posso confermare che il seguente codice funziona in 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';"];
}

Funziona anche per iOS 9 e versioni successive. Ecco il codice swift:

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

2
Confermato su iOS 7! Nota: è possibile raggruppare le due chiamate in una concatenando le due stringhe.
Bigood

Su iOS 9.x una chiamata vuota appare nella parte superiore dello schermo dopo aver premuto a lungo, anche quando si usa sopra.
DwarDoh

come posso usare il codice di cui sopra .. so solo JS; non ho idea di come posso modificare il codice oggettivo c o cambiare il plugin phonegap..se qualcuno può aiutare
Lakshay

Lavora con iOS 9 e 10 ragazzo perfetto!
ΩlostA

25

Sto usando questa tecnica in un'app Web per Android / iPhone (fornita con Trigger.IO) e ho scoperto che funzionerebbe solo con la sintassi concatenata per 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 */

}

Sto usando jQuery Mobile e Phonegap Build e questo ha funzionato per me. Ho provato per la prima volta *:not(input,textarea) {-webkit-touch-callout: none; -webkit-user-select: none;}, ma non ha funzionato per me. Grazie!
Mark Rummel

18

Mi piace la soluzione WrightsCS ma la userò in modo che gli utenti possano ancora utilizzare le azioni di copia, incolla e selezione sugli input

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

2
Se hai intenzione di farlo, non dimenticare textarea!
Ryan

9

Non sono sicuro di come sia eseguita la configurazione, ma perché non si cancella il pasteBoard quando viene chiamato viewWillDisappear. Forse qualcosa come nella tua appDelegate.m:

[UIPasteboard generalPasteboard].string = nil;

questo assicurerà che i dati che l'utente potrebbe aver copiato, non saranno in grado di incollarli fuori dall'app.

Inoltre, come ha detto Engin, puoi sovrascrivere il metodo canPerformSelector nella classe controller che contiene uiwebview.


1
Questa è una delle migliori soluzioni. Questo può essere impostato in - (void) applicationDidEnterBackground: (UIApplication *) gestore di eventi dell'applicazione. E questo garantisce che nessun dato fuoriesca dall'app.
Krishnan

@Krishan, sei sicuro al 100% che interromperà anche gli screenshot?
Norman H

Mi piace questa soluzione, ma poiché rimane sul tavolo di montaggio mentre l'applicazione è attiva, un'altra applicazione (dannosa) in esecuzione nel thread in background può accedere al tavolo di montaggio generale mentre contiene dati.
binary_falcon

questo non rimuoverebbe anche i dati non dall'app? Forse far apparire i dati e reimpostarli su quelli che scompaiono funzionerebbe meglio
Hamzah Malik

7

La risposta di TPoschel è corretta ma nel mio caso l'ordine era 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';"];
}

7

Posso confermare che funzionerà sicuramente per te.

<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>

Se vuoi disabilitare solo il tag del pulsante di ancoraggio, usa questo.

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

5

Risultato del grande lavoro per una settimana! Tutte le altre risposte non sono corrette se si desidera salvare gli eventi del mouse e l'input dell'utente su molte pagine.

1) Metodo Swizzle (dalla libreria 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) Posiziona UIWebView su UIView e aggiungi un codice:

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

E questo:

- (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;
}

2
Qualche spiegazione di ciò che dovrebbe fare sarebbe carino. In particolare, sono confuso sul motivo per cui il tuo gesto si chiama singleTap ma richiede due tocchi.
arlomedia

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

Aggiungi semplicemente questo codice a viewDidLoad (). L'utente può fare clic sul collegamento ma non può copiare il contenuto.


4

La prima soluzione fornita ha funzionato perfettamente per me ... fino a quando non ho caricato un .pdf nella mia UIWebView.

Il caricamento di un file .doc ha funzionato perfettamente, ma il caricamento di un .pdf ha comportato che la seguente riga di codice non avesse più l'effetto desiderato e il menu di copia / definizione appariva di nuovo su un lungo tocco da parte dell'utente.

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

Dopo un altro periodo di tirare i capelli ho trovato questa risposta qui da Johnny Rockex e ha funzionato come un campione. UIWebView senza copia / incolla durante la visualizzazione di file PDF

Molte grazie a lui per questa soluzione geniale e facile da implementare !!


2

Per quanto mi riguarda, ho voluto andare a prendere le immagini NSDatada UIWebViewdaLongPressGesture .

Ma Magnifier e Copy / Paste / Cut si verificano sempre prima dell'esecuzione della mia funzione.

E ho trovato questo: inserisci qui la descrizione dell'immagine

Significa che Magnifier e Copy / Paste / Cut necessitano di 0,5 secondi per essere eseguiti, quindi se la tua funzione può essere eseguita in 0,49, FATTO!

self.longPressPan.minimumPressDuration = 0.3

questo funziona per me in iOS 9 + Xcode 7 GM, altri metodi che ho provato sono utili solo in iOS 7 e 8
Kaiyuan Xu

-4

Usa la funzione di interection della visualizzazione web

   webView.userInteractionEnabled = false

Per me funziona

PS: ricorda di abilitare nuovamente l'interazione quando desideri che l'utente possa interagire nuovamente con la visualizzazione web


1
Benvenuto in stackoverflow. La risposta aggiunge davvero valore a questa vecchia domanda? Si prega di rivedere Come rispondere .
dbank

1
Considera l'idea di espandere la tua risposta (fornendo un piccolo esempio di codice) per aumentare il valore della tua risposta. Inoltre, le risposte contenenti "per me funziona" non ispirano davvero fiducia: meglio presentare la risposta così com'è e quindi risolvere il problema se qualcuno chiede chiarimenti sulla tua risposta.
Aaron D
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.