anti_hook_vpn 1.0.3 copy "anti_hook_vpn: ^1.0.3" to clipboard
anti_hook_vpn: ^1.0.3 copied to clipboard

Flutter plugin to detect VPN, Proxy, and Frida hooking on Android & iOS. Protect your app from runtime attack tools.

example/lib/main.dart

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'AntiHookVpn Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: const Color(0xFF1A1A2E),
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      home: const SecurityScanPage(),
    );
  }
}

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

  @override
  State<SecurityScanPage> createState() => _SecurityScanPageState();
}

class _SecurityScanPageState extends State<SecurityScanPage>
    with SingleTickerProviderStateMixin {
  SecurityStatus? _lastStatus;
  bool _isScanning = false;
  late final AnimationController _pulseController;
  late final Animation<double> _pulseAnimation;

  @override
  void initState() {
    super.initState();
    _pulseController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 1200),
    );
    _pulseAnimation = Tween<double>(begin: 1.0, end: 1.15).animate(
      CurvedAnimation(parent: _pulseController, curve: Curves.easeInOut),
    );
    WidgetsBinding.instance.addPostFrameCallback((_) => _scan());
  }

  @override
  void dispose() {
    _pulseController.dispose();
    super.dispose();
  }

  Future<void> _scan() async {
    setState(() {
      _isScanning = true;
      _lastStatus = null;
    });
    _pulseController.repeat(reverse: true);

    final status = await AntiHookVpn.checkSecurity();

    _pulseController.stop();
    _pulseController.reset();

    if (!mounted) return;
    setState(() {
      _isScanning = false;
      _lastStatus = status;
    });

    if (status.isAttacked) {
      await AntiHookVpn.checkAndBlockIfNeeded(context);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color(0xFF0D0D1A),
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0,
        title: const Text(
          'Security Scanner',
          style: TextStyle(
            color: Colors.white,
            fontWeight: FontWeight.w600,
            letterSpacing: 1.2,
          ),
        ),
        centerTitle: true,
      ),
      body: SafeArea(
        child: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 24),
          child: Column(
            children: [
              const Spacer(),
              _ScannerOrb(
                isScanning: _isScanning,
                status: _lastStatus,
                pulseAnimation: _pulseAnimation,
              ),
              const SizedBox(height: 40),
              _StatusCards(status: _lastStatus, isScanning: _isScanning),
              const Spacer(),
              _ScanButton(isScanning: _isScanning, onTap: _scan),
              const SizedBox(height: 40),
            ],
          ),
        ),
      ),
    );
  }
}

// ─── Scanner Orb ─────────────────────────────────────────────────────────────

class _ScannerOrb extends StatelessWidget {
  const _ScannerOrb({
    required this.isScanning,
    required this.status,
    required this.pulseAnimation,
  });

  final bool isScanning;
  final SecurityStatus? status;
  final Animation<double> pulseAnimation;

  Color get _orbColor {
    if (isScanning || status == null) return const Color(0xFF3A3A6E);
    return status!.isAttacked
        ? const Color(0xFFD32F2F)
        : const Color(0xFF1B5E20);
  }

  Color get _glowColor {
    if (isScanning || status == null) return const Color(0xFF6060CC);
    return status!.isAttacked
        ? const Color(0xFFFF5252)
        : const Color(0xFF69F0AE);
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: pulseAnimation,
      builder: (_, child) => Transform.scale(
        scale: isScanning ? pulseAnimation.value : 1.0,
        child: child,
      ),
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 600),
        width: 180,
        height: 180,
        decoration: BoxDecoration(
          shape: BoxShape.circle,
          color: _orbColor,
          boxShadow: [
            BoxShadow(
              color: _glowColor.withValues(alpha: 0.5),
              blurRadius: 60,
              spreadRadius: 10,
            ),
            BoxShadow(
              color: _glowColor.withValues(alpha: 0.2),
              blurRadius: 100,
              spreadRadius: 30,
            ),
          ],
        ),
        child: Center(
          child: _buildIcon(),
        ),
      ),
    );
  }

  Widget _buildIcon() {
    if (isScanning) {
      return const SizedBox(
        width: 56,
        height: 56,
        child: CircularProgressIndicator(
          strokeWidth: 3,
          color: Colors.white70,
        ),
      );
    }
    if (status == null) {
      return const Icon(Icons.shield_outlined, size: 72, color: Colors.white54);
    }
    return Icon(
      status!.isAttacked ? Icons.gpp_bad_rounded : Icons.verified_user_rounded,
      size: 72,
      color: Colors.white,
    );
  }
}

// ─── Status Cards ─────────────────────────────────────────────────────────────

class _StatusCards extends StatelessWidget {
  const _StatusCards({required this.status, required this.isScanning});

  final SecurityStatus? status;
  final bool isScanning;

  @override
  Widget build(BuildContext context) {
    if (isScanning) {
      return const Text(
        'Scanning for threats...',
        style: TextStyle(color: Colors.white70, fontSize: 16),
      );
    }

    if (status == null) {
      return const Text(
        'Tap Scan to check your device',
        style: TextStyle(color: Colors.white54, fontSize: 15),
      );
    }

    return Column(
      children: [
        Text(
          status!.isAttacked ? '⚠ Threat Detected' : '✓ Device is Secure',
          style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
            color: status!.isAttacked
                ? const Color(0xFFFF5252)
                : const Color(0xFF69F0AE),
          ),
        ),
        const SizedBox(height: 24),
        Row(
          children: [
            Expanded(
              child: _DetectionCard(
                label: 'Frida',
                icon: Icons.bug_report_rounded,
                detected: status!.isFridaDetected,
              ),
            ),
            const SizedBox(width: 12),
            Expanded(
              child: _DetectionCard(
                label: 'VPN / Proxy',
                icon: Icons.vpn_key_rounded,
                detected: status!.isProxyOrVpnDetected,
              ),
            ),
          ],
        ),
      ],
    );
  }
}

class _DetectionCard extends StatelessWidget {
  const _DetectionCard({
    required this.label,
    required this.icon,
    required this.detected,
  });

  final String label;
  final IconData icon;
  final bool detected;

  @override
  Widget build(BuildContext context) {
    final color = detected
        ? const Color(0xFFFF5252)
        : const Color(0xFF69F0AE);

    return AnimatedContainer(
      duration: const Duration(milliseconds: 400),
      padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 16),
      decoration: BoxDecoration(
        color: color.withValues(alpha: 0.08),
        borderRadius: BorderRadius.circular(16),
        border: Border.all(color: color.withValues(alpha: 0.4)),
        boxShadow: [
          BoxShadow(
            color: color.withValues(alpha: 0.15),
            blurRadius: 20,
            spreadRadius: 2,
          ),
        ],
      ),
      child: Column(
        children: [
          Icon(icon, color: color, size: 32),
          const SizedBox(height: 8),
          Text(
            label,
            style: const TextStyle(
              color: Colors.white70,
              fontWeight: FontWeight.w500,
            ),
          ),
          const SizedBox(height: 4),
          Text(
            detected ? 'Detected' : 'Clean',
            style: TextStyle(
              color: color,
              fontWeight: FontWeight.bold,
              fontSize: 13,
            ),
          ),
        ],
      ),
    );
  }
}

// ─── Scan Button ─────────────────────────────────────────────────────────────

class _ScanButton extends StatelessWidget {
  const _ScanButton({required this.isScanning, required this.onTap});

  final bool isScanning;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: isScanning ? null : onTap,
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 300),
        width: double.infinity,
        height: 56,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(16),
          gradient: isScanning
              ? const LinearGradient(
                  colors: [Color(0xFF2A2A4A), Color(0xFF2A2A4A)],
                )
              : const LinearGradient(
                  colors: [Color(0xFF6060CC), Color(0xFF9040CC)],
                  begin: Alignment.centerLeft,
                  end: Alignment.centerRight,
                ),
          boxShadow: isScanning
              ? []
              : [
                  BoxShadow(
                    color: const Color(0xFF6060CC).withValues(alpha: 0.4),
                    blurRadius: 24,
                    spreadRadius: 2,
                    offset: const Offset(0, 6),
                  ),
                ],
        ),
        child: Center(
          child: Text(
            isScanning ? 'Scanning...' : 'Scan Now',
            style: TextStyle(
              color: isScanning ? Colors.white38 : Colors.white,
              fontSize: 16,
              fontWeight: FontWeight.w600,
              letterSpacing: 1.1,
            ),
          ),
        ),
      ),
    );
  }
}
7
likes
150
points
150
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Flutter plugin to detect VPN, Proxy, and Frida hooking on Android & iOS. Protect your app from runtime attack tools.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on anti_hook_vpn

Packages that implement anti_hook_vpn