【问题标题】:iOS Detection of Screenshot?iOS 检测屏幕截图?
【发布时间】:2012-11-09 04:30:39
【问题描述】:

App Store 上的应用程序Snapchat 是一款可让您分享带有自毁图片的图片的应用程序。您只能查看图片 X 秒。如果您在图片显示时尝试使用 Home-Power 组合键截屏,它会告诉发件人您尝试截屏。

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

【问题讨论】:

  • stackoverflow.com/questions/2121970/…,看起来它曾经调用 -applicationDidEnterBackground: 之前截取屏幕截图。现在还不确定。
  • 伙计们。另一个线程有答案:stackoverflow.com/questions/2121970/…
  • 也检查一下,stackoverflow.com/a/8711894/1730272,它说不可能了。也许您可以尝试一下并告诉我们。
  • 尚未在 Internet 上的任何地方看到此内容,但我认为如果您使用 Xcode 截取屏幕截图(从 Organizer 窗口中的设备),该应用程序绝对不会能够知道。在查看收到的 Snapchat 照片时,它必须监视相机胶卷中添加的任何照片,并且通过 Xcode 截取屏幕截图完全绕过了这一点(无需越狱)。
  • 跟进: 测试了这个理论,确认应用没有检测到 Xcode 截图。然而,我意识到有趣的是,在 iOS 6 上,必须明确授予应用程序访问照片的权限……但是这个应用程序仍然会检测屏幕截图而不允许它访问照片!它必须使用另一种检测方法——我注意到当使用 Home+Sleep 按钮方法时,活动照片也会从屏幕上移除。所以一定有一些与这个屏幕截图过程相关的模式,应用可以可靠地监控,也许使用 GestureRecognizer?

标签: ios screenshot


【解决方案1】:

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

这将有效地彻底破坏 Snapchat,因此在新解决方案中添加了几个测试版。现在,解决方案就像使用 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
}

【讨论】:

  • 使用这个和touchesCancelled:withEvent: 应该可以让你在所有(最近的)iOS 版本上检测到屏幕截图。
  • 这不能防止截屏。它只能让应用程序知道已被截取。来自 UIApplication 类参考: UIApplicationUserDidTakeScreenshotNotification 当用户按下 Home 和 Lock 按钮截屏时发布。此通知不包含 userInfo 字典。此通知在截取屏幕截图后发布。
  • @badweasel 正确。考虑到此通知遵循传统的 Cocoa 命名约定,“Did”一词意味着它是在事后发布的。在这种情况下没有“Will”等价物,AFAIK 无法阻止用户使用公共 API 截屏。
  • 请注意,我给了你一个 +1。我最初误读了 OP 问题,并认为问题是如何检测它以防止某些事情发生——因为这就是我想要的。所以我只是在评论中添加了澄清,因为我希望很多人来这个问题都在寻找那个答案。我也从“did”这个词中假设了这一点,但文档使它更加清晰。在我的应用程序中,我允许人们编辑照片,但有些工具需要 IAP。但我让他们在购买前尝试。所以我想在它被捕获之前检测到添加水印。做不到。
  • @MickMacCallum 你在主队列上做这件事有什么具体原因吗?
【解决方案2】:

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

【讨论】:

  • iOS 7 不再适用。请参阅below 了解 iOS7+ 解决方案。
  • 乔说的是对的。提问者应取消选中此作为正确答案。
  • UIApplication​User​Did​Take​Screenshot​可以使用通知.. iOS 7+
【解决方案3】:

以下是如何在 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 你在主队列上做这件事有什么具体原因吗?
  • 复制粘贴的原因
【解决方案4】:

Swift 4+

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

通过使用这个观察者你可以知道用户什么时候截屏,但是你不能阻止他。

【讨论】:

    【解决方案5】:

    最新的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 你在哪里看到这个问题是询问如何收到通知?我只是改进了我上面的答案,不确定你的评论意图..
    • 问题问:“检测到用户正在截屏”。如果 OP 想在事后知道,问题应该是:“检测到用户截取了屏幕截图”
    【解决方案6】:

    看起来没有直接的方法来检测用户是否点击了home + power button。根据this,之前可以使用 darwin 通知,但它不再起作用。由于 snapchat 已经这样做了,我的猜测是他们正在检查 iPhone 相册以检测在这 10 秒之间是否添加了新图片,并且在某种程度上他们正在与显示的当前图像进行比较。可能会为此比较进行一些图像处理。只是一个想法,也许你可以尝试扩展它以使其工作。检查this for more details

    编辑:

    看起来他们可能正在检测 UITouch 取消事件(屏幕捕获取消触摸)并根据此博客向用户显示此错误消息:How to detect screenshots on iOS (like 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
    }
    

    【讨论】:

    • 您似乎在正确的地方建立了良好的联系以获得关于此的明确答案;)
    • 这更像是一个有根据的猜测,而不是一个确定的答案。不幸的是,我没有任何联系可以得到确切的答案。如果他们不使用任何私有 API,这是我能想到的唯一方法。检测添加到相册的图像,并根据某种算法将该图像与屏幕中的当前图像进行比较。
    • 但是考虑到他们可以在不请求访问设备照片和相机胶卷的情况下做到这一点......它一定是别的东西不是吗?我的理论与他们让您长按收到的照片消息以查看它的事实有关,并且当您按下Home + Lock 按钮时,操作系统会立即表现得好像没有手指在触摸屏幕一样。可能在没有touchesEnded:withEvent(或类似的回调)的情况下发生这种情况,因为它通常会这样,所以也许他们可以监视这种独特的事件模式?我可能完全走错了路,但这是我目前唯一的理论。
    • 将手指放在屏幕上,不要抬起,试试看能不能按另外两个按钮。我猜它仍然显示该消息。因此,他们可能正在使用一些私有 API,并以某种方式设法放入应用商店。
    • 从 iOS 7 起不再可能。
    【解决方案7】:

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

    【讨论】:

      猜你喜欢
      • 2015-06-14
      • 1970-01-01
      • 2018-08-29
      • 1970-01-01
      • 1970-01-01
      • 2023-03-11
      • 2015-06-19
      • 2014-10-16
      相关资源
      最近更新 更多