0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Android スクリーンショット検知

Last updated at Posted at 2025-12-22

スクリーンショットを検知したら通知をする

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <!-- これを追加 -->
    <uses-permission android:name="android.permission.DETECT_SCREEN_CAPTURE" />

    <application

MainActivity.kt

package com.example.detectscreencapture

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.example.detectscreencapture.ui.theme.DetectScreenCaptureTheme

class MainActivity : ComponentActivity() {

    private val screenCaptureCallback = ScreenCaptureCallback {
        Log.d("ScreenCapture", "Detect Screen captured")
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            DetectScreenCaptureTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Greeting(
                        name = "Android",
                        modifier = Modifier.padding(innerPadding)
                    )
                }
            }
        }
    }

    override fun onStart() {
        super.onStart()
        registerScreenCaptureCallback(mainExecutor, screenCaptureCallback)
    }

    override fun onStop() {
        super.onStop()
        try {
            unregisterScreenCaptureCallback(screenCaptureCallback)
        } catch (e: IllegalArgumentException) {
            e.printStackTrace()
        }
    }
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(
        text = "Hello $name!",
        modifier = modifier
    )
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    DetectScreenCaptureTheme {
        Greeting("Android")
    }
}

上記2件のコードを組み実行すると次のような結果です
Screenshot_20251222-221243.png
Screenshot_20251222-221246.png

スクリーンショットすると検知・通知されますが画像自体は問題なくスクリーンショットされています。
次にスクリーンショットした画面自体真っ黒にしたい場合は下記コードを組むだけで実現できます。

package com.example.detectscreencapture

import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.example.detectscreencapture.ui.theme.DetectScreenCaptureTheme

class MainActivity : ComponentActivity() {

    private val screenCaptureCallback = ScreenCaptureCallback {
        Log.d("ScreenCapture", "Detect Screen captured")
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        /** ------ ここのコードを追加する ------ */
        window?.setFlags(
            android.view.WindowManager.LayoutParams.FLAG_SECURE,
            android.view.WindowManager.LayoutParams.FLAG_SECURE
        )
        /** ------ ここまで ------ */
        enableEdgeToEdge()
        setContent {
            DetectScreenCaptureTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Greeting(
                        name = "Android",
                        modifier = Modifier.padding(innerPadding)
                    )
                }
            }
        }
    }

    override fun onStart() {
        super.onStart()
        registerScreenCaptureCallback(mainExecutor, screenCaptureCallback)
    }

    override fun onStop() {
        super.onStop()
        try {
            unregisterScreenCaptureCallback(screenCaptureCallback)
        } catch (e: IllegalArgumentException) {
            e.printStackTrace()
        }
    }
}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Box(
        modifier = Modifier
            .fillMaxSize()
            .padding(8.dp),
        contentAlignment = Alignment.Center
    ) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(4.dp),
            verticalArrangement = Arrangement.Top,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text(
                text = "Hello $name!",
                modifier = modifier
            )

            Text(
                text = "スクショ画像は真っ暗です"
            )
        }
    }
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    DetectScreenCaptureTheme {
        Greeting("Android")
    }
}

上記コードを組むと下記のような結果となります
Screenshot_20251222-222845 (1).png
Screenshot_20251222-222701.png

このようにスクリーンショットした画面は真っ黒となります。NetflixやAmazon Prime, マッチングアプリではこのような技術がネイティブアプリにあるのかなと感じました。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?