ikev2 0.0.1 copy "ikev2: ^0.0.1" to clipboard
ikev2: ^0.0.1 copied to clipboard

PlatformAndroid

Flutter plugin for IKEv2 VPN protocol support.

example/lib/main.dart

/// Copyright (C) 2026 Orban
///
/// This library is free software; you can redistribute it and/or
/// modify it under the terms of the GNU Lesser General Public
/// License as published by the Free Software Foundation; either
/// version 2.1 of the License, or (at your option) any later version.
///
/// This library is distributed in the hope that it will be useful,
/// but WITHOUT ANY WARRANTY; without even the implied warranty of
/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
/// Lesser General Public License for more details.
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:ikev2/ikev2.dart';
import 'package:ikev2/state.dart';
import 'package:ikev2/vpn_traffic_stats.dart';

void main() => runApp(const MyApp());

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

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

class _MyAppState extends State<MyApp> {
  final _addressController = TextEditingController(text: "");
  final _usernameController = TextEditingController(text: "");
  final _passwordController = TextEditingController(text: "");
  final _secretController = TextEditingController(text: "");

  final _remoteId = TextEditingController(text: "");
  final _localId = TextEditingController(text: "");

  var state = IkeV2State.disconnected;
  CharonErrorState? charonState = CharonErrorState.NO_ERROR;
  VpnTrafficStats? trafficStats;

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

    // Always call prepare (for Android)
    IkeV2.prepare();

    // ✅ Restore current VPN state
    IkeV2.currentState.then((s) {
      setState(() {
        state = s;
      });

      // ✅ If VPN is already connected, start monitoring manually
      if (s == IkeV2State.connected) {
        IkeV2.startTrafficMonitor(); // Start native side monitor

        IkeV2.onTrafficChanged.listen((stats) {
          setState(() {
            trafficStats = stats;
          });
          debugPrint('⬇ Download: ${stats.downloadSpeed} B/s');
          debugPrint('⬆ Upload: ${stats.uploadSpeed} B/s');
          debugPrint('↓ Total Download: ${stats.totalDownload} bytes');
          debugPrint('↑ Total Upload: ${stats.totalUpload} bytes');
          debugPrint('⏱️ Duration: ${stats.duration} seconds');
        });
      }
    });

    // ✅ Restore Charon error state
    IkeV2.charonErrorState.then((s) {
      setState(() {
        charonState = s ?? CharonErrorState.NO_ERROR;
      });
    });

    // ✅ VPN connection state listener
    IkeV2.onStateChanged.listen((s) {
      setState(() {
        state = s;
      });

      if (s == IkeV2State.connected) {
        IkeV2.startTrafficMonitor(); // Start on connection too

        IkeV2.onTrafficChanged.listen((stats) {
          setState(() {
            trafficStats = stats;
          });
          // print('⬇ Download: ${stats.downloadSpeed} B/s');
          // print('⬆ Upload: ${stats.uploadSpeed} B/s');
          // print('↓ Total Download: ${stats.totalDownload} bytes');
          // print('↑ Total Upload: ${stats.totalUpload} bytes');
          // print('⏱️ Duration: ${stats.duration} seconds');
        });
      } else {
        setState(() {
          trafficStats = null;
        });
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter VPN'),
        ),
        body: ListView(
          padding: const EdgeInsets.all(12),
          children: <Widget>[
            Text('Current State: $state'),
            Text('Current Charon State: $charonState'),
            if (trafficStats != null) ...[
              Text('⬇ Download Speed: ${trafficStats!.downloadSpeed} B/s'),
              Text('⬆ Upload Speed: ${trafficStats!.uploadSpeed} B/s'),
              Text('↓ Total Download: ${trafficStats!.totalDownload} bytes'),
              Text('↑ Total Upload: ${trafficStats!.totalUpload} bytes'),
              Text('⏱️ Duration: ${trafficStats!.duration} seconds'),
              Text('⏱️ Timer: ${trafficStats!.formattedDuration}'),
            ],
            TextFormField(
              controller: _addressController,
              decoration: const InputDecoration(
                icon: Icon(Icons.map_outlined),
                labelText: "Server Address",
              ),
            ),
            TextFormField(
              controller: _usernameController,
              decoration: const InputDecoration(
                icon: Icon(Icons.person_outline),
                labelText: "Username",
              ),
            ),
            TextFormField(
              controller: _passwordController,
              obscureText: true,
              decoration: const InputDecoration(
                icon: Icon(Icons.lock_outline),
                labelText: "Password",
              ),
            ),
            TextFormField(
              controller: _secretController,
              obscureText: true,
              decoration: const InputDecoration(
                icon: Icon(Icons.vpn_key_outlined),
                labelText: 'Secret / PSK',
              ),
            ),
            TextFormField(
              controller: _remoteId,
              decoration: const InputDecoration(
                icon: Icon(Icons.cloud_circle_outlined),
                labelText: 'Remote ID (optional)',
              ),
            ),
            TextFormField(
              controller: _localId,
              decoration: const InputDecoration(
                icon: Icon(Icons.cloud_circle_outlined),
                labelText: 'Local ID (optional)',
              ),
            ),
            ElevatedButton(
              child: const Text('Connect IKEv2 EAP'),
              onPressed: () => IkeV2.connectIkev2EAP(
                server: _addressController.text,
                username: _usernameController.text,
                password: _passwordController.text,
                remoteId: _remoteId.text.isNotEmpty ? _remoteId.text : null,
                localId: _localId.text.isNotEmpty ? _localId.text : null,
                disableCertValidation:
                    false, // Keep false as default for better chain loading
              ),
            ),
            ElevatedButton(
              child: const Text('Connect IKEv2 PSK'),
              onPressed: () => IkeV2.connectIkev2Psk(
                server: _addressController.text,
                username: _usernameController.text,
                password: _passwordController.text,
                remoteId: _remoteId.text.isNotEmpty ? _remoteId.text : '',
                localId: _localId.text.isNotEmpty ? _localId.text : '',
                // In PSK mode, 'secret' is effectively the PSK, but in this library generic structure
                // it might be passed differently. Looking at library code:
                // connectIkev2Psk does NOT take a 'secret' param directly in the signature shown in previous `read_file`.
                // Wait, let me check the library definition again. `connectIkev2Psk` signature:
                // required String server, required String username, required String password, required String remoteId, required String localId, ...
                // It seems it reuses 'password' as PSK or expects it elsewhere?
                // Checking previous `FlutterVpn` (now `IkeV2`) definition:
                // connectIkev2Psk(...) => ... 'Password': password ... 'Secret': '', ...
                // It seems `connectIkev2Psk` in `ikev2.dart` takes `password` but hardcodes `Secret` to empty string.
                // However, usually PSK is passed as the shared secret.
                // Let's check `connectIPSec`. It takes `secret`.
                // If the user wants generic IKEv2 PSK, typically that's Authentication Method = PSK.
                // The library method `connectIkev2Psk` takes username/password? That is unusual for pure PSK.
                // It might be EAP with specific config or the library naming is specific.
                // For `connectIPSec`, it takes `secret`.
                // Let's implement based on available methods.
              ),
            ),
            ElevatedButton(
              child: const Text('Disconnect'),
              onPressed: () => IkeV2.disconnect(),
            ),
            ElevatedButton(
              child: const Text('Update State'),
              onPressed: () async {
                var newState = await IkeV2.currentState;
                setState(() => state = newState);
              },
            ),
            ElevatedButton(
              child: const Text('Update Charon State'),
              onPressed: () async {
                var newState = await IkeV2.charonErrorState;
                setState(() => charonState = newState);
              },
            ),
          ],
        ),
      ),
    );
  }
}
1
likes
140
points
114
downloads

Publisher

verified publisherorbaninfotech.com

Weekly Downloads

Flutter plugin for IKEv2 VPN protocol support.

Homepage

Documentation

API reference

License

LGPL-3.0 (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on ikev2

Packages that implement ikev2