iOS检测屏幕截图?


135

该应用程序Snapchat,在App Store上,是一个应用程序,可以让你分享他们自毁图片。您只能查看图片X秒钟。如果您在显示图片时使用家庭电源键组合拍摄屏幕截图,则会告诉发送者您尝试拍摄屏幕截图。

SDK的哪一部分可让您检测到用户正在截屏?我不知道这是可能的。


1
stackoverflow.com/questions/2121970/…,看起来像以前曾调用过-applicationDidEnterBackground:,然后才获得了屏幕截图。现在不确定。
iDev 2012年

伙计们 其他线程有答案:stackoverflow.com/questions/2121970/...
ME2

1
也请检查一下stackoverflow.com/a/8711894/1730272,它说不可能了。可能您可以尝试一下,并告诉我们。
iDev 2012年

尚未在Internet上的任何地方看到此消息,但我认为,如果您使用Xcode截屏(从Organizer窗口中的设备上),则该应用程序绝对无法知道。它必须在查看收到的Snapchat照片的同时监视相机胶卷中添加的任何照片,并且通过Xcode截取屏幕快照完全绕过了这一过程(无需越狱)。
smileyborg 2012年

后续行动:测试了该理论并确认该应用程序未检测到Xcode屏幕截图。但是,我意识到有趣的是,在iOS 6上,必须明确授予应用访问照片的权限...但是,该应用仍会检测屏幕截图,而不允许其访问照片!它必须使用另一种检测方法-我注意到当使用Home + Sleep按钮方法时,活动照片也会从屏幕上删除。因此,必须有一些与此屏幕快照过程相关的模式,应用程序才能可靠地对其进行监视,也许使用GestureRecognizer?
smileyborg 2012年

Answers:


22

我找到答案了!截屏会中断屏幕上的所有触摸。这就是为什么手套需要握住才能看到图片的原因。参考:http : //tumblr.jeremyjohnstone.com/post/38503925370/how-to-detect-screenshots-on-ios-like-snapchat


15
对于iOS 7不再适用。有关iOS7 +解决方案,请参见下文
乔·马西洛蒂

6
乔说的是正确的。询问者应取消选中此作为正确答案。
饼干神

可以使用UIApplication用户已接受截屏通知.. iOS 7+
Amit Tandel

353

从iOS 7开始,其他答案不再正确。苹果已经做到了,所以touchesCancelled:withEvent:当用户拍摄屏幕截图时不再称呼它。

这将有效地完全打破Snapchat,因此在新解决方案中添加了几个beta。现在,解决方案就像使用NSNotificationCenter向UIApplicationUserDidTakeScreenshotNotification添加观察者一样简单。

这是一个例子:

目标C

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
这无法防止截屏。它只能让应用程序知道有人采取了该方法。该通知不包含userInfo字典。截取屏幕快照后,将发布此通知。
badweasel

6
@badweasel正确。考虑到此通知遵循常规的可可命名约定,因此“ Did”一词表示该通知是在事实之后发布的。在这种情况下,没有“ Will”等效项,并且AFAIK也无法阻止用户使用公共API截屏。
Mick MacCallum 2013年

1
请注意,我给了您+1。我最初误读了OP问题,以为问题是如何检测到它以防止发生某些事情-因为这就是我要寻找的。因此,我只是在评论中添加了说明,因为我希望很多人都在寻找该问题的答案。我也从“ did”一词中推测出了这一点,但是文档更加清楚了。在我的应用程序中,我允许人们编辑照片,但是某些工具需要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")
}

斯威夫特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

免责声明:这是我的回购


嘿,我尝试了一下,效果很好,但是您能解释一下代码中发生了什么吗?我是Swift的新手,很难读懂。
登场

这就是其中一种,“如果可行的话就不要搞砸”这类代码。您无需了解这会导致什么,因为这里使用的框架非常罕见。
Esqarrouth '02

但是,如果您不知道闭包的工作原理,则应该检查一下闭包是如何工作的,基本上,当您调用检测截屏函数时,闭包中的内容都会作为动作函数发送给您
Esqarrouth

@Esqarrouth在主队列上执行此操作的任何特定原因?
kidsid49年

复制粘贴的原因
Esqarrouth '17

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的任何要点...


问题是询问在截屏之前如何得到通知。这告诉你之后,已经采取IS。
-rmaddy

1
@rmaddy您在哪里看到了这个问题,问过如何提前得到通知?我只是改善了我的回答,不确定您的评论意图..
Maksim Kniazev '18

问题问:“检测到用户正在截屏”。如果OP希望在事后知道,该问题应显示为:“检测到用户拍摄了屏幕截图”
-rmaddy

1

似乎没有直接的方法可以检测用户是否点击了home + power button。按照这种方式,可以通过使用darwin通知来实现此功能,但是它不再起作用。由于gmail已经在做,所以我猜测他们正在检查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
}

您似乎在正确的地方联系紧密,可以找到确切的答案;)
smileyborg 2012年

这更多是有根据的猜测,而不是确切的答案。不幸的是,我没有任何联系可以得到确切的答案。如果他们没有使用任何私有API,那是我想到的唯一方法。要检测添加到相册的图像,并根据某种算法将该图像与屏幕上的当前图像进行比较。
iDev 2012年

但是鉴于他们可以做到这一点而无需请求访问设备的照片和“相机胶卷”……这一定不是吗?我的理论与以下事实有关:它们使您长按收到的照片消息来查看它,并且当您按下Home + Lock按钮时,操作系统会立即像没有手指触摸屏幕一样起作用。也许这种情况没有touchesEnded:withEvent通常发生的(或类似的回调)发生,所以他们可以监视这种独特的事件模式吗?我可能完全走错了方向,但这是我目前唯一的理论。
smileyborg 2012年

将手指放在屏幕上,不要抬起它,请尝试按其他两个按钮。我猜它仍在显示该信息。因此,可能是他们使用了一些私有API并设法以某种方式将它们放入了appstore。
iDev 2012年

2
不再尽可能的iOS 7
饼干的神

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

Example#2 with选择器

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

@objc func screenshotTaken() {
    print("Screenshot taken!")
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.