safety_net_flutter 1.2.1 copy "safety_net_flutter: ^1.2.1" to clipboard
safety_net_flutter: ^1.2.1 copied to clipboard

Flutter plugin wrapping SafetyNet (iOS) and SafetyNetAndroid for report-only root/jailbreak/tamper/debugger detection on both platforms.

example/lib/main.dart

import 'dart:io' show Platform;

import 'package:flutter/material.dart';

import 'package:safety_net_flutter/safety_net_flutter.dart';

// Replace with your own Google Cloud project number (linked to your Play
// Console app) and a real per-action request hash — see
// https://developer.android.com/google/play/integrity/setup.
const int _kCloudProjectNumber = 0;
const String _kRequestHash = 'example-request-hash';

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

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

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  SafetyNetCheckResult? _result;
  String? _error;
  String? _integrityStatus;

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

  Future<void> runCheck() async {
    SafetyNetCheckResult result;
    try {
      result = await SafetyNetFlutter.check();
    } catch (e) {
      if (!mounted) return;
      setState(() => _error = e.toString());
      return;
    }

    if (!mounted) return;
    setState(() {
      _result = result;
      _error = null;
    });
  }

  // Play Integrity is Android-only — see the README's "Play Integrity API"
  // section. Calling these on iOS rejects with a PlatformException rather
  // than crashing; this demo just gates the buttons with Platform.isAndroid
  // instead, since the outcome is already known.
  Future<void> prepareIntegrity() async {
    setState(() => _integrityStatus = 'Preparing...');
    try {
      await SafetyNetFlutter.prepareIntegrityCheck(_kCloudProjectNumber);
      if (!mounted) return;
      setState(() => _integrityStatus = 'Prepared — ready to request a token');
    } catch (e) {
      if (!mounted) return;
      setState(() => _integrityStatus = 'Prepare failed: $e');
    }
  }

  Future<void> requestToken() async {
    setState(() => _integrityStatus = 'Requesting token...');
    try {
      final token = await SafetyNetFlutter.requestIntegrityToken(
        _kRequestHash,
      );
      if (!mounted) return;
      // In a real app, send `token` to your server for verification —
      // never trust a client-side read of it.
      setState(() => _integrityStatus = 'Token: ${token.substring(0, 24)}...');
    } catch (e) {
      if (!mounted) return;
      setState(() => _integrityStatus = 'Request failed: $e');
    }
  }

  @override
  Widget build(BuildContext context) {
    final result = _result;
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('SafetyNet example')),
        body: Center(
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                if (_error != null) Text('Error: $_error'),
                if (result != null) ...[
                  Text(
                    result.isCompromised
                        ? 'Compromised device detected'
                        : 'Device looks clean',
                    style: Theme.of(context).textTheme.titleLarge,
                  ),
                  const SizedBox(height: 12),
                  if (result.reasons.isNotEmpty)
                    Text('Reasons: ${result.reasons.join(', ')}'),
                ],
                const SizedBox(height: 24),
                ElevatedButton(
                  onPressed: runCheck,
                  child: const Text('Run check again'),
                ),
                const Divider(height: 48),
                Text(
                  'Play Integrity API (Android-only)',
                  style: Theme.of(context).textTheme.titleMedium,
                ),
                const SizedBox(height: 12),
                if (Platform.isAndroid) ...[
                  Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      ElevatedButton(
                        onPressed: prepareIntegrity,
                        child: const Text('Prepare'),
                      ),
                      const SizedBox(width: 12),
                      ElevatedButton(
                        onPressed: requestToken,
                        child: const Text('Request token'),
                      ),
                    ],
                  ),
                  const SizedBox(height: 12),
                  if (_integrityStatus != null) Text(_integrityStatus!),
                ] else
                  const Text('Not available on this platform.'),
              ],
            ),
          ),
        ),
      ),
    );
  }
}
0
likes
160
points
13
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter plugin wrapping SafetyNet (iOS) and SafetyNetAndroid for report-only root/jailbreak/tamper/debugger detection on both platforms.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on safety_net_flutter

Packages that implement safety_net_flutter