Deaktivieren der Benutzerauswahl in UIWebView

121

Ich habe eine App, in die ich Inhalte lade UIWebViewund diese präsentiere. Ich kann die Benutzerinteraktion nicht vollständig deaktivieren, da der Benutzer auf Links klicken kann. Ich muss nur die Benutzerauswahl deaktivieren. Ich habe irgendwo im Internet gefunden, dass Sie verwenden können:

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

Ich habe versucht, dies als einzufügen

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

im webViewDidFinishLoad:

Es funktioniert jedoch nicht. Ich kann weiterhin Text in WebView auswählen und kopieren.

Irgendwelche Ideen, was schief gehen könnte?

Update: Dies scheint nur ab iOS 4.3 zu geschehen

Engin Kurutepe
quelle

Antworten:

280

Hier sind einige Möglichkeiten, um die Auswahl zu deaktivieren:

Fügen Sie Ihren mobilen Webdokumenten Folgendes hinzu

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

Laden Sie programmgesteuert den folgenden Javascript-Code:

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

Deaktivieren Sie das Benutzermenü Kopieren / Einfügen:

- (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
quelle
1
Erweitern Sie UIWebVieweine Kategorie verwenden.
Deepak Danduprolu
4
Engin, der erste funktioniert in Mobile Safari, iOS 4.3.1. WrightCS hat jedoch vergessen, den Selektor hinzuzufügen. Um es auf alle Elemente anzuwenden, verwenden Sie das Sternchen wie: * {/ * css geht hier * /}
Fisherwebdev
1
Das Hinzufügen des Stils funktionierte perfekt beim Entfernen des Menüs, das beim Tippen auf einen Link in meiner PhoneGap-App angezeigt wurde.
räumlich
7
canPerformActiondeaktiviert das Menü Ausschneiden, Kopieren, Einfügen nicht. Und Wählen Sie, Wählen Sie Alle. Wie kann ich das beheben? -webkit-touch-calloutund removeAllRangesBenutzereingaben unterbrechen. Kann nicht alle bereitgestellten Methoden verwenden :(
Dmitry
4
Das Problem beim Einfügen dieser nicht ausgewählten Stile in den *globalen Bereich besteht darin, dass Benutzereingaben in Webformularen gestoppt werden. Ich habe festgestellt, dass ich bessere Ergebnisse erzielt habe, indem ich bodystattdessen das Tag platziert habe.
David Douglas
104

Ich kann bestätigen, dass der folgende Code in iOS 5.0 - 8.0 funktioniert.

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

Funktioniert auch für iOS 9 und höher. Hier ist der schnelle Code:

func webViewDidFinishLoad(webView: UIWebView) {
    // Disable user selection
    webView.stringByEvaluatingJavaScriptFromString("document.documentElement.style.webkitUserSelect='none'")!
    // Disable callout
    webView.stringByEvaluatingJavaScriptFromString("document.documentElement.style.webkitTouchCallout='none'")!
}
TPoschel
quelle
2
Bestätigt unter iOS 7! Hinweis: Durch Verketten der beiden Zeichenfolgen können die beiden Aufrufe zu einem zusammengefasst werden.
Bigood
Unter iOS 9.x wird nach langem Drücken oben auf dem Bildschirm ein leerer Anruf angezeigt, auch wenn Sie ihn oben verwenden.
DwarDoh
Wie kann ich den obigen Code verwenden? Ich kenne nur JS; Ich habe keine Ahnung, wie ich den objektiven C-Code bearbeiten oder das Phonegap-Plugin ändern kann. Wenn jemand helfen kann
Lakshay,
Arbeite mit iOS 9 & 10 Perfect Guy!
ΩlostA
25

Ich verwende diese Technik in einer Web-App für Android / iPhone (im Lieferumfang von Trigger.IO enthalten) und habe festgestellt, dass sie nur mit der Verkettungssyntax für die Pseudoklasse: not () funktioniert:

*: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
quelle
Ich verwende jQuery Mobile und Phonegap Build und das hat bei mir funktioniert. Ich habe es zuerst versucht, *:not(input,textarea) {-webkit-touch-callout: none; -webkit-user-select: none;}aber das hat mir nicht geholfen. Vielen Dank!
Mark Rummel
18

Ich mag die WrightsCS-Lösung, aber ich werde sie verwenden, damit die Benutzer weiterhin die Aktionen zum Kopieren, Einfügen und Auswählen von Eingaben verwenden können

<style type="text/css">
*:not(input,textarea) {
    -webkit-touch-callout: none;
    -webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
Pablobart
quelle
2
Wenn Sie dies tun, vergessen Sie nicht den Textbereich!
Ryan
9

Ich bin nicht sicher, wie das Setup durchgeführt wird, aber warum löschen Sie nicht einfach das pasteBoard, wenn viewWillDisappear aufgerufen wird. Vielleicht so etwas wie in deiner appDelegate.m:

[UIPasteboard generalPasteboard].string = nil;

Dadurch wird sichergestellt, dass Daten, die der Benutzer möglicherweise kopiert hat, nicht außerhalb der App eingefügt werden können.

Wie Engin sagte, können Sie auch die canPerformSelector-Methode in der Controller-Klasse überschreiben, die die uiwebview enthält.

Bittu
quelle
1
Dies ist eine der besten Lösungen. Dies kann in - (void) applicationDidEnterBackground: (UIApplication *) Application Event Handler festgelegt werden. Und das stellt sicher, dass keine Daten aus der App gehen.
Krishnan
@Krishan, bist du 100% sicher, dass auch Screenshots gestoppt werden?
Norman H
Ich mag diese Lösung, aber da sie auf dem Pasteboard bleibt, während die Anwendung aktiv ist, kann eine andere (böswillige) Anwendung, die im Hintergrundthread ausgeführt wird, auf das allgemeine Pasteboard zugreifen, während sie Daten enthält.
binary_falcon
Würde dies nicht auch Daten entfernen, die nicht aus der App stammen? Vielleicht würde es besser funktionieren, wenn die Daten erscheinen und auf das Zurücksetzen zurückgesetzt würden
Hamzah Malik
7

Die Antwort von TPoschel ist korrekt, aber in meinem Fall war die Reihenfolge wichtig.

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

Ich kann bestätigen, dass dies definitiv für Sie funktionieren wird.

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

Wenn Sie nur das Ankertasten-Tag deaktivieren möchten, verwenden Sie dieses.

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

Ergebnis der großartigen Arbeit für eine Woche! Alle anderen Antworten sind falsch, wenn Sie Mausereignisse und Benutzereingaben auf vielen Seiten speichern möchten.

1) Swizzle-Methode (von rentzsch / jrswizzle library):

[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) Platzieren Sie UIWebView in UIView und fügen Sie einen Code hinzu:

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

Und das hier:

- (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
quelle
2
Eine Erklärung, was dies tun soll, wäre schön. Insbesondere bin ich verwirrt darüber, warum Ihre Geste singleTap heißt, aber zwei Taps erfordert.
Arlomedia
5
    let longPress:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: nil, action: nil)
    longPress.minimumPressDuration = 0.2
    webView.addGestureRecognizer(longPress)

Fügen Sie diesen Code einfach zu viewDidLoad () hinzu. Der Benutzer kann auf den Link klicken, den Inhalt jedoch nicht kopieren.

Samrat Pramanik
quelle
4

Die erste Lösung funktionierte perfekt für mich ... bis ich eine PDF-Datei in meine UIWebView geladen habe.

Das Laden einer DOC-Datei funktionierte einwandfrei, aber das Laden einer PDF-Datei führte dazu, dass die folgende Codezeile nicht mehr den gewünschten Effekt hatte und das Menü zum Kopieren / Definieren bei einer langen Berührung durch den Benutzer erneut angezeigt wurde.

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

Nach einer weiteren Haarsträhne fand ich diese Antwort hier von Johnny Rockex und sie funktionierte wie ein Champion. UIWebView ohne Kopieren / Einfügen beim Anzeigen von PDF-Dateien

Vielen Dank an ihn für diese einfach zu implementierende, geniale Lösung !!

Roller
quelle
2

Für mich habe ich vorgehabt, die Bilder NSDatavon UIWebViewby zu holen LongPressGesture.

Aber die Lupe und das Kopieren / Einfügen / Ausschneiden erfolgen immer, bevor meine Funktion ausgeführt wird.

Und ich fand das: Geben Sie hier die Bildbeschreibung ein

Dies bedeutet, dass die Lupe und das Kopieren / Einfügen / Ausschneiden 0,5 Sekunden benötigen, um ausgeführt zu werden. Wenn Ihre Funktion also in 0,49 Sekunden ausgeführt werden kann, FERTIG!

self.longPressPan.minimumPressDuration = 0.3
Kaiyuan Xu
quelle
Dies funktioniert für mich in iOS 9 + Xcode 7 GM, andere Methoden, die ich ausprobiert habe, sind nur in iOS 7 & 8 nützlich
Kaiyuan Xu
-4

Verwenden Sie die Web View Interection-Funktion

   webView.userInteractionEnabled = false

Für mich geht das

PS: Denken Sie daran, die Interaktion wieder zu aktivieren, wenn der Benutzer wieder mit der Webansicht interagieren kann

Srohr
quelle
1
Willkommen bei stackoverflow. Hat die Antwort wirklich einen Mehrwert für diese alte Frage? Bitte überprüfen Sie, wie zu antworten .
Bank
1
Erwägen Sie, Ihre Antwort zu erweitern (mit einem kleinen Codebeispiel), um den Wert Ihrer Antwort zu erhöhen. Antworten, die "es funktioniert für mich" enthalten, schaffen kein wirkliches Vertrauen. Es ist besser, die Antwort so zu präsentieren, wie sie ist, und dann Fehler zu beheben, wenn jemand um Klärung Ihrer Antwort bittet.
Aaron D