screenshot_shield 0.1.5 copy "screenshot_shield: ^0.1.5" to clipboard
screenshot_shield: ^0.1.5 copied to clipboard

Detect user screenshots and optionally prevent screen capture on Android and iOS.

example/lib/main.dart

import 'dart:async';
import 'dart:typed_data';

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

final RouteObserver<ModalRoute<void>> routeObserver =
    RouteObserver<ModalRoute<void>>();

void main() {
  runApp(
    ScreenshotShieldScope(
      shield: ScreenshotShield(),
      routeObserver: routeObserver,
      child: const MaterialApp(
        title: 'Screenshot Shield Demo',
        home: HomeScreen(),
      ),
    ),
  );
}

class HomeScreen extends StatefulWidget {
  const HomeScreen({super.key});

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final ScreenshotShield shield = ScreenshotShield();
  StreamSubscription<bool>? screenRecordingSubscription;
  bool preventCapture = true;
  bool detectScreenshots = true;
  bool backgroundBlur = false;
  DateTime? lastDetected;
  Uint8List? lastImage;
  bool isScreenRecording = false;
  bool hasScreenRecordingState = false;

  @override
  void initState() {
    super.initState();
    screenRecordingSubscription = shield.onScreenRecordingChanged.listen((
      value,
    ) {
      if (!mounted) {
        return;
      }
      setState(() {
        isScreenRecording = value;
        hasScreenRecordingState = true;
      });
    });
  }

  @override
  void dispose() {
    screenRecordingSubscription?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ScreenshotShieldRouteGuard(
      preventCapture: preventCapture,
      detectScreenshots: detectScreenshots,
      captureOnScreenshot: true,
      onScreenshotDetected: (image) {
        setState(() {
          lastDetected = DateTime.now();
          lastImage = image;
        });
      },
      child: Scaffold(
        appBar: AppBar(title: const Text('Screenshot Shield Demo')),
        body: ListView(
          padding: const EdgeInsets.all(16),
          children: [
            const _SectionLabel('Guarded content'),
            Container(
              height: 180,
              alignment: Alignment.center,
              decoration: BoxDecoration(
                color: Colors.indigo,
                borderRadius: BorderRadius.circular(12),
              ),
              child: const Text(
                'This screen is protected.\nTry taking a screenshot.',
                textAlign: TextAlign.center,
                style: TextStyle(color: Colors.white, fontSize: 16),
              ),
            ),
            const SizedBox(height: 16),
            SwitchListTile(
              title: const Text('Prevent capture'),
              subtitle: const Text(
                'Blanks the captured frame (Android and iOS)',
              ),
              value: preventCapture,
              onChanged: (value) => setState(() => preventCapture = value),
            ),
            SwitchListTile(
              title: const Text('Detect screenshots'),
              subtitle: const Text('Report onScreenshotDetected events'),
              value: detectScreenshots,
              onChanged: (value) => setState(() => detectScreenshots = value),
            ),
            SwitchListTile(
              title: const Text('Background blur'),
              subtitle: const Text('Blur the app in the app switcher'),
              value: backgroundBlur,
              onChanged: (value) async {
                setState(() => backgroundBlur = value);
                await shield.setProtection(backgroundBlur: value);
              },
            ),
            const SizedBox(height: 16),
            const _SectionLabel('Detection'),
            Card(
              child: Padding(
                padding: const EdgeInsets.all(12),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      lastDetected == null
                          ? 'No screenshot detected yet.'
                          : 'Detected at ${lastDetected!.toLocal()}',
                    ),
                    if (lastImage != null) ...[
                      const SizedBox(height: 8),
                      Image.memory(
                        lastImage!,
                        height: 160,
                        fit: BoxFit.contain,
                      ),
                    ],
                  ],
                ),
              ),
            ),
            const SizedBox(height: 16),
            const _SectionLabel('Screen recording'),
            Card(
              child: ListTile(
                leading: Icon(
                  isScreenRecording
                      ? Icons.fiber_manual_record
                      : Icons.videocam_off_outlined,
                  color: isScreenRecording ? Colors.red : null,
                ),
                title: Text(
                  !hasScreenRecordingState
                      ? 'Waiting for a platform event...'
                      : isScreenRecording
                      ? 'The screen is being recorded'
                      : 'The screen is not being recorded',
                ),
                subtitle: const Text(
                  'Android 15+, iOS; best-effort on Windows and Linux',
                ),
              ),
            ),
            const SizedBox(height: 16),
            FilledButton.tonal(
              onPressed: () => Navigator.of(context).push(
                MaterialPageRoute<void>(builder: (_) => const SecondScreen()),
              ),
              child: const Text('Open second screen (unprotect)'),
            ),
          ],
        ),
      ),
    );
  }
}

class _SectionLabel extends StatelessWidget {
  const _SectionLabel(this.text);

  final String text;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 8),
      child: Text(text, style: Theme.of(context).textTheme.titleMedium),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Second screen')),
      body: const Center(
        child: Text('This route is not guarded. Protection is released here.'),
      ),
    );
  }
}
2
likes
0
points
655
downloads

Publisher

unverified uploader

Weekly Downloads

Detect user screenshots and optionally prevent screen capture on Android and iOS.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, meta, plugin_platform_interface

More

Packages that depend on screenshot_shield

Packages that implement screenshot_shield