Реализация защиты от скриншотов экрана в мобильном приложении
Банковское приложение показывает баланс, номер счёта, детали транзакций — всё это может быть на скриншоте в галерее, прочитано другим приложением или утечь через облачный бэкап. На iOS скриншот автоматически сохраняется в Photos. На Android приложения с нужными разрешениями могут читать MediaStore. Защита от скриншотов — стандартное требование в финтех и медицинских приложениях.
Android: FLAG_SECURE
Одна строка, которая работает:
window.setFlags(WindowManager.LayoutParams.FLAG_SECURE,
WindowManager.LayoutParams.FLAG_SECURE)
FLAG_SECURE делает две вещи: запрещает системным инструментам создавать скриншот окна (кнопка «скриншот» не работает, возвращает пустой экран) и помечает поверхность как защищённую — другие приложения не могут захватить содержимое через MediaProjection.
Лучшее место — onCreate Activity до setContentView. Для Fragment-based приложений на одной Activity — применяется ко всему приложению сразу.
Нюанс: FLAG_SECURE работает для системного API скриншотов. Физическая камера, снимающая экран — не блокируется ничем программно.
iOS: UIScreen и WindowScene
На iOS нет прямого аналога FLAG_SECURE. Стандартный подход — реагировать на скриншот, а не блокировать его.
Обнаружение скриншота:
NotificationCenter.default.addObserver(
forName: UIApplication.userDidTakeScreenshotNotification,
object: nil,
queue: .main
) { _ in
// логировать, показать предупреждение, инвалидировать сессию
}
Перекрытие контента при скриншоте. Скриншот создаётся системой до того, как нотификация придёт в приложение — нельзя заблокировать постфактум. Альтернатива: подписаться на UIScreen.capturedDidChangeNotification (срабатывает когда начинается захват экрана, включая AirPlay зеркалирование и QuickTime) и скрывать чувствительный контент превентивно.
NotificationCenter.default.addObserver(
forName: UIScreen.capturedDidChangeNotification,
object: nil,
queue: .main
) { [weak self] _ in
self?.sensitiveView.isHidden = UIScreen.main.isCaptured
}
Это работает для screen recording и миррoring, но не для нажатия кнопки скриншота — isCaptured не становится true в момент единичного снимка.
Трюк с Keychain и SecureTextField. Для текстовых полей с чувствительными данными — isSecureTextEntry = true. iOS автоматически размывает содержимое такого поля на скриншотах системного приложения Passbook/Notes и в переключателе задач.
Overlay-подход. При уходе в фон (sceneWillResignActive) показываем UIWindow с заглушкой поверх приложения:
func sceneWillResignActive(_ scene: UIScene) {
privacyWindow?.isHidden = false
}
func sceneDidBecomeActive(_ scene: UIScene) {
privacyWindow?.isHidden = true
}
Это защищает превью в переключателе задач — стандартная практика для финтех-приложений.
React Native и Flutter
React Native: react-native-flag-secure-android для Android, кастомный нативный модуль для iOS. Для Flutter — flutter_windowmanager пакет на Android, нативный канал platform channel для iOS overlay.
Срок реализации: Android FLAG_SECURE + iOS overlay при переходе в фон + реакция на capturedDidChangeNotification — около 1 дня с тестированием на обеих платформах.







