Rilevamento iOS della schermata?


135

L'app Snapchat , sull'App Store, è un'app che ti consente di condividere foto con un'autodistruzione su di esse. Puoi visualizzare le immagini solo per X secondi. Se provi a fare uno screenshot mentre l'immagine viene mostrata usando la combinazione di tasti di accensione, indicherà al mittente che hai provato a fare uno screenshot.

Quale parte dell'SDK ti consente di rilevare che l'utente sta eseguendo uno screenshot? Non sapevo che ciò fosse possibile.


1
stackoverflow.com/questions/2121970/… , sembra che abbia usato per chiamare -applicationDidEnterBackground: prima di fare uno screenshot in precedenza. Non ne sono sicuro ora.
iDev,

Ragazzi. L'altra discussione ha la risposta: stackoverflow.com/questions/2121970/…
me2

1
controlla anche questo, stackoverflow.com/a/8711894/1730272 , dice che non è più possibile. Probabilmente puoi provarlo e farcelo sapere.
iDev,

Non l'ho ancora visto menzionato da nessuna parte su Internet, ma suppongo che se usi Xcode per fare uno screenshot (dal dispositivo nella finestra Organizer), l'app non sarà assolutamente in grado di saperlo. Deve monitorare il rullino fotografico per eventuali foto aggiunte durante la visualizzazione di una foto Snapchat ricevuta e fare lo screenshot tramite Xcode lo ignora del tutto (senza la necessità di jailbreaking).
smileyborg,

Follow-up: testato questa teoria e confermato che l'app non rileva schermate Xcode. Tuttavia, mi sono reso conto che ciò che è interessante è che su iOS 6, alle app deve essere esplicitamente concesso il permesso di accedere alle foto ... eppure questa app rileva ancora schermate senza consentirle di accedere alle foto! Deve utilizzare un altro metodo per il rilevamento: sto notando che quando si utilizza il metodo del pulsante Home + Sospensione, anche la foto attiva viene rimossa dallo schermo. Quindi ci deve essere un modello correlato a questo processo di screenshot che l'app può monitorare in modo affidabile, forse con un GestureRecognizer?
smileyborg,

Risposte:


22

Ho trovato la risposta !! Fare uno screenshot interrompe qualsiasi tocco sullo schermo. Questo è il motivo per cui Snapchat richiede di tenere premuto per vedere l'immagine. Riferimento: http://tumblr.jeremyjohnstone.com/post/38503925370/how-to-detect-screenshots-on-ios-like-snapchat


15
Non è più vero con iOS 7. Vedi sotto per una soluzione iOS7 +.
Joe Masilotti,

6
Ciò che Joe ha detto è corretto. Il richiedente dovrebbe deselezionarlo come risposta corretta.
God of Biscuits,

L'utente di UIApplication ha preso la notifica della schermata può essere utilizzato .. iOS 7+
Amit Tandel

353

A partire da iOS 7 le altre risposte non sono più vere. Apple l'ha fatto, quindi touchesCancelled:withEvent:non viene più chiamato quando l'utente prende uno screenshot.

Questo effettivamente spezzerebbe completamente Snapchat, quindi è stato aggiunto un paio di beta in una nuova soluzione. Ora, la soluzione è semplice come usare NSNotificationCenter per aggiungere un osservatore a UIApplicationUserDidTakeScreenshotNotification .

Ecco un esempio:

Obiettivo C

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

veloce

NotificationCenter.default.addObserver(
    forName: UIApplication.userDidTakeScreenshotNotification,
    object: nil,
    queue: .main) { notification in
        //executes after screenshot
}

3
Utilizzando questo e touchesCancelled:withEvent:dovrebbe consentire di rilevare uno screenshot su tutte le (recenti) versioni di iOS.
Joshua Gross,

46
Questo non funziona per impedire che venga catturato uno screenshot. Può solo far sapere all'app che ne è stata presa una. Dal riferimento alla classe UIApplication: UIApplicationUserDidTakeScreenshotNotification Inserito quando l'utente preme i pulsanti Home e Lock per fare uno screenshot. Questa notifica non contiene un dizionario userInfo. Questa notifica viene pubblicata DOPO lo screenshot.
badweasel,

6
@badweasel Correct. Considerando che questa notifica segue le convenzioni convenzionali di denominazione del cacao, la parola "Did" implica che è postata dopo il fatto. Non esiste un equivalente "Volontà" in questo caso e AFAIK non ha modo di impedire all'utente di fare uno screenshot usando l'API pubblica.
Mick MacCallum,

1
Nota che ti ho dato un +1. Inizialmente avevo letto male la domanda del PO e ho pensato che la domanda fosse come rilevarla per prevenire qualcosa - perché era quello che stavo cercando. Quindi ho appena aggiunto il chiarimento nel commento perché mi aspetto che molte persone che arrivano a questa domanda stiano cercando quella risposta. Ho assunto che anche dalla parola "ha fatto", ma la documentazione lo rende ancora più chiaro. Nella mia app sto permettendo alle persone di modificare le foto ma alcuni degli strumenti richiedono IAP. Ma li ho lasciati provare prima di acquistare. Quindi volevo rilevare prima che fosse catturato per aggiungere una filigrana. Non si può fare
badweasel,

1
@MickMacCallum Qual è il motivo specifico per cui lo stai facendo nella coda principale?
kidsid49

13

Ecco come fare in Swift con chiusure:

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")
}

Rapido 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()
    }
}

Questo è incluso come funzione standard in:

https://github.com/goktugyil/EZSwiftExtensions

Disclaimer: è il mio repository


Ehi, ci ho provato e ha funzionato alla grande, ma puoi spiegarci un po 'cosa sta succedendo nel codice? Sono nuovo di Swift ed è un po 'difficile da leggere.
attendere il

Questo è uno di quelli, "se funziona non scherzare con esso" tipo di codici. Non è necessario sapere che cosa causa i framework utilizzati qui sono molto rari.
Esqarrouth,

Ma dovresti controllare come funzionano le chiusure se non conosci quella parte, è fondamentalmente quando chiami Rileva funzione screen shot, tutto ciò che metti nelle paratie viene inviato come una funzione di azione
Esqarrouth,

@Esqarrouth Qual è il motivo specifico per cui lo stai facendo nella coda principale?
kidsid49

Causa della copia incolla
Esqarrouth

4

SWIFT 3 più recente :

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

In viewDidLoad , chiama questa funzione

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

Però,

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

    func test() {
    //do stuff here
    }

funziona perfettamente. Non vedo alcun punto di mainQueue ...


La domanda è come ricevere una notifica prima che venga acquisito lo screenshot. Questo ti dice dopo che è stato preso.
rmaddy,

1
@rmaddy dove hai visto che la domanda sta chiedendo come ricevere una notifica prima? Ho solo migliorato la risposta sopra di me, non sono sicuro della tua intenzione di commento ..
Maksim Kniazev

La domanda si pone: "rileva che l'utente sta facendo uno screenshot" . Se l'OP voleva sapere dopo il fatto, la domanda dovrebbe essere: "rileva che l'utente ha preso uno screenshot" .
rmaddy,

1

Sembra che non ci sia un modo diretto per farlo per rilevare se l'utente ha toccato home + power button. Per questo , era possibile in precedenza utilizzando la notifica darwin, ma non funziona più. Dal momento che Snapchat lo sta già facendo, la mia ipotesi è che stiano controllando l'album fotografico dell'iPhone per rilevare se è stata aggiunta una nuova immagine tra questi 10 secondi e in qualche modo si stanno confrontando con l'immagine corrente visualizzata. Può essere che l'elaborazione di alcune immagini venga eseguita per questo confronto. Solo un pensiero, probabilmente puoi provare ad espandere questo per farlo funzionare. Controlla questo per maggiori dettagli .

Modificare:

Sembra che stiano rilevando l'evento di annullamento di UITouch (la cattura dello schermo annulla i tocchi) e mostra questo messaggio di errore all'utente come da questo blog: Come rilevare schermate su iOS (come SnapChat)

In tal caso è possibile utilizzare il – touchesCancelled:withEvent:metodo per rilevare la cancellazione di UITouch per rilevarlo. È possibile rimuovere l'immagine con questo metodo delegato e mostrare un avviso appropriato all'utente.

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

sembri essere ben collegato nei posti giusti per ottenere una risposta definitiva a riguardo;)
smileyborg,

È più un'ipotesi colta che una risposta definitiva. Purtroppo non ho alcuna connessione per ottenere una risposta esatta per questo. Se non utilizzano API private, è l'unico modo in cui riesco a pensare, per farlo. Per rilevare l'aggiunta di immagini all'album e confrontarla con l'immagine corrente sullo schermo in base ad un algoritmo.
iDev,

Ma dato che possono farlo senza richiedere l'accesso alle foto del dispositivo e al Rullino fotografico ... deve essere qualcos'altro no? La mia teoria sarebbe legata al fatto che ti fanno premere a lungo sul messaggio fotografico ricevuto per visualizzarlo e che quando si premono i Home + Lockpulsanti, il sistema operativo si comporta immediatamente come se nessuna dita toccasse lo schermo. Forse questo accade senza una touchesEnded:withEvent(o simile callback) come normalmente, quindi forse possono monitorare questo modello unico di eventi? Potrei essere totalmente sulla strada sbagliata, ma questa è la mia unica teoria a questo punto.
smileyborg,

Metti un dito sullo schermo e senza sollevarlo, prova a premere gli altri due pulsanti. Stava ancora mostrando quel messaggio, immagino. Quindi potrebbero essere che stanno usando alcune API private e in qualche modo sono riusciti a mettere in appstore.
iDev,

2
Non più possibile a partire da 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 questo osservatore puoi scoprire quando l'utente prende uno screenshot, ma non puoi impedirlo.


0

Swift 4 esempi

Esempio n. 1 usando la chiusura

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

Esempio n. 2 con selettore

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

@objc func screenshotTaken() {
    print("Screenshot taken!")
}
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.