Desativando a seleção de usuários no UIWebView

121

Eu tenho um aplicativo no qual carrego conteúdo UIWebViewe apresento isso. Não consigo desativar completamente a interação do usuário porque quero que o usuário possa clicar nos links. Eu só preciso desativar a seleção de usuários. Encontrei em algum lugar do Internets que você pode usar:

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

Eu tentei inserir isso como

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

no webViewDidFinishLoad:

No entanto, isso não funciona. Ainda consigo selecionar e copiar texto dentro do WebView.

Alguma idéia do que pode estar errado?

Atualização: isso parece acontecer apenas a partir do iOS 4.3

Engin Kurutepe
fonte

Respostas:

280

Aqui estão algumas maneiras de desativar a seleção:

Adicione o seguinte aos seus documentos da web para celular

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

Carregue programaticamente o seguinte código Javascript:

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

Desative o menu de usuário Copiar / Colar:

- (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
fonte
1
Estenda UIWebViewusando uma categoria.
Deepak Danduprolu 23/05
4
Engin, o primeiro funciona no Mobile Safari, iOS 4.3.1. Mas o WrightCS esqueceu de adicionar o seletor. Para aplicá-lo a todos os elementos, use o asterisco, como: * {/ * css vai aqui * /}
fisherwebdev
1
A adição do estilo funcionou perfeitamente na remoção do menu exibido ao pressionar um link dentro do meu aplicativo PhoneGap.
espacial
7
canPerformActionnão desativa o menu Recortar, Copiar, Colar. E selecione, selecione o menu Todos. Como consertar isto? -webkit-touch-calloute removeAllRangesinterrompa a entrada do usuário. Não é possível usar todos os métodos fornecidos :(
Dmitry
4
O problema de colocar esses estilos não selecionados no *escopo global é que ele interrompe a entrada do usuário em formulários da web. Descobri que obtive melhores resultados colocando dentro da bodytag.
David Douglas
104

Posso confirmar que o código a seguir funciona no 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';"];
}

Também funciona para iOS 9 e posterior. Aqui está o 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
fonte
2
Confirmado no iOS 7! Nota: É possível agrupar as duas chamadas em uma concatenando as duas cadeias.
Big
No iOS 9.x, uma chamada vazia é exibida na parte superior da tela após pressão prolongada, mesmo quando usado acima.
DwarDoh 29/10/2015
como posso usar o código acima .. eu apenas sei JS; não têm qualquer idéia de como posso editar o código Objective C ou mudança phonegap plugin..if alguém pode ajudar
Lakshay
Trabalhar com iOS 9 e 10 cara perfeito!
ΩlostA
25

Estou usando essa técnica em um aplicativo Web para Android / iPhone (fornecido com o Trigger.IO) e achei que funcionaria apenas com a sintaxe de encadeamento da 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 */

}
Johno Scott
fonte
Estou usando o jQuery Mobile e o Phonegap Build e isso funcionou para mim. Eu tentei pela primeira vez, *:not(input,textarea) {-webkit-touch-callout: none; -webkit-user-select: none;}mas isso não funcionou para mim. Obrigado!
Mark Rummel
18

Gosto da solução WrightsCS, mas usarei isso para que os usuários ainda possam usar a copiar, colar e selecionar ações nas entradas

<style type="text/css">
*:not(input,textarea) {
    -webkit-touch-callout: none;
    -webkit-user-select: none; /* Disable selection/Copy of UIWebView */
}
</style>
pablobart
fonte
2
Se você vai fazer isso, não se esqueça da área de texto!
Ryan
9

Não tenho certeza de como a configuração é feita, mas por que você não limpa o pasteBoard quando o viewWillDisappear é chamado. Talvez algo como no seu appDelegate.m:

[UIPasteboard generalPasteboard].string = nil;

isso garantirá que quaisquer dados que o usuário possa ter copiado, não poderão colá-lo fora do aplicativo.

Além disso, como Engin disse, você pode substituir o método canPerformSelector na classe do controlador que contém o uiwebview.

Bittu
fonte
1
Esta é uma das melhores soluções. Isso pode ser definido em - (void) applicationDidEnterBackground: (UIApplication *) manipulador de eventos do aplicativo. E isso garante que nenhum dado saia do aplicativo.
Krishnan
@Krishan, você tem 100% de certeza de que também interromperá as capturas de tela?
Norman H
Eu gosto dessa solução, mas como ela permanece na área de transferência enquanto o aplicativo está ativo, outro aplicativo (malicioso) em execução no thread de segundo plano pode acessar a área de transferência geral enquanto possui dados.
binary_falcon 26/09
isso não removeria também os dados não do aplicativo? Talvez obter os dados em aparecer e configurá-lo de volta para que, em desaparecer funcionaria melhor
Hamzah Malik
7

A resposta TPoschel é correta, mas no meu caso a ordem foi 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
fonte
7

Posso confirmar que isso definitivamente funcionará para você.

<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 você deseja Desativar apenas a tag do botão de ancoragem, use isso.

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

Resultado do excelente trabalho por uma semana! Todas as outras respostas estão incorretas se você deseja salvar eventos do mouse e entrada do usuário em várias páginas.

1) Método Swizzle (pela 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 o UIWebView no UIView e adicione um 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];

E este:

- (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
fonte
2
Alguma explicação sobre o que isso deveria fazer seria bom. Em particular, estou confuso sobre o motivo pelo qual seu gesto é chamado de toque único, mas requer dois toques.
Arlomedia
5
    let longPress:UILongPressGestureRecognizer = UILongPressGestureRecognizer(target: nil, action: nil)
    longPress.minimumPressDuration = 0.2
    webView.addGestureRecognizer(longPress)

Basta adicionar esse código ao seu viewDidLoad (). O usuário pode clicar no link, mas não pode copiar o conteúdo.

Samrat Pramanik
fonte
4

A primeira solução fornecida funcionou perfeitamente para mim ... até eu carregar um .pdf no meu UIWebView.

O carregamento de um arquivo .doc funcionou perfeitamente, mas o carregamento de um .pdf fez com que a seguinte linha de código não tivesse mais o efeito desejado e o menu copiar / definir apareceu novamente com um longo toque do usuário.

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

Depois de mais um puxão de cabelo, encontrei esta resposta aqui por Johnny Rockex e funcionou como um campeão. UIWebView sem copiar / colar ao exibir arquivos PDF

Muito obrigado a ele por esta fácil de implementar, solução genial !!

Lambreta
fonte
2

Para mim, tenho a intenção de buscar as imagens NSDatade UIWebViewpeloLongPressGesture .

Mas a Lupa e Copiar / Colar / Cortar sempre ocorrem antes da execução da minha função.

E eu achei isso: insira a descrição da imagem aqui

Isso significa que a Lupa e Copiar / Colar / Cortar precisam de 0,5s para serem executadas, portanto, se sua função puder ser executada em 0,49s, CONCLUÍDO!

self.longPressPan.minimumPressDuration = 0.3
Kaiyuan Xu
fonte
Isso funciona para mim em iOS 9 + Xcode 7 GM, outros métodos que eu tentei são apenas úteis para iOS 7 e 8
Kaiyuan Xu
-4

Use a função de intereção de exibição na web

   webView.userInteractionEnabled = false

Funciona para mim

PS: lembre-se de ativar a interação quando quiser que o usuário possa interagir com a visualização na web novamente

Srohr
fonte
1
Bem-vindo ao stackoverflow. A resposta realmente agrega valor a essa pergunta antiga? Por favor, revise Como responder .
DBank
1
Considere expandir sua resposta (fornecendo um pequeno exemplo de código) para aumentar o valor da sua resposta. Além disso, respostas contendo 'funciona para mim' realmente não inspiram confiança - é melhor apresentar a resposta como está e depois solucionar problemas se alguém pedir esclarecimentos sobre sua resposta.
Aaron D