iOS11の新機能の一つにScreen Recordingというものがあります。
とても素敵な機能で、コントロールセンターにあるボタンを押すだけで簡単に画面の録画ができるようになりました。(超便利!)
しかしアプリによっては「この画面を録画されると都合が悪い」といったケースもあるでしょう。
そこで、アプリの中で録画の検知をする方法をTipsとしてまとめます。
アプリ内で録画を検知するためのプロパティ
Screen Recordingへ合わせる形で、iOS11からUIScreenに以下のAPIが追加されました。
このプロパティは、**「スクリーンのキャプチャ」**が行われている間はtrueを返します。
UIScreen.main.isCaptured
ここでいう「スクリーンのキャプチャ」にはScreen Recordingも含まれます。
レコードを開始した上でプロパティの値を確認してみるとわかるのですが、確かにレコード中はtrueを返して、やめるとfalseを返します。
注意点として、「含まれます」というのが曲者で、AirPlayやミラーリング中でも同じくtrueを返す仕様となっています。
従って、AirPlayをサポートしている映像サービスだと、AirPlayのケースを取り除かないとならないでしょう。
AVPlayerを使って映像を再生しているケースであれば、以下のAPIを組み合わせることでスクリーンをキャプチャしているがAirPlayではないというのを判定できるかと思います。
Screen Recordingもしくはミラーリング中であるかどうかは上記2つのプロパティを使って判定します。
// player: AVPlayer
UIScreen.main.isCaptured && !player.isExternalPlaybackActive
ミラーリングを検出したければ、UIScreenのmirroredというプロパティが使用できます。
試してみた所、以下のように呼ぶとミラーリング中はUIScreenのオブジェクトが入り、ミラーリングしていなければnilが入りました。
UISCreen.screens.map { $0.mirrored }
ただし、このプロパティを組み合わせても、「ミラーリング中にスクリーンレコーディングを行っている」という状態を検出することはできません。そのため、厳格にいくのであれば、ミラーリングを除くのは難しいでしょう。
追記
iOS11.1以降では、ミラーリング中にスクリーンレコーディングができないよう変更されているのを確認しました。そのため、上記対応をすれば問題ないかもしれません。
アプリ内で録画を検知するためのNotification
前述のプロパティを使い、UIのライフサイクルイベントや通信完了ハンドラなどで検知できるようになりました。
ただしこのままだと不十分です。画面遷移後ににコントロールセンターを開き、録画を開始したときにはどうすればいいでしょうか。寧ろそういうパターンのほうが多いでしょう。
そういった場合でも対応できるよう、Notificationにも新たな通知が追加されました。
リファレンスを見る限り、通知を受け取ってもuserInfoには何も入っていないようです。通知の中で先程のisCapturedを呼んで、判定をしましょう。
また、UIScreenのisCapturedをKVOで監視するという方法でももちろんよいでしょう。
let obserber = NotificationCenter
.default
.addObserver(forName: .UIScreenCapturedDidChange, object: nil, queue: .main) { [weak self] (notif) in
if let player = self?.player, !player.isExternalPlaybackActive, UIScreen.main.isCaptured {
// ここで何とかする
}
}
まとめ
- 画面遷移してデータを取ってきたタイミングで検知したいのであればUIScreenのisCapturedを呼ぶ
- ただし1.のみだとAirPlayやミラーリングも検知してしまうので、AVPlayerのisExternalPlaybackActiveなども適宜組み合わせる
- レコーディング開始のタイミングを検知したければUIScreenCapturedDidChangeNotificationを監視する
上記方法で、Screen Recordingもしくはミラーリング中という状態は取れるようになりました。以上です。
おまけ - 映像のレコーディングをサーバーで防ぐ方法
著作権が絡む映像の場合、HLSで配信するときにFPSを使ってレコーディングそのものを実行させないという方法もあります。かなり遡りますが、このあたりの話については2015年のWWDCで言及されています。