A NativePHP Mobile plugin that prevents screenshots, blocks screen recording and global protection in App-switch state in your mobile app.
Mainly useful for apps that handle sensitive data, such as financial, healthcare, or enterprise applications, where protecting user privacy and data security is paramount.
| Feature | Android | iOS |
|---|---|---|
| Block screenshots | ✅ | |
| Block screen recording | ✅ | ✅ Black overlay |
| Detect live recording | — | ✅ |
| Global protection | ✅ | ✅ |
Android uses WindowManager.LayoutParams.FLAG_SECURE — an OS-level window flag that prevents the system from capturing the screen by any means: the screenshot button, the built-in screen recorder, ADB shell, and third-party capture apps all receive a blank or blocked frame.
iOS cannot prevent the system screenshot gesture at the application level. Instead the plugin:
- Observes
UIScreen.capturedDidChangeNotification - When recording starts and protection is active, immediately overlays a full-screen black
UIWindow(above the status bar) that hides all WebView content - Reports
isScreenBeingRecordedin real time viaUIScreen.main.isCaptured
| Minimum | |
|---|---|
| PHP | 8.2 |
| NativePHP Mobile | 3.x |
| Android | API 21 (Android 5.0 Lollipop) |
| iOS | 13.0 |
FLAG_SECUREis available from Android API 1. API 21 is the minimum set to match NativePHP Mobile's own requirements. The iOS 13 minimum is required because the recording overlay usesUIWindowScene, introduced in iOS 13.
composer require codingwithrk/no-screenshotThe service provider and NoScreenshot facade alias are auto-discovered by Laravel — no manual registration needed.
use Codingwithrk\NoScreenshot\Facades\NoScreenshot;
// Protect the entire app
NoScreenshot::disableGlobally();
// Lift global protection
NoScreenshot::enableGlobally();All methods are available via the NoScreenshot facade or by resolving Codingwithrk\NoScreenshot\NoScreenshot from the container.
Activates protection for the entire app.
- Android — adds
FLAG_SECUREto the activity window; all capture attempts receive a blank frame. - iOS — registers the
UIScreen.capturedDidChangeNotificationobserver; if recording is already in progress, the black overlay appears immediately.
Returns true on success, false if running outside NativePHP.
NoScreenshot::disableGlobally();Removes global protection.
NoScreenshot::enableGlobally();Toggles global protection on/off. Returns the new isGloballyProtected state.
$isNowProtected = NoScreenshot::toggle();Returns the current protection state as a typed DTO, or null outside NativePHP.
$status = NoScreenshot::getStatus();
$status->isGloballyProtected; // bool — true after disableGlobally()
$status->isScreenBeingRecorded; // bool — iOS: live UIScreen.main.isCaptured; Android: always false
$status->isScreenshotDetectionActive; // bool — true when screenshot detection is runningThree events cover the full lifecycle of capture activity. Subscribe to them in your Livewire components or event listeners.
| Event | Dispatched when |
|---|---|
ScreenshotAttempted |
A screenshot was taken (detected, cannot be blocked on iOS) |
ScreenRecordingStarted |
isScreenBeingRecorded transitions false → true |
ScreenRecordingStopped |
isScreenBeingRecorded transitions true → false |
Android note:
FLAG_SECUREprevents capture rather than detecting it, so events are not dispatched automatically. Dispatch them manually from your polling logic if needed.
use Native\Mobile\Attributes\OnNative;
use Codingwithrk\NoScreenshot\Events\ScreenshotAttempted;
use Codingwithrk\NoScreenshot\Events\ScreenRecordingStarted;
use Codingwithrk\NoScreenshot\Events\ScreenRecordingStopped;
class MyLivewireComponent extends Component
{
#[OnNative(ScreenshotAttempted::class)]
public function onScreenshotAttempted(): void
{
// Log the attempt, notify the user, etc.
logger()->warning('Screenshot attempted');
}
#[OnNative(ScreenRecordingStarted::class)]
public function onRecordingStarted(): void
{
$this->dispatch('recording-started'); // trigger frontend update
}
#[OnNative(ScreenRecordingStopped::class)]
public function onRecordingStopped(): void
{
$this->dispatch('recording-stopped');
}
}use Codingwithrk\NoScreenshot\Facades\NoScreenshot;
use Codingwithrk\NoScreenshot\Events\ScreenRecordingStarted;
use Codingwithrk\NoScreenshot\Events\ScreenRecordingStopped;
use Codingwithrk\NoScreenshot\Events\ScreenshotAttempted;
// In a controller action polled by the frontend:
$status = NoScreenshot::getStatus();
match (true) {
$status->isScreenBeingRecorded => ScreenRecordingStarted::dispatch(),
default => ScreenRecordingStopped::dispatch(),
};
ScreenshotAttempted::dispatch();| Property | Type | Android | iOS |
|---|---|---|---|
isGloballyProtected |
bool |
✅ | ✅ |
isScreenBeingRecorded |
bool |
Always false |
Live UIScreen.main.isCaptured |
isScreenshotDetectionActive |
bool |
API 34+ only | ✅ All versions |
FLAG_SECUREhas been available since API 1, but NativePHP Mobile itself targets API 21+.- The flag covers the entire activity window — all capture attempts (screenshot button, built-in recorder, ADB, third-party apps) receive a blank frame.
- The flag also hides the app thumbnail in the Recents / App Switcher.
- Screenshot detection via
registerScreenCaptureCallbackrequires API 34+. On older devices,startScreenshotDetection()returnssupported: falseand no events fire.
- iOS 13 is the minimum because the recording overlay uses
UIWindowScene, which was introduced in iOS 13. UIScreen.main.isCaptured(available iOS 11+) istrueduring screen recording and AirPlay mirroring — the overlay appears in both cases.- Screenshots cannot be prevented at the application level. The image is saved to Photos before the notification fires. The plugin can detect attempts via
UIApplication.userDidTakeScreenshotNotificationand dispatchScreenshotAttempted, but the file is already saved by then. - The black overlay is a
UIWindowatUIWindow.Level.statusBar + 1, placed above all app content including the NativePHP WebView.
# Install in your NativePHP app (uses path repository)
composer require codingwithrk/no-screenshot
# Run on Android
php artisan native:run android
# Run on iOS
php artisan native:run iosThen trigger NoScreenshot::disableGlobally() from a controller or Livewire component and:
Android — press the screenshot button. The OS shows "Can't take screenshot due to security policy."
iOS — start a screen recording from Control Center. The black overlay should appear immediately and disappear when recording stops.
For questions or issues, email connect@codingwithrk.com
The MIT License (MIT). Please see License File for more information.