Skip to content

Quick start

import 'package:device_shield/device_shield.dart';
Future<void> checkDevice() async {
final report = await DeviceShield.check();
if (report.root.detected || report.jailbreak.detected) {
// e.g. hide sensitive screens or ask for extra verification
}
if (report.anyFailed) {
// Some check couldn't run. Treat the result as incomplete.
}
}

There’s nothing to initialise and nothing throws. check() runs every check and returns a SecurityReport. A check that doesn’t exist on the current platform, such as root on iOS, comes back as CheckStatus.notApplicable.

Every result lists the signals that fired, each with a strength:

final root = await DeviceShield.checkRoot();
switch (root.status) {
case CheckStatus.detected:
print('Rooted: ${root.signals}'); // [su_binary_path (strong)]
case CheckStatus.clear:
print('Clear. Weak signals, if any: ${root.signals}');
case CheckStatus.notApplicable:
print('Not an Android device');
case CheckStatus.failed:
print('Could not check: ${root.error}');
}

A check is detected when at least one strong signal fires, or at least two medium ones. Weak signals, which are common on custom ROMs and debug builds, are reported but never decide the result on their own. See Detection results.

// When the screen opens:
final result = await DeviceShield.setScreenshotProtection(true);
if (result != ProtectionResult.applied) {
// unsupported on this platform, or no window yet
}
// When it closes:
await DeviceShield.setScreenshotProtection(false);

On Android this blocks screenshots and screen recording, and hides the app in Recents. For iOS, see Screenshot protection.

final subscription = DeviceShield.screenshots.listen((_) {
// The user just took a screenshot.
});
// Later: await subscription.cancel();