Detecção de captura de tela do iOS?

135

O aplicativo Snapchat , na App Store, é um aplicativo que permite compartilhar fotos com uma autodestruição. Você só pode ver as fotos por X segundos. Se você tentar fazer uma captura de tela enquanto a imagem estiver sendo exibida usando a combinação de teclas de energia doméstica, ele informará ao remetente que você tentou fazer uma captura de tela.

Qual parte do SDK permite detectar que o usuário está fazendo uma captura de tela? Eu não sabia que isso era possível.

me2
fonte
1
stackoverflow.com/questions/2121970/… , parece que costumava chamar -applicationDidEnterBackground: antes de tirar a captura de tela anteriormente. Não tenho certeza sobre isso agora.
IDev
Rapazes. O outro encadeamento tem a resposta: stackoverflow.com/questions/2121970/…
me2
1
verifique isso também, stackoverflow.com/a/8711894/1730272 , e diz que não é mais possível. Provavelmente, você pode experimentar e nos informar.
iDev
Ainda não vi isso mencionado em nenhum lugar da Internet, mas eu suporia que, se você usar o Xcode para tirar uma captura de tela (do dispositivo na janela do Organizer), não há absolutamente nenhuma maneira que o aplicativo possa saber. Ele deve monitorar o rolo da câmera em busca de quaisquer fotos adicionadas ao visualizar uma foto do Snapchat recebida, e a captura de tela via Xcode ignora isso completamente (sem a necessidade de jailbreak).
smileyborg
Acompanhamento: testou essa teoria e confirmou que o aplicativo não detecta capturas de tela do Xcode. No entanto, percebi que o interessante é que no iOS 6, os aplicativos precisam ter permissão explícita para acessar fotos ... mas esse aplicativo ainda detecta capturas de tela sem permitir o acesso a fotos! Ele deve estar usando outro método de detecção - notei que, ao usar o método do botão Home + Sleep, a foto ativa também é removida da tela. Portanto, deve haver algum padrão relacionado a esse processo de captura de tela que o aplicativo possa monitorar com segurança, talvez com um GestureRecognizer?
smileyborg

Respostas:

22

Eu encontrei a resposta !! A captura de tela interrompe todos os toques que estão na tela. É por isso que o snapchat exige que você segure para ver a foto. Referência: http://tumblr.jeremyjohnstone.com/post/38503925370/how-to-detect-screenshots-on-ios-like-snapchat

portforwardpodcast
fonte
15
Não é mais verdade com o iOS 7. Veja abaixo uma solução para iOS7 +.
Joe Masilotti
6
O que Joe disse está correto. O solicitante deve desmarcar esta opção como a resposta correta.
Deus dos Biscoitos
O usuário do UIApplication tirou a notificação de captura de tela pode ser usada. IOS 7+
Amit Tandel
353

A partir do iOS 7, as outras respostas não são mais verdadeiras. A Apple fez com que touchesCancelled:withEvent:não seja mais chamada quando o usuário faz uma captura de tela.

Isso efetivamente quebraria completamente o Snapchat, então foram adicionados alguns betas em uma nova solução. Agora, a solução é tão simples quanto usar o NSNotificationCenter para adicionar um observador ao UIApplicationUserDidTakeScreenshotNotification .

Aqui está um exemplo:

Objetivo C

NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationUserDidTakeScreenshotNotification
                                                  object:nil
                                                   queue:mainQueue
                                              usingBlock:^(NSNotification *note) {
                                                 // executes after screenshot
                                              }];

Rápido

NotificationCenter.default.addObserver(
    forName: UIApplication.userDidTakeScreenshotNotification,
    object: nil,
    queue: .main) { notification in
        //executes after screenshot
}
Mick MacCallum
fonte
3
Use isso e touchesCancelled:withEvent:permita detectar uma captura de tela em todas as versões (recentes) do iOS.
27713 Joshua Gross
46
Isso não funciona para impedir que uma captura de tela seja feita. Ele só pode informar ao aplicativo que foi tirada. Na Referência da classe UIApplication: UIApplicationUserDidTakeScreenshotNotification Publicado quando o usuário pressiona os botões Início e Bloquear para tirar uma captura de tela. Esta notificação não contém um dicionário userInfo. Esta notificação é publicada APÓS a captura de tela.
badweasel
6
@badweasel Correto. Considerando que esta notificação segue as convenções convencionais de nomenclatura de cacau, a palavra "Did" implica que ela é publicada após o fato. Não há equivalente "Vontade" neste caso, e o AFAIK não pode impedir o usuário de capturar uma captura de tela usando a API pública.
Mick MacCallum
1
Observe que eu lhe dei um +1. Eu tinha interpretado mal a pergunta do OP originalmente e pensei que a pergunta era como detectá-la para evitar algo - porque era isso que eu estava procurando. Acabei de adicionar o esclarecimento no comentário, porque espero que muitas pessoas que estão chegando a essa pergunta estejam procurando por essa resposta. Eu assumi que também da palavra "fez", mas a documentação torna ainda mais clara. No meu aplicativo, estou permitindo que as pessoas editem fotos, mas algumas das ferramentas exigem IAPs. Mas eu os deixei tentar antes de comprar. Então, eu queria detectar antes de ser capturado para adicionar uma marca d'água. Não pode ser feito.
badweasel
1
@MickMacCallum Algum motivo específico para você fazer isso na fila principal?
precisa
13

Aqui está como fazer em Swift com fechamentos:

func detectScreenShot(action: () -> ()) {
    let mainQueue = NSOperationQueue.mainQueue()
    NSNotificationCenter.defaultCenter().addObserverForName(UIApplicationUserDidTakeScreenshotNotification, object: nil, queue: mainQueue) { notification in
        // executes after screenshot
        action()
    }
}

detectScreenShot { () -> () in
    print("User took a screen shot")
}

Swift 4.2

func detectScreenShot(action: @escaping () -> ()) {
    let mainQueue = OperationQueue.main
    NotificationCenter.default.addObserver(forName: UIApplication.userDidTakeScreenshotNotification, object: nil, queue: mainQueue) { notification in
        // executes after screenshot
        action()
    }
}

Isso está incluído como uma função padrão em:

https://github.com/goktugyil/EZSwiftExtensions

Disclaimer: É o meu repo

Esqarrouth
fonte
Ei, eu tentei isso e funcionou muito bem, mas você pode explicar um pouco o que está acontecendo no código? Eu sou novo no Swift e é um pouco difícil de ler.
aecend
Este é um desses códigos de tipo "se funcionar, não mexa com ele". Você não precisa aprender o que isso faz com que as estruturas usadas aqui sejam muito raras.
Esqarrouth
Mas você deve fazer o checkout como fechamentos funcionar se você não sabe que parte, o seu basicamente quando você chamar detectar func captura de tela, o que sempre você colocar nas parantheses é enviado como uma função de ação
Esqarrouth
@ Esqarrouth Algum motivo específico para você fazer isso na fila principal?
precisa
Causa da pasta de cópia
Esqarrouth 04/04
4

SWIFT mais recente 3 :

func detectScreenShot(action: @escaping () -> ()) {
        let mainQueue = OperationQueue.main
        NotificationCenter.default.addObserver(forName: .UIApplicationUserDidTakeScreenshot, object: nil, queue: mainQueue) { notification in
            // executes after screenshot
            action()
        }
    }

Em viewDidLoad , chame esta função

detectScreenShot { () -> () in
 print("User took a screen shot")
}

Contudo,

NotificationCenter.default.addObserver(self, selector: #selector(test), name: .UIApplicationUserDidTakeScreenshot, object: nil)

    func test() {
    //do stuff here
    }

funciona totalmente bem. Não vejo nenhum ponto do mainQueue ...

Maksim Kniazev
fonte
A questão é perguntar como ser notificado antes da captura de tela. Isto diz-lhe depois de ter sido tomada.
Rddydy
1
@rmaddy, onde você viu essa pergunta perguntando como ser notificado antes? Eu só melhorou a resposta acima de mim, não tenho certeza o seu comentário intenção ..
Maksim Kniazev
A pergunta é: "detecte que o usuário está fazendo uma captura de tela" . Se o OP quisesse saber após o fato, a pergunta deveria ser: "detecte que o usuário fez uma captura de tela" .
Rddydy 22/07
1

Parece que não há uma maneira direta de fazer isso para detectar se o usuário tocou home + power button. Conforme isso , foi possível anteriormente usando a notificação darwin, mas não funciona mais. Como o snapchat já está fazendo isso, meu palpite é que eles estão verificando o álbum de fotos do iPhone para detectar se há uma nova imagem adicionada entre esses 10 segundos e de alguma forma eles estão comparando com a imagem atual exibida. Pode ser que algum processamento de imagem seja feito para essa comparação. Apenas um pensamento, provavelmente você pode tentar expandir isso para fazê-lo funcionar. Verifique isso para mais detalhes .

Editar:

Parece que eles podem estar detectando o evento de cancelamento do UITouch (a captura de tela cancela os toques) e mostrando esta mensagem de erro ao usuário de acordo com este blog: Como detectar capturas de tela no iOS (como SnapChat)

Nesse caso, você pode usar o – touchesCancelled:withEvent:método para detectar o cancelamento do UITouch para detectar isso. Você pode remover a imagem nesse método delegado e mostrar um alerta apropriado ao usuário.

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];

    NSLog(@"Touches cancelled");

    [self.imageView removeFromSuperView]; //and show an alert to the user
}
iDev
fonte
você parece estar bem ligado nos lugares certos para obter uma resposta definitiva sobre isso;)
smileyborg
É mais um palpite educado do que uma resposta definitiva. Infelizmente não tenho conexões para obter uma resposta exata para isso. Se eles não estiverem usando nenhuma API privada, é a única maneira de pensar, para fazer isso. Para detectar a adição de imagem ao álbum e comparar essa imagem com a imagem atual na tela com base em algum algoritmo.
IDev
Mas, como eles podem fazer isso sem solicitar acesso às fotos e ao rolo da câmera do dispositivo ... deve ser outra coisa, não? Minha teoria estaria relacionada ao fato de eles fazerem com que você pressione demoradamente a mensagem fotográfica recebida para visualizá-la e que, quando você pressiona Home + Lockbotões, o sistema operacional age imediatamente como se nenhum dedo estivesse tocando a tela. Talvez isso aconteça sem um touchesEnded:withEvent(ou retorno de chamada semelhante) como faria normalmente, então talvez eles possam monitorar esse padrão único de eventos? Posso estar totalmente no caminho errado, mas essa é a minha única teoria neste momento.
21812 smileyborg
Coloque um dedo na tela e, sem levantá-lo, tente se você pode pressionar os outros dois botões. Ainda estava mostrando essa mensagem, eu acho. Pode ser que eles estejam usando alguma API privada e de alguma forma conseguiram colocar na appstore.
IDev
2
Não é mais possível a partir do iOS 7.
God of Biscuits
1

Swift 4+

NotificationCenter.default.addObserver(forName: UIApplication.userDidTakeScreenshotNotification, object: nil, queue: OperationQueue.main) { notification in
           //you can do anything you want here. 
        }

usando esse observador, você pode descobrir quando o usuário faz uma captura de tela, mas não pode impedi-lo.

Hamid Shahsavari
fonte
0

Swift 4 Exemplos

Exemplo # 1 usando fechamento

NotificationCenter.default.addObserver(forName: .UIApplicationUserDidTakeScreenshot, 
                                       object: nil, 
                                       queue: OperationQueue.main) { notification in
    print("\(notification) that a screenshot was taken!")
}

Exemplo # 2 com seletor

NotificationCenter.default.addObserver(self, 
                                       selector: #selector(screenshotTaken), 
                                       name: .UIApplicationUserDidTakeScreenshot, 
                                       object: nil)

@objc func screenshotTaken() {
    print("Screenshot taken!")
}
Devbot10
fonte