DEV Community

Cover image for Building a Privacy Shield for Flutter Apps: Screenshots, App Switcher Protection, Biometrics, and Root Detection
Agirîn Mohammadi
Agirîn Mohammadi

Posted on

Building a Privacy Shield for Flutter Apps: Screenshots, App Switcher Protection, Biometrics, and Root Detection

When we talk about mobile app security, we often focus on authentication, APIs, encryption, and backend security.

But there is another important question:

What happens to sensitive information while the app is running on the user's device?

A banking app, password manager, healthcare app, or any application that displays private information may need to protect its content from screenshots, screen recordings, app switcher previews, or unauthorized access after the app returns from the background.

While working with Flutter, I wanted a simple way to combine these protections without adding separate security logic throughout an application.

That is why I built flutter_app_shield.

The idea

The main goal was simple:

Wrap your app with one widget and configure the privacy features you need.

Instead of handling screenshot protection, background blur, authentication, and compromised-device detection separately, the package provides a single wrapper:

AppShield(
  child: MaterialApp(
    home: const HomeScreen(),
  ),
);
Enter fullscreen mode Exit fullscreen mode

From there, each security feature can be enabled or configured independently.

What does flutter_app_shield protect?

The package currently focuses on several areas of mobile privacy and application protection:

  • Screenshot and screen recording prevention
  • Protecting sensitive content in the app switcher
  • Authentication when the app returns from the background
  • Root and jailbreak detection
  • Custom lock screens
  • Configurable authentication attempt limits

The package is built around existing Flutter packages and combines them behind a simpler API.

1. Preventing screenshots and screen recordings

For many applications, allowing sensitive information to be captured can be a privacy concern.

For example:

  • Banking applications
  • Password managers
  • Healthcare apps
  • Internal company applications
  • Apps displaying private documents
  • Applications containing personal information

With flutter_app_shield, screenshot protection can be enabled with a simple option:

AppShield(
  preventScreenshot: true,
  child: const MyApp(),
);
Enter fullscreen mode Exit fullscreen mode

Under the hood, the package uses platform-specific functionality through the no_screenshot package.

This is important because screenshot behavior is platform-dependent. Android and iOS do not provide exactly the same mechanisms, so the implementation relies on the capabilities available on each platform.

2. Protecting content in the app switcher

One privacy issue that is easy to overlook is the app switcher.

When a user leaves an application, the operating system may display a preview of the application's last visible screen.

Imagine that the user was viewing:

  • Account information
  • A private conversation
  • A password
  • A medical record

That content may still be visible in the recent-apps screen.

To reduce this risk, flutter_app_shield can display a blurred overlay when the application moves into the background.

AppShield(
  blurAmount: 25.0,
  opacity: 0.9,
  child: const MyApp(),
);
Enter fullscreen mode Exit fullscreen mode

The blur and opacity are configurable, allowing developers to control how much of the original interface remains visible.

3. Requiring authentication when the app resumes

Another common security pattern is requiring the user to authenticate after the application returns from the background.

For example, imagine this flow:

  1. The user opens a banking app.
  2. The user switches to another application.
  3. Someone else picks up the device.
  4. The user returns to the banking app.

In some cases, immediately showing the previous screen is not ideal.

With AppShield, authentication can be requested when the application needs to be unlocked:

AppShield(
  requireAuthOnResume: true,
  child: const MyApp(),
);
Enter fullscreen mode Exit fullscreen mode

The package uses Flutter's local authentication capabilities, allowing the device's available authentication methods, such as biometrics or PIN/device credentials, to be used.

Authentication failures can also be limited:

AppShield(
  requireAuthOnResume: true,
  maxAuthAttempts: 3,
  maxAttemptsMessage:
      'Too many failed attempts. Please try again later.',
  child: const MyApp(),
);
Enter fullscreen mode Exit fullscreen mode

After reaching the configured limit, the application can show a security error screen. On supported native platforms, developers can also configure the app to exit after too many failed attempts.

4. Root and jailbreak detection

A rooted or jailbroken device can change the security assumptions of an application.

For applications with higher security requirements, developers may want to detect these environments and block access.

This can be enabled with:

AppShield(
  blockOnJailbreak: true,
  child: const MyApp(),
);
Enter fullscreen mode Exit fullscreen mode

If a compromised device is detected, the package can display a default warning screen.

However, the screen is also customizable:

AppShield(
  blockOnJailbreak: true,
  compromisedDeviceBuilder: const Scaffold(
    body: Center(
      child: Text(
        'This app cannot run on a compromised device.',
      ),
    ),
  ),
  child: const MyApp(),
);
Enter fullscreen mode Exit fullscreen mode

This makes it possible to adapt the security experience to the application's own design and requirements.

5. Customizing the lock screen

I did not want the package to force developers to use a specific security UI.

The lock screen can be completely customized using lockedBuilder.

For example:

AppShield(
  requireAuthOnResume: true,
  lockedBuilder: (context, controller) {
    return Center(
      child: ElevatedButton(
        onPressed: () => controller?.unlock(),
        child: const Text('Unlock'),
      ),
    );
  },
  child: const MyApp(),
);
Enter fullscreen mode Exit fullscreen mode

This makes it easier to integrate the package into existing applications without breaking the app's visual identity.

Putting everything together

Here is a more complete example:

import 'package:flutter/material.dart';
import 'package:flutter_app_shield/flutter_app_shield.dart';

void main() {
  runApp(
    AppShield(
      preventScreenshot: true,
      requireAuthOnResume: true,
      blockOnJailbreak: true,
      blurAmount: 25.0,
      opacity: 0.9,
      maxAuthAttempts: 3,
      exitOnMaxAttempts: false,
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Secure App',
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Secure Home'),
        ),
        body: const Center(
          child: Text('Sensitive content is protected.'),
        ),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

The idea is that security features should not require security-related code to be scattered throughout the entire widget tree.

The application can define its protection strategy near the root of the app.

The architecture behind the package

The core of the package is a StatefulWidget called AppShield.

When the widget is initialized, it performs the required security setup.

Conceptually, the flow looks like this:

AppShield
   │
   ├── Screenshot protection
   │
   ├── Root/Jailbreak detection
   │
   ├── Secure application lifecycle handling
   │
   └── Authentication on unlock
          │
          ├── Success → Unlock app
          │
          └── Failure → Count attempts
                        │
                        └── Max attempts → Lock/Error
Enter fullscreen mode Exit fullscreen mode

The package combines several specialized Flutter packages instead of trying to reinvent platform-level security features.

The main dependencies currently handle:

  • Screenshot protection
  • Secure background/application lifecycle behavior
  • Root and jailbreak detection
  • Local authentication

The goal of flutter_app_shield is to provide a unified developer experience on top of these capabilities.

Important: this is not a magic security solution

One thing I think is important to mention when building packages like this:

No client-side Flutter package can guarantee absolute protection of data.

A determined attacker with control over a device may have capabilities beyond what a normal application can prevent.

For example, someone can always potentially use another physical device to photograph the screen.

So flutter_app_shield should be viewed as a defense-in-depth tool.

It can help reduce common privacy risks and make accidental or casual exposure more difficult, but it should not replace:

  • Proper backend authorization
  • Secure API design
  • Encryption where appropriate
  • Secure storage
  • Server-side validation
  • Good authentication and session management

Security works best when multiple layers work together.

Installation

Check out the package on Pub.dev:

flutter_app_shield on Pub.dev

Add the package to your pubspec.yaml:

dependencies:
  flutter_app_shield: ^0.1.5
Enter fullscreen mode Exit fullscreen mode

Then run:

flutter pub get
Enter fullscreen mode Exit fullscreen mode

For iOS biometric authentication, you may also need to add a Face ID usage description to Info.plist.

Testing security features

Some features should be tested on real devices.

For example:

  • Screenshot protection may behave differently across platforms.
  • Root detection should be tested on an actual rooted device or appropriate test environment.
  • Biometric authentication requires device-level configuration.
  • App switcher behavior should be checked on both Android and iOS.

This is especially important for security-related packages because emulator behavior does not always represent real device behavior.

Why I built this package

The main motivation behind this project was developer experience.

Flutter has a great ecosystem, and there are already packages for many individual security features.

But when building an app, developers often need to combine several of them:

  • One package for screenshots
  • Another for app lifecycle protection
  • Another for authentication
  • Another for root detection

I wanted to experiment with bringing these capabilities together behind one simple and customizable widget.

The result is flutter_app_shield.

What's next?

This is still an early version of the package, and there is room to improve it.

Some areas I want to explore include:

  • More platform-specific configuration
  • Better testing coverage
  • Improved security state handling
  • More customization options
  • Additional documentation and examples
  • Community feedback and contributions

If you build Flutter applications that handle sensitive information, I would love to hear what features you think a package like this should support.

Try it out

If you want to try flutter_app_shield in your Flutter project, you can find it here:

📦 Pub.dev

Check out the package, installation instructions, API documentation, and examples on Pub.dev:

flutter_app_shield on Pub.dev

💻 GitHub

You can also explore the source code, report issues, or contribute to the project on GitHub:

flutter_app_shield on GitHub

If you find the package useful, feel free to give the repository a star ⭐ and share your feedback.

Security should not have to mean complicated APIs.

The goal of flutter_app_shield is to make it easier to add multiple privacy and security layers to a Flutter application with a simple and customizable API.

Top comments (0)