iOS обнаружение скриншота?

135

Приложение Snapchat в App Store - это приложение, которое позволяет вам делиться фотографиями с самоуничтожением. Вы можете просматривать фотографии только в течение X секунд. Если вы попытаетесь сделать снимок экрана во время показа изображения с помощью сочетания клавиш включения питания, он сообщит отправителю, что вы попытались сделать снимок экрана.

Какая часть SDK позволяет определить, что пользователь делает снимок экрана? Я не знал, что это возможно.

те2
источник
1
stackoverflow.com/questions/2121970/… , похоже, он раньше вызывал -applicationDidEnterBackground: перед тем, как сделать снимок экрана ранее. Не уверен насчет этого сейчас.
iDev
Ребята. Другой поток имеет ответ: stackoverflow.com/questions/2121970/…
me2
1
проверьте это также, stackoverflow.com/a/8711894/1730272 , он говорит, что это больше невозможно. Возможно, вы можете попробовать это и сообщить нам.
iDev
Еще нигде в интернете об этом не упоминалось, но я предполагаю, что если вы используете Xcode для создания снимка экрана (с устройства в окне «Органайзер»), приложение не сможет узнать об этом. Он должен контролировать Camera Roll для всех фотографий, добавленных во время просмотра полученной фотографии Snapchat, и делать снимок экрана через XCode вообще обходит это (без необходимости джейлбрейка).
smileyborg
Продолжение: проверил эту теорию и подтвердил, что приложение не обнаруживает скриншоты Xcode. Тем не менее, я понял, что интересно то, что на iOS 6 приложениям должно быть явно предоставлено разрешение на доступ к фотографиям ... но это приложение по-прежнему обнаруживает скриншоты, не позволяя ему получать доступ к фотографиям! Должно быть, используется другой метод обнаружения - я замечаю, что при использовании метода Home + Sleep button активная фотография также удаляется с экрана. Таким образом, должен быть какой-то шаблон, связанный с этим процессом скриншота, который приложение может надежно отслеживать, возможно, с помощью GestureRecognizer?
smileyborg

Ответы:

22

Я нашел ответ! Снимок экрана прерывает любые прикосновения, которые находятся на экране. Вот почему Snapchat требует удержания, чтобы увидеть картинку. Ссылка: http://tumblr.jeremyjohnstone.com/post/38503925370/how-to-detect-screenshots-on-ios-like-snapchat

portforwardpodcast
источник
15
Больше не работает с iOS 7. См. Ниже решение для iOS7 +.
Джо Масилотти
6
То, что сказал Джо, верно. Аскер должен снять галочку как правильный ответ.
Бог печенья
Пользователь UIApplication сделал снимок экрана уведомления могут быть использованы .. iOS 7+
Amit Tandel
353

Начиная с iOS 7 другие ответы больше не верны. Apple сделала это так touchesCancelled:withEvent:, больше не называется, когда пользователь делает снимок экрана.

Это полностью разрушило бы Snapchat, поэтому была добавлена ​​пара бета-версий в новом решении. Теперь решение так же просто, как использование NSNotificationCenter для добавления наблюдателя в UIApplicationUserDidTakeScreenshotNotification .

Вот пример:

Цель С

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

стриж

NotificationCenter.default.addObserver(
    forName: UIApplication.userDidTakeScreenshotNotification,
    object: nil,
    queue: .main) { notification in
        //executes after screenshot
}
Мик МакКаллум
источник
3
Использование этого и touchesCancelled:withEvent:должно позволить вам обнаружить скриншот на всех (последних) версиях iOS.
Джошуа Гросс
46
Это не работает, чтобы не сделать снимок экрана. Оно может только сообщить приложению, что оно было взято. Из ссылки на класс UIApplication: UIApplicationUserDidTakeScreenshotNotification Опубликовано, когда пользователь нажимает кнопки «Домой» и «Блокировка», чтобы сделать снимок экрана. Это уведомление не содержит словаря userInfo. Это уведомление размещено ПОСЛЕ снятия скриншота.
badweasel
6
@badweasel Правильно. Учитывая, что это уведомление следует обычным соглашениям о присвоении имен какао, слово «сделал» подразумевает, что оно публикуется после факта. В этом случае нет эквивалента «Воля», и AFAIK не может помешать пользователю сделать снимок экрана с помощью общедоступного API.
Мик МакКаллум,
1
Обратите внимание, что я дал вам +1. Первоначально я неправильно прочитал вопрос ОП и подумал, что вопрос заключается в том, как его обнаружить, чтобы что-то предотвратить, потому что это то, что я искал. Поэтому я просто добавил пояснение в комментарии, потому что ожидаю, что многие люди, приходящие на этот вопрос, ищут этот ответ. Я предположил, что также от слова "сделал", но документация делает это еще более ясным. В моем приложении я позволяю людям редактировать фотографии, но некоторые инструменты требуют IAP. Но я позволил им попробовать, прежде чем купить. Поэтому я хотел обнаружить, прежде чем он был захвачен, чтобы добавить водяной знак. Не может быть сделано
badweasel
1
@MickMacCallum Есть какая-то конкретная причина, по которой вы делаете это в главной очереди?
kidsid49
13

Вот как это сделать в Swift с замыканиями:

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

Это включено как стандартная функция в:

https://github.com/goktugyil/EZSwiftExtensions

Отказ от ответственности: это мой репо

Esqarrouth
источник
Эй, я попробовал это, и это отлично сработало, но не могли бы вы немного объяснить, что происходит в коде? Я новичок в Swift, и его немного сложно читать.
конец
Это один из тех кодов типа «если это работает, не связывайтесь с ним». Вам не нужно изучать, что это делает, потому что используемые здесь фреймворки очень редки.
Esqarrouth
Но вы должны проверить, как работают замыкания, если вы не знаете эту часть, в основном, когда вы вызываете функцию определения снимка экрана, все, что вы помещаете в парантезы, отправляется как функция действия
Esqarrouth
@ Esqarrouth По какой-то конкретной причине вы делаете это в главной очереди?
kidsid49
Причина копирования паста
Esqarrouth
4

Последний 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()
        }
    }

В viewDidLoad , вызовите эту функцию

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

Тем не мение,

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

    func test() {
    //do stuff here
    }

работает совершенно нормально. Я не вижу никаких точек mainQueue ...

Максим Князев
источник
Вопрос в том, как получить уведомление до того, как будет сделан снимок экрана. Это говорит вам после того, как это было принято.
rmaddy
1
@ rmaddy, где вы видели, что вопрос спрашивает, как получать уведомления раньше? Я только улучшил ответ над собой, не уверенный в вашем намерении комментировать ..
Максим Князев
Вопрос задается: «определить, что пользователь делает снимок экрана» . Если ОП хотел знать об этом после факта, вопрос должен гласить: «определить, что пользователь сделал снимок экрана» .
rmaddy
1

Похоже, что нет прямого способа сделать это, чтобы обнаружить, нажал ли пользователь home + power button. Согласно этому , это было возможно раньше с помощью уведомления Дарвина, но это больше не работает. Так как Snapchat уже делает это, я предполагаю, что они проверяют фотоальбом iPhone, чтобы определить, было ли добавлено новое изображение в течение этих 10 секунд, и в какой-то мере они сравниваются с текущим отображаемым изображением. Может быть некоторая обработка изображения сделана для этого сравнения. Просто мысль, возможно, вы можете попытаться расширить это, чтобы оно заработало. Проверьте это для более подробной информации .

Редактировать:

Похоже, что они могут обнаружить событие отмены UITouch (Снимок экрана отменяет касания) и показать это сообщение об ошибке пользователю согласно этому блогу: Как обнаружить скриншоты на iOS (например, Snapchat)

В этом случае вы можете использовать – touchesCancelled:withEvent:метод для определения отмены UITouch, чтобы обнаружить это. Вы можете удалить изображение в этом методе делегата и показать соответствующее предупреждение пользователю.

- (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
источник
вы, кажется, хорошо связаны в нужных местах, чтобы получить окончательный ответ об этом;)
smileyborg
Это скорее обоснованное предположение, чем окончательный ответ. К сожалению, у меня нет никаких связей, чтобы получить точный ответ на это. Если они не используют какие-либо частные API, это единственный способ, который я могу придумать для этого. Для обнаружения добавления изображения в альбом и сравнения этого изображения с текущим изображением на экране на основе некоторого алгоритма.
iDev
Но, учитывая, что они могут сделать это, не запрашивая доступ к фотографиям устройства и Camera Roll ... это должно быть что-то еще нет? Моя теория была бы связана с тем, что они заставляют вас долго нажимать на полученное фото-сообщение, чтобы просмотреть его, и что, когда вы нажимаете Home + Lockкнопки, ОС немедленно действует так, как будто пальцы не касаются экрана. Может быть, это происходит без touchesEnded:withEvent(или аналогичного обратного вызова), как это обычно бывает , поэтому, возможно, они могут отслеживать этот уникальный паттерн событий? Я могу быть совершенно не на том пути, но это моя единственная теория на данный момент.
smileyborg
Положите палец на экран и, не поднимая его, попробуйте нажать две другие кнопки. Я думаю, это все еще показывало это сообщение. Так что, может быть, они используют какой-то частный API и каким-то образом удалось разместить его в магазине приложений.
iDev
2
С iOS 7 больше не возможно.
God of Biscuits
1

Свифт 4+

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

С помощью этого наблюдателя вы можете узнать, когда пользователь делает снимок экрана, но вы не можете предотвратить его.

Хамид Шахсавари
источник
0

Swift 4 Примеры

Пример № 1 с использованием замыкания

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

Пример №2 с селектором

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

@objc func screenshotTaken() {
    print("Screenshot taken!")
}
Devbot10
источник