Wykrywanie zrzutu ekranu w systemie iOS?

135

Aplikacja Snapchat w App Store to aplikacja, która umożliwia udostępnianie zdjęć z autodestrukcją. Zdjęcia można oglądać tylko przez X sekund. Jeśli spróbujesz zrobić zrzut ekranu, gdy obraz jest wyświetlany, za pomocą kombinacji klawiszy zasilania domu, nadawca powie, że próbowałeś zrobić zrzut ekranu.

Jaka część zestawu SDK umożliwia wykrycie, że użytkownik wykonuje zrzut ekranu? Nie wiedziałem, że to możliwe.

me2
źródło
1
stackoverflow.com/questions/2121970/… , Wygląda na to, że wywoływał -applicationDidEnterBackground: przed wykonaniem zrzutu ekranu. Teraz nie jestem tego pewien.
iDev
Chłopaki. Drugi wątek ma odpowiedź: stackoverflow.com/questions/2121970/…
me2
1
sprawdź to również, stackoverflow.com/a/8711894/1730272 , mówi, że to już nie jest możliwe. Prawdopodobnie możesz to wypróbować i dać nam znać.
iDev
Nie widziałem jeszcze tego wspomnianego nigdzie w Internecie, ale zakładam, że jeśli użyjesz Xcode do zrobienia zrzutu ekranu (z urządzenia w oknie Organizatora), nie ma absolutnie żadnego sposobu, aby aplikacja mogła się o tym dowiedzieć. Musi monitorować Rolkę z aparatu pod kątem wszelkich dodanych zdjęć podczas przeglądania otrzymanego zdjęcia Snapchata, a zrobienie zrzutu ekranu za pomocą Xcode całkowicie to omija (bez potrzeby jailbreakingu).
smileyborg
Kontynuacja: przetestowano tę teorię i potwierdzono, że aplikacja nie wykrywa zrzutów ekranu Xcode. Jednak zdałem sobie sprawę, że interesujące jest to, że na iOS 6 aplikacje muszą mieć wyraźne pozwolenie na dostęp do zdjęć ... jednak ta aplikacja nadal wykrywa zrzuty ekranu bez zezwolenia na dostęp do zdjęć! Musi używać innej metody wykrywania - zauważam, że podczas korzystania z metody przycisku Home + Sleep aktywne zdjęcie jest również usuwane z ekranu. Więc musi istnieć jakiś wzorzec związany z tym procesem zrzutu ekranu, który aplikacja może niezawodnie monitorować, na przykład za pomocą GestureRecognizer?
smileyborg

Odpowiedzi:

22

Znalazłem odpowiedź !! Zrobienie zrzutu ekranu przerywa wszelkie dotknięcia ekranu. Dlatego snapchat wymaga przytrzymania, aby zobaczyć obraz. Źródła: http://tumblr.jeremyjohnstone.com/post/38503925370/how-to-detect-screenshots-on-ios-like-snapchat

portforwardpodcast
źródło
15
To już nie dotyczy iOS 7. Zobacz poniżej rozwiązanie iOS7 +.
Joe Masilotti
6
To, co powiedział Joe, jest poprawne. Asker powinien odznaczyć tę odpowiedź jako właściwą.
God of Biscuits
UIApplication Użytkownik zrobił powiadomienie o zrobieniu zrzutu ekranu może być użyty. IOS 7+
Amit Tandel
353

Od iOS 7 inne odpowiedzi nie są już prawdziwe. Apple sprawiło, że tak touchesCancelled:withEvent:się nie dzieje, gdy użytkownik robi zrzut ekranu.

To skutecznie całkowicie zepsułoby Snapchata, więc dodano kilka wersji beta w nowym rozwiązaniu. Teraz rozwiązanie jest tak proste, jak użycie NSNotificationCenter w celu dodania obserwatora do UIApplicationUserDidTakeScreenshotNotification .

Oto przykład:

Cel C

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

Szybki

NotificationCenter.default.addObserver(
    forName: UIApplication.userDidTakeScreenshotNotification,
    object: nil,
    queue: .main) { notification in
        //executes after screenshot
}
Mick MacCallum
źródło
3
Korzystanie z tego i touchesCancelled:withEvent:powinno umożliwić wykrycie zrzutu ekranu we wszystkich (najnowszych) wersjach systemu iOS.
Joshua Gross
46
Nie zapobiega to wykonaniu zrzutu ekranu. Może tylko powiadomić aplikację, że jeden z nich został zrobiony. Z klasy referencyjnej UIApplication: UIApplicationUserDidTakeScreenshotNotification Wysłane, gdy użytkownik naciśnie przyciski Home i Lock, aby zrobić zrzut ekranu. To powiadomienie nie zawiera słownika informacji o użytkowniku. To powiadomienie jest wysyłane PO wykonaniu zrzutu ekranu.
badweasel
6
@badweasel Correct. Biorąc pod uwagę, że to powiadomienie jest zgodne z konwencjonalnymi konwencjami nazewnictwa kakao, słowo „wykonano” oznacza, że ​​zostało wysłane po fakcie. W tym przypadku nie ma odpowiednika „Will”, a AFAIK nie ma sposobu, aby uniemożliwić użytkownikowi wykonanie zrzutu ekranu przy użyciu publicznego interfejsu API.
Mick MacCallum
1
Zauważ, że dałem Ci +1. Początkowo źle odczytałem pytanie OP i pomyślałem, że pytanie brzmi, jak je wykryć, aby temu zapobiec - ponieważ tego właśnie szukałem. Dlatego właśnie dodałem wyjaśnienie w komentarzu, ponieważ spodziewam się, że wiele osób przychodzących na to pytanie szuka tej odpowiedzi. Założyłem to również ze słowa „zrobił”, ale dokumentacja czyni to jeszcze bardziej jasnym. W mojej aplikacji pozwalam użytkownikom edytować zdjęcia, ale niektóre narzędzia wymagają IAP. Ale pozwoliłem im spróbować przed zakupem. Chciałem więc wykryć, zanim został przechwycony, aby dodać znak wodny. Nie da się zrobić.
badweasel
1
@MickMacCallum Czy jest jakiś konkretny powód, dla którego robisz to w głównej kolejce?
kidsid49
13

Oto jak to zrobić w Swift z zamknięciami:

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

Jest to standardowa funkcja w:

https://github.com/goktugyil/EZSwiftExtensions

Zastrzeżenie: to moje repozytorium

Esqarrouth
źródło
Hej, próbowałem tego i działało świetnie, ale czy możesz trochę wyjaśnić, co się dzieje w kodzie? Jestem nowy w Swift i jest trochę trudny do odczytania.
koniec
To jeden z tych kodów typu „jeśli to działa, nie zadzieraj z tym”. Nie musisz się uczyć, co to oznacza, ponieważ używane tutaj frameworki są bardzo rzadkie.
Esqarrouth,
Ale trzeba kasy jak zamknięcia działać, jeśli nie wiesz, że udział jego w zasadzie podczas wywoływania func wykryć zrzut ekranu, co kiedykolwiek można umieścić w nawiasach jest wysyłana jako funkcja działania
Esqarrouth
@Esqarrouth Czy jest jakiś konkretny powód, dla którego robisz to w głównej kolejce?
kidsid49
Przyczyna kopiowania wklejania
Esqarrouth
4

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

W viewDidLoad wywołaj tę funkcję

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

Jednak,

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

    func test() {
    //do stuff here
    }

działa całkowicie dobrze. Nie widzę żadnych punktów mainQueue ...

Maksim Kniazev
źródło
Pytanie brzmi, jak zostać powiadomionym przed zrobieniem zrzutu ekranu. To mówi ci, kiedy zostało zrobione.
rmaddy
1
@rmaddy gdzie widziałeś to pytanie z pytaniem, jak otrzymywać powiadomienia? Poprawiłem tylko odpowiedź nad sobą, nie jestem pewien twojego zamiaru komentarza ..
Maksim Kniazev
Pytanie brzmi: „wykryj, że użytkownik robi zrzut ekranu” . Jeśli OP chciał wiedzieć po fakcie, pytanie powinno brzmieć: „wykryj, że użytkownik wykonał zrzut ekranu” .
rmaddy
1

Wygląda na to, że nie ma bezpośredniego sposobu, aby to zrobić, aby wykryć, czy użytkownik kliknął home + power button. W związku z tym było to możliwe wcześniej za pomocą powiadomienia Darwina, ale już nie działa. Ponieważ snapchat już to robi, przypuszczam, że sprawdzają album ze zdjęciami iPhone'a, aby wykryć, czy między tymi 10 sekundami dodano nowe zdjęcie, aw jakiś sposób porównują się z wyświetlanym obecnie obrazem. Być może dla tego porównania przeprowadzane jest przetwarzanie obrazu. Tylko myśl, prawdopodobnie możesz spróbować rozszerzyć to, aby działało. Sprawdź to, aby uzyskać więcej informacji .

Edytować:

Wygląda na to, że mogą wykrywać zdarzenie anulowania UITouch (zrzut ekranu anuluje dotknięcia) i wyświetlać użytkownikowi ten komunikat o błędzie zgodnie z tym blogiem: Jak wykryć zrzuty ekranu w iOS (jak SnapChat)

W takim przypadku możesz użyć – touchesCancelled:withEvent:metody, aby wykryć anulowanie UITouch, aby to wykryć. Możesz usunąć obraz w tej metodzie delegata i pokazać użytkownikowi odpowiedni alert.

- (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
źródło
wydaje się, że jesteś dobrze połączony we właściwych miejscach, aby uzyskać ostateczną odpowiedź na ten temat;)
smileyborg
Jest to raczej zgadywanie, niż ostateczna odpowiedź. Niestety nie mam żadnych powiązań, aby uzyskać dokładną odpowiedź na to pytanie. Jeśli nie używają żadnych prywatnych interfejsów API, to jedyny sposób, jaki mogę wymyślić, aby to zrobić. Aby wykryć dodanie obrazu do albumu i porównać ten obraz z bieżącym obrazem na ekranie na podstawie pewnego algorytmu.
iDev
Ale biorąc pod uwagę, że mogą to zrobić bez proszenia o dostęp do zdjęć urządzenia i Rolki z aparatu ... to musi być coś innego, prawda? Moja teoria byłaby związana z faktem, że zmuszają cię do długiego naciskania otrzymanej wiadomości ze zdjęciem, aby ją wyświetlić, oraz że po naciśnięciu Home + Lockprzycisków system operacyjny natychmiast zachowuje się tak, jakby żaden palec nie dotykał ekranu. Może dzieje się to bez touchesEnded:withEventwywołania zwrotnego (lub podobnego wywołania zwrotnego), jak zwykle, więc może mogą monitorować ten unikalny wzorzec zdarzeń? Być może jestem na złym tropie, ale to moja jedyna teoria w tej chwili.
smileyborg
Połóż palec na ekranie i nie podnosząc go, spróbuj nacisnąć pozostałe dwa przyciski. Chyba nadal pokazywał tę wiadomość. Może więc używają prywatnego API i jakoś udało im się umieścić w Appstore.
iDev
2
Nie jest już możliwe od 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. 
        }

korzystając z tego obserwatora możesz dowiedzieć się, kiedy użytkownik robi zrzut ekranu, ale nie możesz mu zapobiec.

Hamid Shahsavari
źródło
0

Szybkie 4 przykłady

Przykład 1 z użyciem zamknięcia

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

Przykład nr 2 z selektorem

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

@objc func screenshotTaken() {
    print("Screenshot taken!")
}
Devbot10
źródło