PHPackages                             codingwithrk/no-screenshot - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Security](/categories/security)
4. /
5. codingwithrk/no-screenshot

ActiveNativephp-plugin[Security](/categories/security)

codingwithrk/no-screenshot
==========================

A NativePHP Mobile plugin that prevents screenshots, blocks screen recording and global protection in App-switch state in your mobile app.

v1.1.0(2w ago)2877[1 issues](https://github.com/codingwithrk/no-screenshot/issues)MITPHPPHP ^8.2

Since Mar 2Pushed 1mo agoCompare

[ Source](https://github.com/codingwithrk/no-screenshot)[ Packagist](https://packagist.org/packages/codingwithrk/no-screenshot)[ RSS](/packages/codingwithrk-no-screenshot/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (2)Dependencies (6)Versions (4)Used By (0)

NoScreenshot plugin for NativePHP Mobile
========================================

[](#noscreenshot-plugin-for-nativephp-mobile)

[![Latest Version](https://camo.githubusercontent.com/80a664f771b14b06f11767b0515451fe642d020f8013134876ab255c2863f0dc/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f636f64696e6777697468726b2f6e6f2d73637265656e73686f743f7374796c653d706c6173746963)](https://packagist.org/packages/codingwithrk/no-screenshot)[![Packagist Downloads](https://camo.githubusercontent.com/24af2a4a33abea3efe1bec8acd221a641765008903a0a859e2de411c05627dfa/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f636f64696e6777697468726b2f6e6f2d73637265656e73686f743f7374796c653d706c6173746963)](https://camo.githubusercontent.com/24af2a4a33abea3efe1bec8acd221a641765008903a0a859e2de411c05627dfa/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f636f64696e6777697468726b2f6e6f2d73637265656e73686f743f7374796c653d706c6173746963)[![License](https://camo.githubusercontent.com/5942a9bbdcb1e4e094aa0711ad8f3174dc131a9721af8477c97b055425bff4ed/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f636f64696e6777697468726b2f6e6f2d73637265656e73686f743f7374796c653d706c6173746963)](https://camo.githubusercontent.com/5942a9bbdcb1e4e094aa0711ad8f3174dc131a9721af8477c97b055425bff4ed/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f636f64696e6777697468726b2f6e6f2d73637265656e73686f743f7374796c653d706c6173746963)

A NativePHP Mobile plugin that prevents screenshots, blocks screen recording, and protects the App Switcher thumbnail — on both Android and iOS.

Mainly useful for apps that handle sensitive data such as **financial**, **healthcare**, or **enterprise** applications where protecting user privacy and data security is paramount.

---

Platform Support
----------------

[](#platform-support)

FeatureAndroidiOSBlock screenshots✅ `FLAG_SECURE`✅ UITextField secure layerBlock screen recording✅ `FLAG_SECURE`✅ Black overlayApp Switcher thumbnail protection✅✅Detect live recording—✅ `UIScreen.isCaptured`Detect screenshot events✅ API 34+✅ All versionsPersist protection across restarts✅✅### How It Works

[](#how-it-works)

**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, and third-party capture apps all receive a blank frame. The flag also prevents the App Switcher / Recents thumbnail from showing real content.

A `ContentProvider` (`NoScreenshotInitProvider`) registers `Application.ActivityLifecycleCallbacks` before any Activity is created. On every `Activity.onCreate()` it reads the persisted protection state from `SharedPreferences` and re-applies `FLAG_SECURE` — so the flag is active from the very first frame, even before the WebView or any PHP controller has run.

**iOS** uses two complementary techniques:

1. **UITextField `isSecureTextEntry` screenshot prevention** — when protection is active, all main-window content is moved inside the first subview of a `UITextField` with `isSecureTextEntry = true`. iOS routes that subtree through its system DRM compositing path, which is excluded from the screenshot pipeline. The protected area appears **blank/white** in any screenshot taken while protection is active.
2. **Overlay windows** — a full-screen black `UIWindow` (above the status bar) is shown:

    - When `UIScreen.main.isCaptured` is `true` (screen recording / AirPlay mirroring active)
    - When `UIApplication.willResignActiveNotification` fires (user pressed Home — prevents the OS from capturing a real frame for the App Switcher thumbnail)

Protection state is persisted in `UserDefaults`. The plugin exports a `NativePHPNoScreenshotInit` function (registered as `init_function` in the manifest) that restores the saved state at app startup, re-arming all observers before the first bridge call.

---

Requirements
------------

[](#requirements)

MinimumPHP8.2NativePHP Mobile3.xAndroidAPI 21 (Android 5.0 Lollipop)iOS13.0> `FLAG_SECURE` is available from Android API 1. API 21 is set to match NativePHP Mobile's own minimum. The iOS 13 minimum is required because the recording overlay uses `UIWindowScene`, introduced in iOS 13.

---

Installation
------------

[](#installation)

```
composer require codingwithrk/no-screenshot

php artisan native:plugin:register codingwithrk/no-screenshot
```

The service provider and `NoScreenshot` facade are auto-discovered by Laravel — no manual registration needed.

---

Quick Start
-----------

[](#quick-start)

```
use Codingwithrk\NoScreenshot\Facades\NoScreenshot;

// Protect the entire app (persisted across restarts)
NoScreenshot::disableGlobally();

// Lift global protection
NoScreenshot::enableGlobally();
```

Call `disableGlobally()` once — from a service provider, middleware, or any controller. The choice is saved to `SharedPreferences` (Android) / `UserDefaults` (iOS) and automatically restored the next time the app launches.

---

PHP API
-------

[](#php-api)

All methods are available via the `NoScreenshot` facade or by resolving `Codingwithrk\NoScreenshot\NoScreenshot` from the container.

### `disableGlobally(): bool`

[](#disableglobally-bool)

Activates protection for the entire app and persists the state so it survives app restarts.

- **Android** — adds `FLAG_SECURE` to the activity window; all capture attempts receive a blank frame. On the next launch, `FLAG_SECURE` is applied at `Activity.onCreate()` before the WebView loads.
- **iOS** — moves window content into the `UITextField` secure container (screenshot content appears blank), starts the `UIScreen.capturedDidChangeNotification` observer, and registers `willResignActiveNotification` to protect the App Switcher thumbnail.

Returns `true` on success, `false` if running outside NativePHP.

```
NoScreenshot::disableGlobally();
```

---

### `enableGlobally(): bool`

[](#enableglobally-bool)

Removes global protection and clears the persisted state.

```
NoScreenshot::enableGlobally();
```

---

### `toggle(): bool`

[](#toggle-bool)

Toggles global protection on/off. Returns the new `isGloballyProtected` state.

```
$isNowProtected = NoScreenshot::toggle();
```

---

### `getStatus(): ?ScreenProtectionStatus`

[](#getstatus-screenprotectionstatus)

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 running
```

---

### `startScreenshotDetection(): bool`

[](#startscreenshotdetection-bool)

Registers a native observer that fires `ScreenshotAttempted` whenever the user takes a screenshot.

- **Android** — uses `Activity.registerScreenCaptureCallback()` (API 34+). On older devices the call succeeds but `supported` is `false` and no events fire.
- **iOS** — uses `UIApplication.userDidTakeScreenshotNotification` (all iOS versions).

```
NoScreenshot::startScreenshotDetection();
```

---

### `stopScreenshotDetection(): bool`

[](#stopscreenshotdetection-bool)

Unregisters the screenshot observer.

```
NoScreenshot::stopScreenshotDetection();
```

---

Events
------

[](#events)

Three events cover the full lifecycle of capture activity. Listen to them in Livewire components with the `native:` prefix.

EventDispatched when`ScreenshotAttempted`A screenshot was taken (iOS: all versions; Android: API 34+)`ScreenRecordingStarted``isScreenBeingRecorded` transitions `false → true` (iOS)`ScreenRecordingStopped``isScreenBeingRecorded` transitions `true → false` (iOS)> **Android note:** `FLAG_SECURE` prevents capture at the OS level rather than detecting it. `ScreenshotAttempted` requires API 34+ and `startScreenshotDetection()` to be called first. `ScreenRecordingStarted` / `ScreenRecordingStopped` are iOS-only.

### Listening in a Livewire component

[](#listening-in-a-livewire-component)

```
use Livewire\Attributes\On;
use Livewire\Component;
use Codingwithrk\NoScreenshot\Facades\NoScreenshot;

class SecureScreen extends Component
{
    #[On('native:Codingwithrk\NoScreenshot\Events\ScreenshotAttempted')]
    public function onScreenshotAttempted(): void
    {
        logger()->warning('Screenshot attempted');
    }

    #[On('native:Codingwithrk\NoScreenshot\Events\ScreenRecordingStarted')]
    public function onRecordingStarted(): void
    {
        // Recording / mirroring is now active — overlay is already shown by the plugin.
        // Use this hook for your own app logic (e.g. pause playback).
    }

    #[On('native:Codingwithrk\NoScreenshot\Events\ScreenRecordingStopped')]
    public function onRecordingStopped(): void
    {
        // Recording stopped — overlay is hidden automatically.
    }
}
```

### Manual dispatch (polling pattern)

[](#manual-dispatch-polling-pattern)

```
use Codingwithrk\NoScreenshot\Facades\NoScreenshot;
use Codingwithrk\NoScreenshot\Events\ScreenRecordingStarted;
use Codingwithrk\NoScreenshot\Events\ScreenRecordingStopped;

$status = NoScreenshot::getStatus();

match (true) {
    $status->isScreenBeingRecorded => ScreenRecordingStarted::dispatch(),
    default                        => ScreenRecordingStopped::dispatch(),
};
```

---

ScreenProtectionStatus Reference
--------------------------------

[](#screenprotectionstatus-reference)

PropertyTypeAndroidiOS`isGloballyProtected``bool`✅✅`isScreenBeingRecorded``bool`Always `false`Live `UIScreen.main.isCaptured``isScreenshotDetectionActive``bool`API 34+ only✅ All versions---

Platform Notes
--------------

[](#platform-notes)

### Android

[](#android)

- **Startup protection** — `NoScreenshotInitProvider` (a `ContentProvider`) runs before `MainActivity.onCreate()`. It reads `SharedPreferences` and registers `ActivityLifecycleCallbacks`. On every `Activity.onCreate()` and `onResume()`, `FLAG_SECURE` is re-applied if protection is active. This means the App Switcher thumbnail is always black on cold launches — not just after the first bridge call.
- **Scope** — `FLAG_SECURE` covers the entire activity window. All capture methods (screenshot button, built-in recorder, ADB, third-party apps, Recents thumbnail) receive a blank frame.
- **Screenshot detection** — `registerScreenCaptureCallback()` requires API 34 (Android 14+). On earlier devices `startScreenshotDetection()` returns `supported: false` and `ScreenshotAttempted` never fires.

### iOS

[](#ios)

- **Screenshot content prevention** — when protection is active, the main window's subviews are moved inside a `UITextField` with `isSecureTextEntry = true`. iOS's secure compositing path excludes this subtree from screenshot capture — the screenshot shows blank/white instead of real content. If Apple changes the internal `UITextField` structure in a future OS release, the plugin falls back gracefully to overlay-only protection.
- **App Switcher protection** — `willResignActiveNotification` fires before the OS captures the Recents thumbnail. The plugin shows the black overlay at that moment and hides it again on `didBecomeActiveNotification`.
- **Screen recording overlay** — `UIScreen.main.isCaptured` is `true` during screen recording and AirPlay mirroring. The black `UIWindow` overlay (level `statusBar + 1`) appears immediately when either starts and disappears when both stop.
- **Startup restoration** — `NativePHPNoScreenshotInit` (the `init_function`) reads `UserDefaults` at app launch and calls `apply()` if protection was previously enabled. The `didBecomeActiveNotification` observer retries `applyScreenshotPrevention()` if the window was not yet ready at init time.
- **iOS 13 minimum** — required for `UIWindowScene` used by the overlay window.

---

Testing
-------

[](#testing)

### Unit tests

[](#unit-tests)

```
cd packages/codingwithrk/no-screenshot
./vendor/bin/pest
```

### Device scenarios

[](#device-scenarios)

\#ScenarioStepsExpected1**App Switcher** (Android &amp; iOS)Enable protection → press Home → open RecentsThumbnail is black2**Screenshot content** (iOS)Enable protection → take screenshot (Vol Up + Side) → open PhotosScreenshot is blank/white3**Screenshot event** (Android 14+ &amp; iOS)`startScreenshotDetection()` → take screenshot`ScreenshotAttempted` fires in Livewire4**Restart persistence** (Android &amp; iOS)Enable protection → force-kill app → reopenProtection active before any PHP call; App Switcher thumbnail already black---

Changelog
---------

[](#changelog)

### 1.1.0

[](#110)

- **Android fix** — `FLAG_SECURE` is now applied at `Activity.onCreate()` via `NoScreenshotInitProvider` (a `ContentProvider`), fixing the App Switcher thumbnail leak that occurred before the first bridge call ([\#1](https://github.com/codingwithrk/no-screenshot/issues/1))
- **Android** — protection state persisted to `SharedPreferences`; restored automatically on cold launch
- **iOS** — added `UITextField isSecureTextEntry` screenshot prevention; screenshot content now appears blank instead of showing real app content
- **iOS** — added `willResignActiveNotification` observer to protect the App Switcher thumbnail
- **iOS** — added `NativePHPNoScreenshotInit` (`init_function`) to restore persisted protection state at app startup
- **iOS** — protection state persisted to `UserDefaults`

### 1.0.0

[](#100)

- Initial release

---

Support
-------

[](#support)

For questions or issues, email

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE) for more information.

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance83

Actively maintained with recent releases

Popularity22

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~77 days

Total

3

Last Release

15d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/107883290?v=4)[CodingwithRK](/maintainers/CodingwithRK)[@codingwithrk](https://github.com/codingwithrk)

---

Top Contributors

[![codingwithrk](https://avatars.githubusercontent.com/u/107883290?v=4)](https://github.com/codingwithrk "codingwithrk (6 commits)")

---

Tags

nativephpnativephp-mobilenativephp-plugin

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/codingwithrk-no-screenshot/health.svg)

```
[![Health](https://phpackages.com/badges/codingwithrk-no-screenshot/health.svg)](https://phpackages.com/packages/codingwithrk-no-screenshot)
```

###  Alternatives

[paragonie/ecc

PHP Elliptic Curve Cryptography library

25866.3k44](/packages/paragonie-ecc)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
