Skip to content

Flutter plugin to enable, disable or toggle screenshot support in your application.

License

Notifications You must be signed in to change notification settings

FlutterPlaza/no_screenshot

no_screenshot

no_screenshot Pub Star on Github Flutter Website

The Flutter plugin will enable, disable, or toggle screenshot support in your application.

Features

  • Disables screenshot and screen recording on Android and iOS.
  • Enables screenshot and screen recording on Android and iOS.
  • Toggles screenshot and screen recording on Android and iOS.
  • Provides a stream to listen for screenshot activities.

Update

Tracking didChangeAppLifecycleState is no longer required. The state will be persisted automatically in the native platform SharedPreferences.

Getting started

Add no_screenshot to your pubspec.yaml dependencies.

Usage

  • Basic Usage: Enable, disable, and toggle screenshot and screen recording functionalities.
  • Advanced Features: Use stream to listen for screenshot activities and integrate these features into your application.

Screenshots and Recordings

Basic Usage Advanced Usage
basic_usage.mp4
advanced_usage.mp4

Basic Usage

Step 1: Disable Screenshot and Screen Recording

To disable screenshots and screen recording, you first have to import the package, then you can create an instance of the NoScreenshot object, which you can use to turn off screenshot, see code snippet:

import 'package:no_screenshot/no_screenshot.dart';

final _noScreenshot = NoScreenshot.instance;

void disableScreenshot() async {
  bool result = await _noScreenshot.screenshotOff();
  debugPrint('Screenshot Off: $result');
}

Step 2: Enable Screenshot and Screen Recording

To re-enable screenshots and screen recording, use this code:

import 'package:no_screenshot/no_screenshot.dart';

final _noScreenshot = NoScreenshot.instance;

void enableScreenshot() async {
  bool result = await _noScreenshot.screenshotOn();
  debugPrint('Enable Screenshot: $result');
}

Step 3: Toggle Screenshot and Screen Recording

If you just want to toggle the screenshot or screen recording functionality, use this code:

import 'package:no_screenshot/no_screenshot.dart';

final _noScreenshot = NoScreenshot.instance;

void toggleScreenshot() async {
  bool result = await _noScreenshot.toggleScreenshot();
  debugPrint('Toggle Screenshot: $result');
}

Example UI Integration

Here’s an example of how you might integrate these functionalities into your app's UI:

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

void main() {
  runApp(const BasicUsage());
}

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

  @override
  State<BasicUsage> createState() => _BasicUsageState();
}

class _BasicUsageState extends State<BasicUsage> {
  final _noScreenshot = NoScreenshot.instance;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('No Screenshot Basic Usage'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              ElevatedButton(
                onPressed: disableScreenshot,
                child: const Text('Disable Screenshot'),
              ),
              ElevatedButton(
                onPressed: enableScreenshot,
                child: const Text('Enable Screenshot'),
              ),
              ElevatedButton(
                onPressed: toggleScreenshot,
                child: const Text('Toggle Screenshot'),
              ),
              const SizedBox(height: 60),
            ],
          ),
        ),
      ),
    );
  }

  void toggleScreenshot() async {
    bool result = await _noScreenshot.toggleScreenshot();
    debugPrint('Toggle Screenshot: $result');
  }

  void enableScreenshot() async {
    bool result = await _noScreenshot.screenshotOn();
    debugPrint('Enable Screenshot: $result');
  }

  void disableScreenshot() async {
    bool result = await _noScreenshot.screenshotOff();
    debugPrint('Screenshot Off: $result');
  }
}

Part 2: Advanced Features

Step 1: Listen for Screenshot Activities

To listen for screenshot activities, you can set up a stream listener like this:

NOTE: You first have to import the package, then you can create an instance of the NoScreenshot object, which you can use to listen for screenshot events, see code snippet:

import 'package:no_screenshot/no_screenshot.dart';

final _noScreenshot = NoScreenshot.instance;

void listenForScreenshot() {
  _noScreenshot.screenshotStream.listen((value) {
    print('Screenshot taken: ${value.wasScreenshotTaken}');
    print('Screenshot path: ${value.screenshotPath}');
  });
}

Step 2: Enable screenshot listening

By default, listening to screenshot events is turned off. To listen for screenshot activities, you will need to enable or start listening:

import 'package:no_screenshot/no_screenshot.dart';

final _noScreenshot = NoScreenshot.instance;

void startScreenshotListening() async {
  await _noScreenshot.startScreenshotListening();
}

Step 3: Disable/stop screenshot listening

To stop listen for screenshot activities, code below:

import 'package:no_screenshot/no_screenshot.dart';

final _noScreenshot = NoScreenshot.instance;

void stopScreenshotListening() async {
  await _noScreenshot.stopScreenshotListening();
}

Example Integration with Application

Incorporate the screenshot listener into your app's main logic:

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

void main() {
  runApp(const AdvancedUsage());
}

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

  @override
  State<AdvancedUsage> createState() => _AdvancedUsageState();
}

class _AdvancedUsageState extends State<AdvancedUsage> {
  final _noScreenshot = NoScreenshot.instance;
  bool _isListeningToScreenshotSnapshot = false;

  @override
  void initState() {
    super.initState();
    listenForScreenshot();
  }

  void listenForScreenshot() {
    _noScreenshot.screenshotStream.listen((value) {
      if (value.wasScreenshotTaken) showAlert(value.screenshotPath);
    });
  }


  void stopScreenshotListening() async {
    await _noScreenshot.stopScreenshotListening();
    setState(() {
      _isListeningToScreenshotSnapshot = false;
    });
  }

  void startScreenshotListening() async {
    await _noScreenshot.startScreenshotListening();
    setState(() {
      _isListeningToScreenshotSnapshot = true;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Listen for Screenshot Activities'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: startScreenshotListening,
              child: const Text('Start Listening'),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text("Screenshot Listening: $_isListeningToScreenshotSnapshot"),
                _isListeningToScreenshotSnapshot
                    ? Container(
                        height: 20,
                        width: 20,
                        margin: const EdgeInsets.only(left: 20),
                        decoration: BoxDecoration(
                          color: Colors.red,
                          borderRadius: BorderRadius.circular(20),
                        ),
                      )
                    : const SizedBox.shrink()
              ],
            ),
            ElevatedButton(
              onPressed: stopScreenshotListening,
              child: const Text('Stop Listening'),
            ),
            const SizedBox(height: 20),
          ],
        ),
      ),
    );
  }

  void showAlert(String path) {
    showDialog(
      context: context,
      builder: (context) {
        return Dialog(
          child: Container(
            padding: const EdgeInsets.all(20.0),
            height: 280,
            width: MediaQuery.sizeOf(context).width - 60,
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                const Icon(
                  Icons.warning_amber_outlined,
                  size: 80,
                  color: Colors.red,
                ),
                const Text(
                  "Alert: screenshot taken",
                  style: TextStyle(fontSize: 24),
                ),
                Text("Path: $path"),
                const SizedBox(height: 40),
                FilledButton(
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                  child: const Text("confirm"),
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}

Additional information

Check out our repo for Open-Source contributions. Contributions are welcome!