device_safety_info (Null-Safety)

A Flutter plugin to detect if a device is jailbroken/rooted, running in an emulator, and to check for other security vulnerabilities like screen capture and hooking frameworks.

Features

  • Jailbreak/Root Detection: Checks if the device is jailbroken (iOS) or rooted (Android).
  • Emulator/Simulator Detection: Determines if the app is running on a simulator/emulator or a real device.
  • App Install Source: Verifies if the app was installed from the App Store (iOS) or Play Store (Android).
  • Screen Lock: Checks if a screen lock (passcode, Touch ID, Face ID) is enabled.
  • External Storage: Detects if the app is running on external storage (Android only).
  • Developer Mode: Checks if Developer Options are enabled (Android only).
  • VPN Status: Monitors the device's VPN connection state.
  • App Version Check: Checks for new versions of the app in the App Store/Play Store.
  • Screen Capture Detection: Detects if the screen is being captured (recorded or mirrored).
  • Screen Capture Prevention: Blocks screenshots and screen recordings.
  • Hook Detection: Detects if the app is being targeted by hooking frameworks like Frida or Cydia Substrate.
  • Hide App in Recents: Programmatically hide or show the app in the recent apps list (Android only).

Platform Support

Feature Android iOS
Jailbreak/Root Detection
Emulator/Simulator Detection
Installed from Store
Screen Lock Enabled
Hooking/Reverse-Engineering
Screen Capture Detection
Screen Capture Prevention
VPN Status Monitoring
App Store Version Check
Exit App on Detection
Developer Mode Enabled
Running on External Storage
Hide App in Recents
Prompt for Uninstall

Getting Started

In your flutter project add the dependency:

dependencies:
  
  device_safety_info: ^1.0.4

Usage

Importing package

import 'package:device_safety_info/device_safety_info.dart';

Using it

Checks whether device is JailBroken (iOS) or Rooted (Android)?

bool isRootedDevice = await DeviceSafetyInfo.isRootedDevice;

Checks whether device is a real device or an Emulator/Simulator

bool isRealDevice = await DeviceSafetyInfo.isRealDevice;

Checks if the app was installed from the App Store or Google Play

bool isInstalledFromStore = await DeviceSafetyInfo.isInstalledFromStore;

Checks whether a screen lock is enabled

bool isScreenLock = await DeviceSafetyInfo.isScreenLock;

Checks if the screen is being captured (recorded or mirrored) This stream will emit true if screen capture is detected.

DeviceSafetyInfo.onScreenCapturedChanged.listen((bool isCaptured) {
  print('Screen is being captured: $isCaptured');
});

// You can also get the current status directly
bool isScreenCaptured = await DeviceSafetyInfo.isScreenCaptured;

Blocks screenshots and screen recordings (Android & iOS) On Android, this uses FLAG_SECURE. On iOS, it overlays a view to hide the content when the screen is captured.

// To block
await DeviceSafetyInfo.blockScreenshots(block: true);

// To unblock
await DeviceSafetyInfo.blockScreenshots(block: false);

Checks for hooking frameworks like Frida or Cydia Substrate (Android & iOS) This helps detect if the app is being reverse-engineered.

// Simple check
bool isHooked = await DeviceSafetyInfo.isHooked;

// Check and exit the app if hooked (works on both platforms)
await DeviceSafetyInfo.checkHooked(exitProcessIfTrue: true);

// Check and prompt for uninstall if hooked (Android only)
await DeviceSafetyInfo.checkHooked(uninstallIfTrue: true);

Hides or shows the app in the recent apps list (Android Only)

// To hide
await DeviceSafetyInfo.hideMenu(hide: true);

// To show
await DeviceSafetyInfo.hideMenu(hide: false);

Checks whether the application is running on external storage (Android Only)

bool isExternalStorage = await DeviceSafetyInfo.isExternalStorage;

Checks whether Developer Options are enabled on the device (Android Only)

bool isDeveloperMode = await DeviceSafetyInfo.isDeveloperMode;

Checks VPN status on device For checking VPN status device must be connected to the internet. For Android, add <uses-permission android:name="android.permission.INTERNET"/> to your AndroidManifest.xml.

final vpnCheck = VPNCheck();

vpnCheck.vpnState.listen((state) {
      if (state == VPNState.CONNECTED) {
        if (kDebugMode) {
          print("VPN connected.");
        }
      } else {
        if (kDebugMode) {
          print("VPN disconnected.");
        }
      }
});

Checks if a new app version is available Requires an internet connection. For Android, add <uses-permission android:name="android.permission.INTERNET"/> to your AndroidManifest.xml.

appVersionStatus() {
    final newVersion = NewVersionChecker(
      iOSId: '', // Your iOS app ID
      androidId: '', // Your Android app ID
    );
    statusCheck(newVersion);
}

statusCheck(NewVersionChecker newVersion) async {
    try {
      final status = await newVersion.getVersionStatus();

      if (status != null) {
        debugPrint(status.appStoreLink);
        debugPrint(status.localVersion);
        debugPrint(status.storeVersion);
        debugPrint(status.canUpdate.toString());

        if (status.canUpdate) {
         // New version available
        }
      }
    } catch (e) {
      if (kDebugMode) {
        print(e.toString());
      }
    }
}