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(),
),
);
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(),
);
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(),
);
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:
- The user opens a banking app.
- The user switches to another application.
- Someone else picks up the device.
- 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(),
);
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(),
);
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(),
);
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(),
);
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(),
);
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.'),
),
),
);
}
}
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
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:
Add the package to your pubspec.yaml:
dependencies:
flutter_app_shield: ^0.1.5
Then run:
flutter pub get
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:
💻 GitHub
You can also explore the source code, report issues, or contribute to the project 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)