Détection iOS de capture d'écran?

135

L'application Snapchat , sur l'App Store, est une application qui vous permet de partager des images avec une auto-destruction sur elles. Vous ne pouvez voir les photos que pendant X secondes. Si vous essayez de prendre une capture d'écran pendant que l'image est affichée à l'aide de la combinaison de touches d'alimentation principale, il indiquera à l'expéditeur que vous avez essayé de prendre une capture d'écran.

Quelle partie du SDK vous permet de détecter que l'utilisateur prend une capture d'écran? Je ne savais pas que c'était possible.

moi2
la source
1
stackoverflow.com/questions/2121970/… , On dirait qu'il a utilisé pour appeler -applicationDidEnterBackground: avant de prendre la capture d'écran plus tôt. Pas sûr à ce sujet maintenant.
iDev
Les mecs. L'autre thread a la réponse: stackoverflow.com/questions/2121970/…
me2
1
vérifiez cela également, stackoverflow.com/a/8711894/1730272 , il dit que ce n'est plus possible. Vous pouvez probablement l'essayer et nous le faire savoir.
iDev
Je n'ai encore vu cela mentionné nulle part sur Internet, mais je suppose que si vous utilisez Xcode pour prendre une capture d'écran (à partir de l'appareil dans la fenêtre de l'organiseur), il n'y a absolument aucun moyen pour l'application de le savoir. Il doit surveiller la pellicule pour toutes les photos ajoutées lors de la visualisation d'une photo Snapchat reçue, et prendre la capture d'écran via Xcode contourne complètement cela (sans avoir besoin de jailbreaking).
smileyborg
Suivi: testé cette théorie et confirmé que l'application ne détecte pas les captures d'écran Xcode. Cependant, j'ai réalisé que ce qui est intéressant, c'est que sur iOS 6, les applications doivent explicitement être autorisées à accéder aux photos ... pourtant cette application détecte toujours les captures d'écran sans lui permettre d'accéder aux photos! Il doit utiliser une autre méthode de détection - je remarque que lorsque vous utilisez la méthode du bouton Accueil + Veille, la photo active est également supprimée de l'écran. Il doit donc y avoir un modèle lié à ce processus de capture d'écran que l'application peut surveiller de manière fiable, peut-être avec un GestureRecognizer?
smileyborg

Réponses:

22

J'ai trouvé la réponse !! Prendre une capture d'écran interrompt toutes les touches qui sont sur l'écran. C'est pourquoi Snapchat nécessite de tenir pour voir l'image. Référence: http://tumblr.jeremyjohnstone.com/post/38503925370/how-to-detect-screenshots-on-ios-like-snapchat

portforwardpodcast
la source
15
Ce n'est plus vrai avec iOS 7. Voir ci - dessous pour une solution iOS7 +.
Joe Masilotti
6
Ce que Joe a dit est correct. Le demandeur doit décocher cette case comme étant la bonne réponse.
God of Biscuits
La notification de capture d'écran par l'utilisateur UIApplication peut être utilisée. IOS 7+
Amit Tandel
353

Depuis iOS 7, les autres réponses ne sont plus vraies. Apple a fait en sorte qu'il touchesCancelled:withEvent:ne soit plus appelé lorsque l'utilisateur prend une capture d'écran.

Cela casserait complètement Snapchat, donc quelques bêtas dans une nouvelle solution ont été ajoutés. Désormais, la solution est aussi simple que d'utiliser NSNotificationCenter pour ajouter un observateur à UIApplicationUserDidTakeScreenshotNotification .

Voici un exemple:

Objectif c

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

Rapide

NotificationCenter.default.addObserver(
    forName: UIApplication.userDidTakeScreenshotNotification,
    object: nil,
    queue: .main) { notification in
        //executes after screenshot
}
Mick MacCallum
la source
3
Son utilisation touchesCancelled:withEvent:devrait vous permettre de détecter une capture d'écran sur toutes les versions (récentes) d'iOS.
Joshua Gross le
46
Cela ne fonctionne pas pour empêcher la capture d'une capture d'écran. Il ne peut que faire savoir à l'application que l'une d'entre elles a été prise. Depuis la référence de classe UIApplication: UIApplicationUserDidTakeScreenshotNotification Publié lorsque l'utilisateur appuie sur les boutons Accueil et Verrouiller pour prendre une capture d'écran. Cette notification ne contient pas de dictionnaire userInfo. Cette notification est publiée APRÈS la capture d'écran.
badweasel
6
@badweasel Correct. Étant donné que cette notification suit les conventions de dénomination conventionnelles de Cocoa, le mot "Did" implique qu'elle est publiée après coup. Il n'y a pas d'équivalent «Will» dans ce cas, et AFAIK aucun moyen d'empêcher l'utilisateur de prendre une capture d'écran en utilisant l'API publique.
Mick MacCallum
1
Notez que je vous ai donné un +1. J'avais mal lu la question du PO au départ et je pensais que la question était de savoir comment la détecter pour empêcher quelque chose - parce que c'est ce que je cherchais. Je viens donc d'ajouter la clarification dans le commentaire parce que je m'attends à ce que beaucoup de gens qui viennent à cette question recherchent cette réponse. J'ai supposé cela aussi du mot «fait», mais la documentation le rend encore plus clair. Dans mon application, j'autorise les gens à modifier des photos, mais certains outils nécessitent des IAP. Mais je les laisse essayer avant d'acheter. J'ai donc voulu détecter avant qu'il ne soit capturé pour ajouter un filigrane. Ça ne peut pas être fait.
badweasel
1
@MickMacCallum Une raison spécifique pour laquelle vous le faites sur la file d'attente principale?
kidsid49
13

Voici comment faire dans Swift avec des fermetures:

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

Ceci est inclus en tant que fonction standard dans:

https://github.com/goktugyil/EZSwiftExtensions

Avertissement: c'est mon dépôt

Esqarrouth
la source
Hé, j'ai essayé ça et ça a très bien fonctionné, mais peux-tu expliquer un peu ce qui se passe dans le code? Je suis nouveau sur Swift et c'est un peu difficile à lire.
aecend
C'est l'un de ces types de codes "si ça marche, ne joue pas avec ça". Vous n'avez pas besoin d'apprendre ce que cela fait car les frameworks utilisés ici sont très rares.
Esqarrouth
Mais vous devriez vérifier comment fonctionnent les fermetures si vous ne connaissez pas cette partie, c'est essentiellement lorsque vous appelez la fonction de détection de capture d'écran, tout ce que vous mettez dans les parantheses est envoyé comme une fonction d'action
Esqarrouth
@Esqarrouth Une raison spécifique pour laquelle vous le faites sur la file d'attente principale?
kidsid49
Cause du copier-coller
Esqarrouth
4

Dernier SWIFT 3 :

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

Dans viewDidLoad , appelez cette fonction

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

cependant,

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

    func test() {
    //do stuff here
    }

fonctionne parfaitement bien. Je ne vois aucun point de mainQueue ...

Maksim Kniazev
la source
La question est de savoir comment être notifié avant que la capture d'écran ne soit prise. Cela vous indique après la prise.
rmaddy le
1
@rmaddy où avez-vous vu cette question demande comment être notifié auparavant? J'ai seulement amélioré la réponse au-dessus de moi, pas sûr de votre intention de commentaire ..
Maksim Kniazev
La question se pose: "détecter que l'utilisateur est en train de prendre une capture d'écran" . Si l'OP voulait savoir après coup, la question devrait se lire: "détecter que l'utilisateur a pris une capture d'écran" .
rmaddy
1

Il semble qu'il n'y ait aucun moyen direct de le faire pour détecter si l'utilisateur a appuyé sur home + power button. De ce fait , c'était possible plus tôt en utilisant la notification Darwin, mais cela ne fonctionne plus. Puisque Snapchat le fait déjà, je suppose qu'ils vérifient l'album photo de l'iPhone pour détecter si une nouvelle image a été ajoutée entre ces 10 secondes, et d'une certaine manière, ils comparent avec l'image actuelle affichée. Peut-être qu'un traitement d'image est effectué pour cette comparaison. Juste une pensée, vous pouvez probablement essayer d'élargir cela pour que cela fonctionne. Vérifiez ceci pour plus de détails .

Éditer:

On dirait qu'ils pourraient détecter l'événement d'annulation UITouch (la capture d'écran annule les touches) et afficher ce message d'erreur à l'utilisateur selon ce blog: Comment détecter les captures d'écran sur iOS (comme SnapChat)

Dans ce cas, vous pouvez utiliser la – touchesCancelled:withEvent:méthode pour détecter l'annulation UITouch pour le détecter. Vous pouvez supprimer l'image dans cette méthode déléguée et afficher une alerte appropriée à l'utilisateur.

- (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
la source
vous semblez être bien connecté aux bons endroits pour obtenir une réponse définitive à ce sujet;)
smileyborg
C'est plus une supposition éclairée qu'une réponse définitive. Malheureusement, je n'ai aucun lien pour obtenir une réponse exacte à ce sujet. S'ils n'utilisent aucune API privée, c'est la seule façon dont je peux penser, pour faire cela. Pour détecter l'ajout d'image à l'album et comparer cette image avec l'image actuelle à l'écran en fonction d'un algorithme.
iDev
Mais étant donné qu'ils peuvent le faire sans demander l'accès aux photos et à la pellicule de l'appareil ... ça doit être autre chose non? Ma théorie serait liée au fait qu'ils vous obligent à appuyer longuement sur le message photo reçu pour l'afficher, et que lorsque vous appuyez sur des Home + Lockboutons, le système d'exploitation agit immédiatement comme si aucun doigt ne touchait l'écran. Peut-être que cela se produit sans un touchesEnded:withEvent(ou un rappel similaire) comme cela se passerait normalement, alors peut-être qu'ils peuvent surveiller ce modèle unique d'événements? Je suis peut-être totalement sur la mauvaise voie, mais c'est ma seule théorie à ce stade.
smileyborg
Mettez un doigt sur l'écran et sans le soulever, essayez si vous pouvez appuyer sur les deux autres boutons. Il montrait toujours ce message, je suppose. Alors peut-être qu'ils utilisent une API privée et ont réussi à mettre en appstore.
iDev
2
Plus possible à partir d'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. 
        }

en utilisant cet observateur, vous pouvez savoir quand l'utilisateur prend une capture d'écran, mais vous ne pouvez pas l'empêcher.

Hamid Shahsavari
la source
0

Exemples de Swift 4

Exemple # 1 utilisant la fermeture

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

Exemple # 2 avec sélecteur

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

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