BLOGサブスレッドの日常

2023.02.18

AndroidのFLAG_SECUREを使った画面キャプチャ禁止は強力なので、開発・テスト時は無効にした方がよい話

s.kono

Androidアプリ開発をしていると、個人情報を表示する場面など、ユーザーがアプリのスクリーンショットを撮影することを禁止したい場面が出てきます。

その時、FLAG_SECUREを使えばスクリーンショットの撮影を含む、画面キャプチャ禁止することが可能です。

このFLAG_SECURE、スクリーンショットだけを禁止するものかと思いきや、その他の手段で画面をキャプチャする方法も制限する強力なものだった、開発中やテストする時はビルドフラグで無効にしといたほうが良さそう、という話です。

FLAG_SECURE を使った画面キャプチャ禁止とは

AndroidのActivityに対して、以下のようにFLAG_SECUREをつけると、画面キャプチャができなくなるというものです。FLAG_SECUREはActivityごとに設定出来るので、一つのアプリの中でも特定の画面だけ画面キャプチャを禁止する…といった制御も可能です。例えば漫画アプリで、漫画本編表示はキャプチャ禁止、各話を一覧表示する画面ではキャプチャ許可としているものがありました。

具体的には、以下のようなプログラムをActivityに追加します。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window.setFlags(
            WindowManager.LayoutParams.FLAG_SECURE,
            WindowManager.LayoutParams.FLAG_SECURE
        )
    }

上記のコードを入れた状態でアプリをビルド・端末へアプリインストールし、
対象のActivityを表示した状態で端末のハードウェアボタンを使ってスクリーンショットを撮ると…

上記のように画面が真っ黒になります。
アプリに個人情報を入力する画面などでは、ぜひ有効にしておきたい機能ですね。

ただ、例えばテスターがアプリをテスト中をしている時、テスターが『この画面の表示が想定と違うようです…』といった共有を行いたい時、スクリーンショットが撮れないとなると、何がどうおかしいのかを開発者に伝えるという手段が減るのでテストの効率が悪くなりますね。

ちなみに、上記はAndroid 13で確認した結果です。Android 8.xで確認したところ、スクリーンショットの撮影自体が禁止され、スクリーンショットを画像にすることができませんでした。
(Androidのどのバージョンから挙動が変わったのか、という具体的なバージョンの切り分けまでは行えていません)

他の手段で画面キャプチャを取得してみる

タイトルにある「FLAG_SECUREを使った画面キャプチャ禁止は強力」というのはどういうことなのか…ということですが。
他の手段でスクリーンショットを撮るのとは別の方法で、画面キャプチャを取得できないか試してみます。

adbでキャプチャしてみる

Androidでは、Android SDK付属のadbコマンドを経由してスクリーンキャプチャを撮ることもできます。

adb shell screencap -p /sdcard/screen.png
adb pull /sdcard/screen.png ./capture.png

端末をPCと接続した状態で上記のコマンドを実行し、capture.pngを取得します。
capture.pngを表示しようと思ってmacOSのFinderを開いてみると…

ぜ、0バイト…
画面キャプチャを取得することができませんでした。

もちろん、FLAG_SECUREを設定していない画面を表示してない時(OSの待受画面を表示している時など)にadbでキャプチャしてみると、正常にキャプチャが撮れます。

Android Studioで画面キャプチャしてみる

Android StudioのLogCatメニューから画面キャプチャを取得機能にアクセスすることができます。

通常この機能を使うと、PCと接続している端末に表示されている画面の画面キャプチャを取得ことができます。

FLAG_SECUREを設定したActivityを表示した状態でこれを実行すると…

上記の様な表示が出ます。

Android Studioも内部では「adbでキャプチャしてみる」と同じような方法でキャプチャを撮っていることは容易に想像できるので、adbで撮影できなかった後だと画面キャプチャを取得することができないことも想像できますね。

画面のキャストをしてみる

自宅にはNest Hub (第二世代)があります。
これに自分のスマートフォンの映像をキャストしてみたところ…

真っ黒になります。(デバイスの電源はちゃんとついてます!)
個人的にはこのこと(映像も画面キャプチャを制限している)ことには驚きました。

ちなみに、Android Studioには端末に映っている画面を動画で撮影する機能がありますが、これを使った場合も同様に、FLAG_SECUREを設定したActivityの表示は真っ黒に映ります。
同様に、PC上で画面を写すツールscrcpy を使った時も同様、真っ黒に映りました。

…ということでFLAG_SECUREをつけてる画面のキャプチャを撮るのは原則無理そうです。(root化した端末とかは #知らんけど )

対策

開発やテスト時には、FLAG_SECUREを設定しないようにしましょう。
私の場合は、商用リリース時のみFLAG_SECUREをつける、という方法を採りました。

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (BuildConfig.FLAVOR == "prod") {
            window.setFlags(
                WindowManager.LayoutParams.FLAG_SECURE,
                WindowManager.LayoutParams.FLAG_SECURE
            )
        }
    }

BuildConfig.FLAVORは、プロダクトフレーバーの設定を利用した時にAndroid Studioによって作成されるプロパティです。

私はdevelopとprodというプロダクトフレーバーを設定し、商用ビルドではprodフレーバーを使って商用ビルドしているため、上記のような判定をしています。

まとめ

FLAG_SECUREを設定した画面は、スクリーンショットを撮影した時に画面が真っ黒になることに限らず、様々な方法で画面キャプチャを行う方法に対しても有効である、という話でした。
画面キャプチャを禁止することは、アプリを利用するユーザーにアプリを安心して使ってもらうことにもつながるので、適切に使っていきましょう。

この記事を書いた人

s.kono