スクリーンショットのiOS検出?


135

App StoreにあるアプリSnapchatは、写真を自己破壊して共有できるアプリです。写真はX秒間しか表示できません。家庭用電源キーの組み合わせを使用して画像が表示されているときにスクリーンショットを撮ろうとすると、スクリーンショットを撮ろうとしたことが送信者に通知されます。

SDKのどの部分で、ユーザーがスクリーンショットを撮っていることを検出できますか?これが可能であることを知りませんでした。


1
stackoverflow.com/questions/2121970/…、以前のスクリーンショットを撮る前に-applicationDidEnterBackground:を呼び出すために使用されていたようです。今はよくわかりません。
iDev 2012年

みんな。:他のスレッドが答えていstackoverflow.com/questions/2121970/...
ME2

1
これも確認してください。stackoverflow.com/a/8711894/1730272、それはもう不可能であると述べています。おそらくそれを試して、私たちに知らせてください。
iDev

これはインターネットのどこにも言及されていませんが、Xcodeを使用してスクリーンショット([オーガナイザ]ウィンドウのデバイスから)を取得した場合、アプリがそれを知る方法はまったくないと思います。受信したSnapchat写真の表示中に追加された写真についてカメラロールを監視している必要があり、Xcodeを介してスクリーンショットを撮ると、これが完全に回避されます(脱獄する必要はありません)。
smileyborg

フォローアップ:この理論をテストし、アプリがXcodeスクリーンショットを検出しないことを確認しました。ただし、興味深いことに、iOS 6ではアプリに写真へのアクセスを明示的に許可する必要があることに気付きましたが、このアプリは写真へのアクセスを許可せずにスクリーンショットを検出します!検出には別の方法を使用している必要があります。Home+ Sleepボタンの方法を使用すると、アクティブな写真も画面から削除されることに気づきました。したがって、おそらくGestureRecognizerを使用して、アプリが確実に監視できるこのスクリーンショットプロセスに関連するパターンがあるはずです。
smileyborg

回答:


22

答えを見つけた!! スクリーンショットを撮ると、画面上のすべてのタッチが中断されます。これが、snapchatが写真を表示するために長押しする必要がある理由です。リファレンス:http : //tumblr.jeremyjohnstone.com/post/38503925370/how-to-detect-screenshots-on-ios-like-snapchat


15
iOS 7ではもはや当てはまりません。iOS7+ソリューションについては、以下を参照してください。
Joe Masilotti 2014

6
ジョーの言ったことは正しい。アスカーは正しい答えとしてこれのチェックを外すべきです。
ビスケットの神2015年

UIApplication User Did Take Screenshot Notification is used .. iOS 7+
Amit Tandel

353

iOS 7以降、他の答えは当てはまりません。Appleが作成したため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
}

3
これを使用するとtouchesCancelled:withEvent:、iOSのすべての(最近の)バージョンでスクリーンショットを検出できます。
ジョシュアグロス

46
これは、スクリーンショットが撮られるのを防ぐためには機能しません。アプリがそれを取得したことのみを通知できます。この通知にはuserInfo辞書は含まれていません。この通知は、スクリーンショットが撮られた後に投稿されます。
badweasel 2013年

6
@badweasel正解です。この通知が従来のCocoa命名規則に従っていることを考えると、「Did」という言葉は、事実の後に投稿されたことを意味します。この場合、「Will」に相当するものはなく、AFAIKは、ユーザーがパブリックAPIを使用してスクリーンショットを撮るのを防ぐ方法がありません。
Mick MacCallum 2013年

1
+1を付けたことに注意してください。私は元々OPの質問を誤解しており、質問は何かを防ぐためにそれを検出する方法だと思っていました。それが私が探していたものだからです。この質問に来る多くの人がその答えを探していると思うので、コメントに説明を追加しました。「did」という言葉からもそうであると想定しましたが、ドキュメントによりさらに明確になっています。私のアプリでは、写真の編集を許可していますが、一部のツールではIAPが必要です。でも、買う前に試してもらいました。だから私はそれがキャプチャされる前にそれを検出して透かしを追加したかったのです。できません。
badweasel 2013年

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

免責事項:その私のリポジトリ


ねえ、私はこれを試してみましたがうまくいきましたが、コードで何が起こっているのか少し説明できますか?私はSwiftを初めて使用するので、読みにくいです。
2016

これはそれらの1つであり、「機能する場合は、それを台無しにしないでください」という種類のコードです。ここで使用されているフレームワークが非常にまれであることの原因を学ぶ必要はありません。
Esqarrouth、2016

しかし、あなたはその部分を知っていない場合は、スクリーンショットfuncを検出呼び出すときに、その基本的に、どのような今までにあなたが括弧に入れてはアクション機能として送信され、クロージャがどのように機能するかをチェックアウトする必要があります
Esqarrouth

@Esqarrouthメインキューで実行している特定の理由はありますか?
kidsid49

コピーペーストの原因
Esqarrouth 2017

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 2018

1
@rmaddyどこでその質問がどこに通知されるかを尋ねているのを見ましたか?私はあなたのコメントの意図が確かではないので、私より上で答えを改善しました..
Maksim Kniazev 2018

「ユーザーがスクリーンショットを取得していることを検出する」という質問です。OPが事後に知りたい場合は、「ユーザーがスクリーンショットを撮ったことを検出する」という質問を読む必要があります
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
}

あなたはこれについて決定的な答えを得るために適切な場所でうまく繋がっているようです;)
smileyborg

これは、決定的な答えというよりは、知識に基づいた推測です。残念ながら、これに対する正確な答えを得るための接続はありません。彼らがプライベートAPIを使用していない場合は、これが私が考えられる唯一の方法です。アルバムへの画像の追加を検出し、その画像を何らかのアルゴリズムに基づいて画面内の現在の画像と比較します。
iDev

しかし、彼らがデバイスの写真とカメラロールへのアクセスを要求せずにこれを行うことができるとすれば、それは他の何かでなければなりませんか?私の理論は、受信した写真メッセージを長押ししてそれを表示させ、Home + Lockボタンを押すと、OSはすぐに指が画面に触れていないかのように動作するという事実に関連しています。おそらくこれはtouchesEnded:withEvent通常のように(または類似のコールバック)なしで発生するので、おそらくこのユニークなイベントパターンを監視できますか?私は完全に間違った軌道に乗っているかもしれませんが、それは現時点で私の唯一の理論です。
smileyborg

画面に指を置き、持ち上げないで、他の2つのボタンを押すことができるかどうか試してください。それは私が推測するそのメッセージをまだ示していました。それで彼らはいくつかのプライベートAPIを使用していて、どういうわけかアプリストアに置くことができたのかもしれません。
iDev

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

例2とセレクター

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

@objc func screenshotTaken() {
    print("Screenshot taken!")
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.