Flutter VPN配置插件wireguard_2govpn的使用

Flutter VPN配置插件wireguard_2govpn的使用

介绍

wireguard_2govpn 是一个用于通过 WireGuard 隧道设置和控制VPN连接的 Flutter 插件。

使用

初始化

首先,在你的项目中添加 wireguard_2govpn 依赖:

flutter pub add wireguard_2govpn

初始化 WireGuard 实例:

final wireguard = WireGuardFlutter.instance;

// 初始化接口
await wireguard.initialize(interfaceName: 'wg0');

然后声明 .conf 数据:

const String conf = '''[Interface]
PrivateKey = 0IZmHsxiNQ54TsUs0EQ71JNsa5f70zVf1LmDvON1CXc=
Address = 10.8.0.4/32
DNS = 1.1.1.1

[Peer]
PublicKey = 6uZg6T0J1bHuEmdqPx8OmxQ2ebBJ8TnVpnCdV8jHliQ=
PresharedKey = As6JiXcYcqwjSHxSOrmQT13uGVlBG90uXZWmtaezZVs=
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 0
Endpoint = 38.180.13.85:51820''';

更多关于配置数据的信息,可以参见 文档 中的例子。

连接

初始化后,使用 startVpn 方法进行连接:

await wireguard.startVpn(
  serverAddress: address, // 例如 'demo.wireguard.com:51820'
  wgQuickConfig: conf, // 快速配置文件
  providerBundleIdentifier: 'com.example', // 你的应用标识符
);

断开连接

连接后,使用 stopVpn 方法断开连接:

await wireguard.stopVpn();

监听阶段变化

监听阶段变化使用 vpnStageSnapshot

wireguard.vpnStageSnapshot.listen((event) {
  debugPrint("状态改变 $event");
});

或者获取当前阶段使用 getStage

final stage = await wireguard.stage();

可用阶段包括:

代码 描述
connecting 接口正在连接
connected 接口已连接
disconnecting 接口正在断开连接
disconnected 接口已断开连接
waitingConnection 等待用户交互
authenticating 正在与服务器认证
reconnect 重新连接接口
noConnection 任何连接都没有建立
preparing 准备连接
denied 连接被系统拒绝,通常是权限问题
exiting 接口退出

支持的平台

平台 Android iOS macOS Windows Linux
版本 SDK 21+ 15.0+ 12+ 7+ 任意

Windows

在 Windows 上,应用必须以管理员身份运行才能创建和操作隧道。要调试应用,请从提升后的命令提示符运行 flutter run。要正常运行应用,系统会请求你以管理员身份运行应用。无需进行代码更改或外部依赖。

Linux

安装依赖

需要安装以下依赖:wireguardwireguard-tools

在 Ubuntu/Debian 上,使用以下命令安装依赖:

sudo apt install wireguard wireguard-tools openresolv

对于其他 Linux 发行版,请参阅 这里

注意: 如果系统中未安装 openresolv,配置文件中的 DNS 可能无法连接。更多信息请参阅 此问题

初始化

当调用 wireguard.initialize 时,应用程序将请求用户密码([sudo] password for <user>:)。这是必要的,因为 WireGuard 必须以 root 身份运行才能创建和操作隧道。这适用于调试模式、发布模式或分布式可执行文件。

警告: 不要在 root 模式下运行应用(例如 sudo ./executablesudo flutter run),否则连接将无法建立。

常见问题及故障排除

Linux 错误 resolvconf: command not found

在 Linux 上,可能会收到错误 resolvconf: command not found。这是因为 WireGuard 尝试调整名称服务器。确保安装了 openresolv 或不提供 “DNS” 字段。

示例代码

以下是一个完整的示例代码,展示了如何使用 wireguard_2govpn 插件:

import 'dart:async';

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

void main() {
  runApp(
    MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('WireGuard 示例应用'),
        ),
        body: const MyApp(),
      ),
    ),
  );
}

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

  [@override](/user/override)
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final wireguard = WireGuardFlutter.instance;

  late String name;

  [@override](/user/override)
  void initState() {
    super.initState();
    wireguard.vpnStageSnapshot.listen((event) {
      debugPrint("状态改变 $event");
      if (mounted) {
        ScaffoldMessenger.of(context).clearSnackBars();
        ScaffoldMessenger.of(context).showSnackBar(SnackBar(
          content: Text('状态改变: $event'),
        ));
      }
    });
    name = 'my_wg_vpn';
  }

  Future<void> initialize() async {
    try {
      await wireguard.initialize(interfaceName: name);
      debugPrint("初始化成功 $name");
    } catch (error, stack) {
      debugPrint("初始化失败: $error\n$stack");
    }
  }

  void startVpn() async {
    try {
      await wireguard.startVpn(
        serverAddress: '167.235.55.239:51820',
        wgQuickConfig: conf,
        providerBundleIdentifier: 'com.billion.wireguardvpn.WGExtension',
      );
    } catch (error, stack) {
      debugPrint("启动失败 $error\n$stack");
    }
  }

  void disconnect() async {
    try {
      await wireguard.stopVpn();
    } catch (e, str) {
      debugPrint('断开失败 $e\n$str');
    }
  }

  void getStatus() async {
    debugPrint("获取状态");
    final stage = await wireguard.stage();
    debugPrint("阶段: $stage");

    if (mounted) {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(
        content: Text('阶段: $stage'),
      ));
    }
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Container(
      constraints: const BoxConstraints.expand(),
      padding: const EdgeInsets.all(16),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          const SizedBox(height: 20),
          TextButton(
            onPressed: initialize,
            style: ButtonStyle(
                minimumSize: MaterialStateProperty.all<Size>(const Size(100, 50)),
                padding: MaterialStateProperty.all(const EdgeInsets.fromLTRB(20, 15, 20, 15)),
                backgroundColor: MaterialStateProperty.all<Color>(Colors.blueAccent),
                overlayColor: MaterialStateProperty.all<Color>(Colors.white.withOpacity(0.1))),
            child: const Text(
              '初始化',
              style: TextStyle(color: Colors.white),
            ),
          ),
          const SizedBox(height: 20),
          TextButton(
            onPressed: startVpn,
            style: ButtonStyle(
                minimumSize: MaterialStateProperty.all<Size>(const Size(100, 50)),
                padding: MaterialStateProperty.all(const EdgeInsets.fromLTRB(20, 15, 20, 15)),
                backgroundColor: MaterialStateProperty.all<Color>(Colors.blueAccent),
                overlayColor: MaterialStateProperty.all<Color>(Colors.white.withOpacity(0.1))),
            child: const Text(
              '连接',
              style: TextStyle(color: Colors.white),
            ),
          ),
          const SizedBox(height: 20),
          TextButton(
            onPressed: disconnect,
            style: ButtonStyle(
                minimumSize: MaterialStateProperty.all<Size>(const Size(100, 50)),
                padding: MaterialStateProperty.all(const EdgeInsets.fromLTRB(20, 15, 20, 15)),
                backgroundColor: MaterialStateProperty.all<Color>(Colors.blueAccent),
                overlayColor: MaterialStateProperty.all<Color>(Colors.white.withOpacity(0.1))),
            child: const Text(
              '断开连接',
              style: TextStyle(color: Colors.white),
            ),
          ),
          const SizedBox(height: 20),
          TextButton(
            onPressed: getStatus,
            style: ButtonStyle(
                minimumSize: MaterialStateProperty.all<Size>(const Size(100, 50)),
                padding: MaterialStateProperty.all(const EdgeInsets.fromLTRB(20, 15, 20, 15)),
                backgroundColor: MaterialStateProperty.all<Color>(Colors.blueAccent),
                overlayColor: MaterialStateProperty.all<Color>(Colors.white.withOpacity(0.1))),
            child: const Text(
              '获取状态',
              style: TextStyle(color: Colors.white),
            ),
          ),
        ],
      ),
    );
  }
}

const String conf = '''[Interface]
PrivateKey = 0IZmHsxiNQ54TsUs0EQ71JNsa5f70zVf1LmDvON1CXc=
Address = 10.8.0.4/32
DNS = 1.1.1.1

[Peer]
PublicKey = 6uZg6T0J1bHuEmdqPx8OmxQ2ebBJ8TnVpnCdV8jHliQ=
PresharedKey = As6JiXcYcqwjSHxSOrmQT13uGVlBG90uXZWmtaezZVs=
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 0
Endpoint = 38.180.13.85:51820''';

更多关于Flutter VPN配置插件wireguard_2govpn的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter VPN配置插件wireguard_2govpn的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中配置和使用wireguard_2govpn插件的示例代码。这个插件允许你在Flutter应用中配置和使用WireGuard VPN。

首先,你需要在你的pubspec.yaml文件中添加wireguard_2govpn依赖:

dependencies:
  flutter:
    sdk: flutter
  wireguard_2govpn: ^最新版本号 # 请替换为实际的最新版本号

然后运行flutter pub get来获取依赖。

接下来,你需要在你的Flutter应用中配置和使用WireGuard。以下是一个简单的示例,展示如何初始化WireGuard配置并启动VPN连接。

主应用代码(main.dart

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

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

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

class _MyAppState extends State<MyApp> {
  late WireGuard2GoVpn _wireguard;
  bool _isConnected = false;

  @override
  void initState() {
    super.initState();
    _wireguard = WireGuard2GoVpn();
    _initializeWireGuard();
  }

  Future<void> _initializeWireGuard() async {
    try {
      // 配置WireGuard,例如接口名称、私钥、公钥、服务器地址等
      String interfaceName = "wg0";
      String privateKey = "你的私钥";
      List<Map<String, String>> peers = [
        {
          "publicKey": "服务器的公钥",
          "endpoint": "服务器的地址:端口",
          "allowedIPs": "0.0.0.0/0, ::/0", // 允许的IP范围
          "persistentKeepalive": "25", // 持久性保活时间(秒)
        },
        // 可以添加更多peer配置
      ];

      // 设置配置
      await _wireguard.setConfig(
        interfaceName: interfaceName,
        privateKey: privateKey,
        peers: peers,
      );

      // 启动VPN连接
      bool success = await _wireguard.start();
      if (success) {
        setState(() {
          _isConnected = true;
        });
      } else {
        // 处理启动失败的情况
        print("Failed to start WireGuard");
      }
    } catch (e) {
      print("Error initializing WireGuard: $e");
    }
  }

  Future<void> _stopWireGuard() async {
    try {
      bool success = await _wireguard.stop();
      if (success) {
        setState(() {
          _isConnected = false;
        });
      } else {
        // 处理停止失败的情况
        print("Failed to stop WireGuard");
      }
    } catch (e) {
      print("Error stopping WireGuard: $e");
    }
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text('WireGuard VPN Example'),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Text(
                'Connection Status: $_isConnected',
                style: TextStyle(fontSize: 24),
              ),
              SizedBox(height: 20),
              ElevatedButton(
                onPressed: _isConnected ? _stopWireGuard : () async {
                  await _initializeWireGuard();
                },
                child: Text(_isConnected ? 'Stop VPN' : 'Start VPN'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

注意事项

  1. 权限:在Android上,你可能需要在AndroidManifest.xml中添加必要的网络权限。在iOS上,你可能需要在Info.plist中添加网络权限和后台模式权限。

  2. 私钥和公钥:在实际应用中,私钥和公钥应该是安全的,并且不应该硬编码在代码中。你可能需要使用安全的存储方式,如Keychain(iOS)或KeyStore(Android)。

  3. 依赖项wireguard_2govpn插件可能依赖于特定的系统库或二进制文件,确保你的设备或模拟器已经安装了必要的依赖项。

  4. 错误处理:示例代码中的错误处理非常基础,在实际应用中你应该添加更详细的错误处理和用户反馈机制。

  5. 平台特定配置:WireGuard在不同平台上的配置可能会有所不同,确保你查阅了相关平台的文档和配置指南。

请根据你的具体需求调整上述代码,并确保在发布应用之前进行充分的测试。

回到顶部