flutter_singbox_vpn 1.1.1 copy "flutter_singbox_vpn: ^1.1.1" to clipboard
flutter_singbox_vpn: ^1.1.1 copied to clipboard

A Flutter plugin for Sing-Box VPN by TecClub. Provides complete VPN functionality with traffic stats, logging, and per-app tunneling.

Flutter SingBox #

A Flutter plugin for integrating Sing-Box VPN functionality into your Flutter applications. This plugin provides a complete bridge to the native Sing-Box implementation on Android.

pub package License: MIT

Features #

  • VPN Connection Management - Start, stop, and monitor VPN connections
  • Real-time Status Updates - Stream-based status monitoring
  • Traffic Statistics - Upload/download speeds, data usage, connection counts
  • Log Streaming - Real-time logs from sing-box core
  • Per-App Tunneling - Include/exclude specific apps from VPN
  • 16KB Page Size Support - Compatible with Android 15+ devices
  • JSON Configuration - Full sing-box JSON configuration support

Platform Support #

Platform Support Sing-Box Version
Android 1.12.12
iOS ❌ Not Supported -
macOS ❌ Not Supported -
Windows ❌ Not Supported -
Linux ❌ Not Supported -

Need iOS, macOS, or Windows support?
Contact us at tecclubx.com or email [email protected] for custom development.

Requirements #

  • Flutter SDK: >=3.3.0
  • Dart SDK: >=3.9.2
  • Android: minSdk 21, targetSdk 36

Installation #

Add the plugin to your pubspec.yaml:

dependencies:
  flutter_singbox: ^1.1.0

Then run:

flutter pub get

Android Setup #

1. Update android/app/build.gradle.kts #

android {
    compileSdk = 36
    
    defaultConfig {
        minSdk = 21
        targetSdk = 36
    }
    
    packaging {
        jniLibs {
            useLegacyPackaging = true
        }
    }
}

2. Update android/app/src/main/AndroidManifest.xml #

Add the required permissions:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <!-- Required Permissions -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE_SPECIAL_USE" />
    <uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
    
    <application
        android:label="Your App"
        android:extractNativeLibs="true"
        tools:targetApi="36">
        
        <!-- Your activities here -->
        
    </application>
</manifest>

3. Update android/settings.gradle.kts #

Add JitPack repository for sing-box library:

pluginManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
    }
}

dependencyResolutionManagement {
    repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS)
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }
    }
}

Usage #

Initialize the Plugin #

import 'package:flutter_singbox/flutter_singbox.dart';

final flutterSingbox = FlutterSingbox();

Save Configuration #

Provide a valid sing-box JSON configuration:

String config = '''
{
  "dns": {
    "servers": [
      {
        "address": "tls://8.8.8.8",
        "tag": "dns-remote"
      }
    ]
  },
  "inbounds": [
    {
      "type": "tun",
      "tag": "tun-in",
      "address": ["172.19.0.1/30"],
      "auto_route": true,
      "strict_route": true
    }
  ],
  "outbounds": [
    {
      "type": "hysteria2",
      "tag": "proxy",
      "server": "your-server.com",
      "server_port": 443,
      "password": "your-password"
    },
    {
      "type": "direct",
      "tag": "direct"
    }
  ]
}
''';

await flutterSingbox.saveConfig(config);

Start/Stop VPN #

// Start VPN connection
bool started = await flutterSingbox.startVPN();

// Stop VPN connection
bool stopped = await flutterSingbox.stopVPN();

// Get current status
String status = await flutterSingbox.getVPNStatus();
// Returns: "Stopped", "Starting", "Started", or "Stopping"

Listen to Status Changes #

flutterSingbox.onStatusChanged.listen((statusMap) {
  String status = statusMap['status'];
  int statusCode = statusMap['statusCode'];
  
  print('VPN Status: $status (code: $statusCode)');
});

Status codes:

  • 0 - Stopped
  • 1 - Starting
  • 2 - Started
  • 3 - Stopping

Monitor Traffic Statistics #

flutterSingbox.onTrafficUpdate.listen((stats) {
  // Raw values (in bytes)
  int uploadSpeed = stats['uplinkSpeed'];
  int downloadSpeed = stats['downlinkSpeed'];
  int uploadTotal = stats['uplinkTotal'];
  int downloadTotal = stats['downlinkTotal'];
  
  // Formatted strings
  String uploadSpeedStr = stats['formattedUplinkSpeed'];     // e.g., "1.24 KB/s"
  String downloadSpeedStr = stats['formattedDownlinkSpeed']; // e.g., "5.67 MB/s"
  String uploadTotalStr = stats['formattedUplinkTotal'];     // e.g., "125.4 MB"
  String downloadTotalStr = stats['formattedDownlinkTotal']; // e.g., "1.2 GB"
  
  // Connection counts
  int connectionsIn = stats['connectionsIn'];
  int connectionsOut = stats['connectionsOut'];
});

Stream Logs #

flutterSingbox.onLogMessage.listen((logEvent) {
  if (logEvent['type'] == 'log') {
    String message = logEvent['message'];
    print('Log: $message');
  }
});

// Get buffered logs
List<String> logs = await flutterSingbox.getLogs();

// Clear log buffer
await flutterSingbox.clearLogs();

Per-App Tunneling #

// Set mode: "off", "include", or "exclude"
await flutterSingbox.setPerAppProxyMode(ProxyMode.EXCLUDE);

// Set app list (package names)
await flutterSingbox.setPerAppProxyList([
  'com.whatsapp',
  'com.instagram.android',
]);

// Get current settings
String mode = await flutterSingbox.getPerAppProxyMode();
List<String> apps = await flutterSingbox.getPerAppProxyList();

// Get installed apps for selection UI
List<Map<String, dynamic>> installedApps = await flutterSingbox.getInstalledApps();
for (var app in installedApps) {
  print('${app['appName']} - ${app['packageName']}');
}

Complete Example #

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_singbox/flutter_singbox.dart';

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

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final FlutterSingbox _singbox = FlutterSingbox();
  String _status = 'Stopped';
  String _uploadSpeed = '0 B/s';
  String _downloadSpeed = '0 B/s';
  StreamSubscription? _statusSub;
  StreamSubscription? _trafficSub;

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

  void _initVPN() {
    // Listen to status changes
    _statusSub = _singbox.onStatusChanged.listen((status) {
      setState(() => _status = status['status']);
    });

    // Listen to traffic updates
    _trafficSub = _singbox.onTrafficUpdate.listen((stats) {
      setState(() {
        _uploadSpeed = stats['formattedUplinkSpeed'];
        _downloadSpeed = stats['formattedDownlinkSpeed'];
      });
    });
  }

  Future<void> _toggleVPN() async {
    if (_status == VPNStatus.STOPPED) {
      await _singbox.saveConfig(yourConfigJson);
      await _singbox.startVPN();
    } else if (_status == VPNStatus.STARTED) {
      await _singbox.stopVPN();
    }
  }

  @override
  void dispose() {
    _statusSub?.cancel();
    _trafficSub?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('SingBox VPN')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text('Status: $_status'),
              SizedBox(height: 16),
              Text('↑ $_uploadSpeed'),
              Text('↓ $_downloadSpeed'),
              SizedBox(height: 32),
              ElevatedButton(
                onPressed: _toggleVPN,
                child: Text(_status == VPNStatus.STOPPED ? 'Connect' : 'Disconnect'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

API Reference #

FlutterSingbox Class #

Method Description Returns
saveConfig(String config) Save sing-box JSON configuration Future<bool>
getConfig() Get current configuration Future<String>
startVPN() Start VPN connection Future<bool>
stopVPN() Stop VPN connection Future<bool>
getVPNStatus() Get current VPN status Future<String>
setPerAppProxyMode(String mode) Set per-app tunneling mode Future<bool>
getPerAppProxyMode() Get per-app tunneling mode Future<String>
setPerAppProxyList(List<String>? apps) Set apps for per-app tunneling Future<bool>
getPerAppProxyList() Get per-app tunneling app list Future<List<String>>
getInstalledApps() Get list of installed apps Future<List<Map>>
getLogs() Get buffered log messages Future<List<String>>
clearLogs() Clear log buffer Future<bool>

Streams #

Stream Description Event Type
onStatusChanged VPN status updates Map<String, dynamic>
onTrafficUpdate Traffic statistics Map<String, dynamic>
onLogMessage Log messages from sing-box Map<String, dynamic>

Helper Classes #

class VPNStatus {
  static const String STOPPED = "Stopped";
  static const String STARTING = "Starting";
  static const String STARTED = "Started";
  static const String STOPPING = "Stopping";
}

class ProxyMode {
  static const String OFF = "off";
  static const String INCLUDE = "include";
  static const String EXCLUDE = "exclude";
}

Troubleshooting #

VPN Permission Not Granted #

The plugin will automatically request VPN permission when startVPN() is called. Ensure your app handles the permission dialog properly.

No Internet After Connecting #

Check your sing-box configuration:

  • Ensure DNS servers are properly configured
  • Verify outbound proxy servers are reachable
  • Check route rules are correct

Build Errors #

If you encounter build errors:

  1. Clean and rebuild:
cd android && ./gradlew clean && cd ..
flutter clean
flutter pub get
flutter build apk
  1. Ensure JitPack repository is added to settings.gradle.kts

16KB Page Size (Android 15+) #

The plugin supports 16KB page size devices. Ensure your app's build.gradle.kts has:

android {
    compileSdk = 36
    packaging {
        jniLibs {
            useLegacyPackaging = true
        }
    }
}

Changelog #

1.1.1 #

  • Fixed app launcher icon being overridden by plugin drawable
  • Added VPN key icon for notification
  • Fixed VPN status incorrectly showing "Started" when config has errors
  • Improved error handling during VPN startup

1.1.0 #

  • Added log streaming support
  • Added 16KB page size support for Android 15+
  • Improved VPN state management
  • Fixed connection stability issues
  • Updated to libbox 1.12.12

1.0.0 #

  • Initial release

License #

This project is licensed under the MIT License - see the LICENSE file for details.

Credits #

Contact #

For support, custom development, or business inquiries:

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

3
likes
0
points
370
downloads

Publisher

verified publishertecclubx.com

Weekly Downloads

A Flutter plugin for Sing-Box VPN by TecClub. Provides complete VPN functionality with traffic stats, logging, and per-app tunneling.

Homepage
Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, plugin_platform_interface

More

Packages that depend on flutter_singbox_vpn

Packages that implement flutter_singbox_vpn