Qt VPN Client 完整项目设置指南

项目目录结构

QtVPNClient/
├── QtVPNClient.pro          # qmake项目文件
├── CMakeLists.txt           # cmake项目文件
├── main.cpp                 # 程序入口
├── mainwindow.h             # 主窗口头文件
├── mainwindow.cpp           # 主窗口实现
├── mainwindow.ui            # 主窗口UI文件
├── vpnmanager.h             # VPN管理器头文件
├── vpnmanager.cpp           # VPN管理器实现
├── configparser.h           # 配置解析器头文件
├── configparser.cpp         # 配置解析器实现
├── resources.qrc            # 资源文件
├── icons/                   # 图标目录
│   ├── app_icon.png
│   ├── connected.png
│   ├── disconnected.png
│   └── connecting.png
├── platforms/               # 平台特定文件
│   ├── android/
│   │   ├── AndroidManifest.xml
│   │   ├── build.gradle
│   │   └── res/
│   ├── ios/
│   │   ├── Info.plist
│   │   └── Icons/
│   ├── windows/
│   │   ├── app.rc
│   │   └── app.ico
│   ├── macos/
│   │   └── Info.plist
│   └── linux/
│       └── qtxrayvpn.desktop
├── translations/            # 翻译文件
│   ├── qtxrayvpn_zh_CN.ts
│   ├── qtxrayvpn_en_US.ts
│   └── qtxrayvpn_ja_JP.ts
├── scripts/                 # 构建脚本
│   ├── build.sh
│   ├── build.bat
│   ├── deploy_android.sh
│   ├── deploy_ios.sh
│   └── install_deps.sh
├── docs/                    # 文档
│   ├── README.md
│   ├── BUILD.md
│   └── API.md
└── third_party/             # 第三方库
    └── xray/
        ├── windows/
        ├── linux/
        ├── macos/
        ├── android/
        └── ios/

1. QtVPNClient.pro (qmake项目文件)

QT += core widgets network

CONFIG += c++17

TARGET = QtVPNClient
TEMPLATE = app

# 版本信息
VERSION = 1.0.0
QMAKE_TARGET_COMPANY = "VPN Client Team"
QMAKE_TARGET_PRODUCT = "Qt VPN Client"
QMAKE_TARGET_DESCRIPTION = "Cross-platform VPN client based on Qt and Xray"
QMAKE_TARGET_COPYRIGHT = "Copyright (C) 2025"

# 源文件
SOURCES += \
    main.cpp \
    mainwindow.cpp \
    vpnmanager.cpp \
    configparser.cpp

HEADERS += \
    mainwindow.h \
    vpnmanager.h \
    configparser.h

FORMS += \
    mainwindow.ui

RESOURCES += \
    resources.qrc

# 翻译文件
TRANSLATIONS += \
    translations/qtxrayvpn_zh_CN.ts \
    translations/qtxrayvpn_en_US.ts \
    translations/qtxrayvpn_ja_JP.ts

# 平台特定配置
win32 {
    RC_FILE = platforms/windows/app.rc
    LIBS += -lws2_32 -lwininet
}

macx {
    ICON = icons/app_icon.icns
    QMAKE_INFO_PLIST = platforms/macos/Info.plist
    QMAKE_MACOSX_DEPLOYMENT_TARGET = 10.15
}

unix:!macx {
    TARGET = qtxrayvpn
    target.path = /usr/local/bin
    desktop.files = platforms/linux/qtxrayvpn.desktop
    desktop.path = /usr/share/applications
    icons.files = icons/app_icon.png
    icons.path = /usr/share/pixmaps
    INSTALLS += target desktop icons
}

android {
    QT += androidextras
    ANDROID_PACKAGE_SOURCE_DIR = $$PWD/platforms/android
    ANDROID_MIN_SDK_VERSION = 23
    ANDROID_TARGET_SDK_VERSION = 30
}

ios {
    QMAKE_INFO_PLIST = platforms/ios/Info.plist
    QMAKE_IOS_DEPLOYMENT_TARGET = 12.0
    app_launch_images.files = platforms/ios/Icons/Default*.png
    QMAKE_BUNDLE_DATA += app_launch_images
}

# 调试/发布配置
CONFIG(debug, debug|release) {
    DEFINES += DEBUG_MODE
    DESTDIR = debug
} else {
    DEFINES += RELEASE_MODE
    DESTDIR = release
}

# 包含路径
INCLUDEPATH += \
    third_party/xray/include

# 库链接
LIBS += -L$$PWD/third_party/xray/lib

2. 详细的源代码文件

main.cpp

#include <QApplication>
#include <QStyleFactory>
#include <QDir>
#include <QStandardPaths>
#include <QTranslator>
#include <QLocale>
#include <QLibraryInfo>
#include <QMessageBox>
#include "mainwindow.h"

#ifdef Q_OS_ANDROID
#include <QtAndroid>
#include <QAndroidJniObject>
#endif

#ifdef Q_OS_WIN
#include <windows.h>
#include <io.h>
#include <fcntl.h>
#endif

int main(int argc, char *argv[])
{
    // 启用高DPI支持
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
    
    QApplication app(argc, argv);
    
    // 应用程序信息
    app.setApplicationName("Qt VPN Client");
    app.setApplicationDisplayName("Qt VPN Client");
    app.setApplicationVersion("1.0.0");
    app.setOrganizationName("VPN Client Team");
    app.setOrganizationDomain("vpnclient.com");
    
    // 设置应用程序图标
    app.setWindowIcon(QIcon(":/icons/app_icon.png"));
    
#ifdef Q_OS_WIN
    // Windows控制台支持
    if (AllocConsole()) {
        freopen_s((FILE**)stdout, "CONOUT$", "w", stdout);
        freopen_s((FILE**)stderr, "CONOUT$", "w", stderr);
        freopen_s((FILE**)stdin, "CONIN$", "r", stdin);
    }
#endif
    
    // 国际化支持
    QTranslator translator;
    QTranslator qtTranslator;
    
    QString locale = QLocale::system().name();
    QString translationPath = ":/translations";
    
    if (translator.load(QString("qtxrayvpn_%1").arg(locale), translationPath)) {
        app.installTranslator(&translator);
    }
    
    if (qtTranslator.load(QString("qt_%1").arg(locale), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
        app.installTranslator(&qtTranslator);
    }
    
    // 设置样式
    app.setStyle(QStyleFactory::create("Fusion"));
    
    // 应用样式表
    QString styleSheet = R"(
        QMainWindow {
            background-color: #f0f0f0;
        }
        
        QGroupBox {
            font-weight: bold;
            border: 2px solid #cccccc;
            border-radius: 5px;
            margin-top: 10px;
            padding-top: 10px;
        }
        
        QGroupBox::title {
            subcontrol-origin: margin;
            left: 10px;
            padding: 0 10px 0 10px;
        }
        
        QPushButton {
            background-color: #0078d4;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
            font-weight: bold;
        }
        
        QPushButton:hover {
            background-color: #106ebe;
        }
        
        QPushButton:pressed {
            background-color: #005a9e;
        }
        
        QPushButton:disabled {
            background-color: #cccccc;
            color: #666666;
        }
        
        QLineEdit, QSpinBox, QComboBox {
            padding: 6px;
            border: 1px solid #cccccc;
            border-radius: 3px;
            background-color: white;
        }
        
        QLineEdit:focus, QSpinBox:focus, QComboBox:focus {
            border-color: #0078d4;
        }
        
        QTextEdit {
            border: 1px solid #cccccc;
            border-radius: 3px;
            background-color: white;
            font-family: 'Consolas', 'Monaco', monospace;
        }
        
        QProgressBar {
            border: 1px solid #cccccc;
            border-radius: 3px;
            text-align: center;
        }
        
        QProgressBar::chunk {
            background-color: #0078d4;
            border-radius: 2px;
        }
    )";
    app.setStyleSheet(styleSheet);
    
    // 创建配置目录
    QString configDir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
    QDir().mkpath(configDir);
    
#ifdef Q_OS_ANDROID
    // Android权限请求
    QStringList permissions;
    permissions << "android.permission.INTERNET"
                << "android.permission.ACCESS_NETWORK_STATE"
                << "android.permission.WRITE_EXTERNAL_STORAGE"
                << "android.permission.READ_EXTERNAL_STORAGE";
    
    for (const QString &permission : permissions) {
        if (QtAndroid::checkPermission(permission) != QtAndroid::PermissionResult::Granted) {
            auto result = QtAndroid::requestPermissionsSync(QStringList() << permission);
            if (result[permission] != QtAndroid::PermissionResult::Granted) {
                QMessageBox::warning(nullptr, "权限错误", 
                    QString("需要权限: %1").arg(permission));
            }
        }
    }
#endif
    
    // 检查是否已有实例运行
    QString lockFilePath = configDir + "/app.lock";
    QFile lockFile(lockFilePath);
    if (lockFile.exists()) {
        QMessageBox::information(nullptr, "提示", "应用程序已在运行中");
        return 0;
    }
    
    // 创建锁文件
    if (lockFile.open(QIODevice::WriteOnly)) {
        lockFile.write(QString::number(QApplication::applicationPid()).toUtf8());
        lockFile.close();
    }
    
    // 创建主窗口
    MainWindow window;
    window.show();
    
    int result = app.exec();
    
    // 清理锁文件
    lockFile.remove();
    
    return result;
}

mainwindow.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>800</width>
    <height>650</height>
   </rect>
  </property>
  <property name="minimumSize">
   <size>
    <width>600</width>
    <height>500</height>
   </size>
  </property>
  <property name="windowTitle">
   <string>Qt VPN Client</string>
  </property>
  <property name="windowIcon">
   <iconset resource="resources.qrc">
    <normaloff>:/icons/app_icon.png</normaloff>:/icons/app_icon.png</iconset>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QVBoxLayout" name="verticalLayout">
    <property name="spacing">
     <number>10</number>
    </property>
    <property name="leftMargin">
     <number>10</number>
    </property>
    <property name="topMargin">
     <number>10</number>
    </property>
    <property name="rightMargin">
     <number>10</number>
    </property>
    <property name="bottomMargin">
     <number>10</number>
    </property>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menubar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>800</width>
     <height>22</height>
    </rect>
   </property>
   <widget class="QMenu" name="menuFile">
    <property name="title">
     <string>文件(&amp;F)</string>
    </property>
    <addaction name="actionImportConfig"/>
    <addaction name="actionExportConfig"/>
    <addaction name="separator"/>
    <addaction name="actionExit"/>
   </widget>
   <widget class="QMenu" name="menuHelp">
    <property name="title">
     <string>帮助(&amp;H)</string>
    </property>
    <addaction name="actionAbout"/>
    <addaction name="actionAboutQt"/>
   </widget>
   <widget class="QMenu" name="menuView">
    <property name="title">
     <string>视图(&amp;V)</string>
    </property>
    <addaction name="actionShowLog"/>
    <addaction name="actionAlwaysOnTop"/>
   </widget>
   <addaction name="menuFile"/>
   <addaction name="menuView"/>
   <addaction name="menuHelp"/>
  </widget>
  <widget class="QStatusBar" name="statusbar"/>
  <action name="actionImportConfig">
   <property name="text">
    <string>导入配置(&amp;I)</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+I</string>
   </property>
  </action>
  <action name="actionExportConfig">
   <property name="text">
    <string>导出配置(&amp;E)</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+E</string>
   </property>
  </action>
  <action name="actionExit">
   <property name="text">
    <string>退出(&amp;X)</string>
   </property>
   <property name="shortcut">
    <string>Ctrl+Q</string>
   </property>
  </action>
  <action name="actionAbout">
   <property name="text">
    <string>关于(&amp;A)</string>
   </property>
  </action>
  <action name="actionAboutQt">
   <property name="text">
    <string>关于Qt(&amp;Q)</string>
   </property>
  </action>
  <action name="actionShowLog">
   <property name="text">
    <string>显示日志(&amp;L)</string>
   </property>
   <property name="checkable">
    <bool>true</bool>
   </property>
   <property name="checked">
    <bool>true</bool>
   </property>
  </action>
  <action name="actionAlwaysOnTop">
   <property name="text">
    <string>置顶窗口(&amp;T)</string>
   </property>
   <property name="checkable">
    <bool>true</bool>
   </property>
  </action>
 </widget>
 <resources>
  <include location="resources.qrc"/>
 </resources>
 <connections/>
</ui>

3. 平台特定文件

platforms/android/build.gradle

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.vpnclient.qt"
        minSdkVersion 23
        targetSdkVersion 30
        versionCode 1
        versionName "1.0.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.3.1'
}

platforms/windows/app.rc

#include <windows.h>

IDI_ICON1 ICON DISCARDABLE "app.ico"

VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x40004L
FILETYPE 0x1L
FILESUBTYPE 0x0L
BEGIN
    BLOCK "StringFileInfo"
    BEGIN
        BLOCK "040904b0"
        BEGIN
            VALUE "CompanyName", "VPN Client Team"
            VALUE "FileDescription", "Qt VPN Client"
            VALUE "FileVersion", "1.0.0.0"
            VALUE "LegalCopyright", "Copyright (C) 2025"
            VALUE "OriginalFilename", "QtVPNClient.exe"
            VALUE "ProductName", "Qt VPN Client"
            VALUE "ProductVersion", "1.0.0.0"
        END
    END
    BLOCK "VarFileInfo"
    BEGIN
        VALUE "Translation", 0x409, 1200
    END
END

platforms/linux/qtxrayvpn.desktop

[Desktop Entry]
Version=1.0
Type=Application
Name=Qt VPN Client
Comment=Cross-platform VPN client based on Qt and Xray
Icon=qtxrayvpn
Exec=qtxrayvpn
Categories=Network;
StartupNotify=true
StartupWMClass=QtVPNClient

4. 构建脚本

scripts/build.sh

#!/bin/bash

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

echo -e "${BLUE}Qt VPN Client Build Script${NC}"
echo "==============================="

# 检测操作系统
OS="Unknown"
case "$(uname -s)" in
    Linux*)     OS=Linux;;
    Darwin*)    OS=Mac;;
    CYGWIN*)    OS=Cygwin;;
    MINGW*)     OS=MinGw;;
    *)          OS="UNKNOWN:$(uname -s)"
esac

echo -e "${YELLOW}检测到操作系统: $OS${NC}"

# 设置Qt路径
if [ -z "$Qt6_DIR" ]; then
    case $OS in
        Linux)
            Qt6_DIR="/opt/Qt/6.5.0/gcc_64"
            ;;
        Mac)
            Qt6_DIR="/usr/local/Qt-6.5.0"
            ;;
        *)
            echo -e "${RED}错误: 请设置 Qt6_DIR 环境变量${NC}"
            exit 1
            ;;
    esac
fi

if [ ! -d "$Qt6_DIR" ]; then
    echo -e "${RED}错误: Qt目录不存在: $Qt6_DIR${NC}"
    exit 1
fi

export PATH="$Qt6_DIR/bin:$PATH"
echo -e "${GREEN}Qt路径: $Qt6_DIR${NC}"

# 检查必要工具
check_tool() {
    if ! command -v $1 &> /dev/null; then
        echo -e "${RED}错误: $1 未找到,请先安装${NC}"
        exit 1
    fi
}

check_tool cmake
check_tool make

# 清理旧的构建
if [ -d "build" ]; then
    echo -e "${YELLOW}清理旧的构建目录...${NC}"
    rm -rf build
fi

# 创建构建目录
mkdir -p build
cd build

echo -e "${BLUE}配置CMake...${NC}"
cmake .. \
    -DCMAKE_BUILD_TYPE=Release \
    -DQt6_DIR="$Qt6_DIR" \
    -DCMAKE_PREFIX_PATH="$Qt6_DIR"

echo -e "${BLUE}开始编译...${NC}"
make -j$(nproc)

if [ $? -eq 0 ]; then
    echo -e "${GREEN}构建成功!${NC}"
    echo -e "${GREEN}可执行文件位置: $(pwd)/QtVPNClient${NC}"
else
    echo -e "${RED}构建失败!${NC}"
    exit 1
fi

# 创建发布包
echo -e "${BLUE}创建发布包...${NC}"
if [ "$OS" = "Linux" ]; then
    "$Qt6_DIR/bin/linuxdeployqt" QtVPNClient -appimage
elif [ "$OS" = "Mac" ]; then
    "$Qt6_DIR/bin/macdeployqt" QtVPNClient.app -dmg
fi

echo -e "${GREEN}构建完成!${NC}"

scripts/build.bat

@echo off
setlocal enabledelayedexpansion

echo Qt VPN Client Build Script
echo ===============================

REM 设置Qt路径
if "%Qt6_DIR%"=="" (
    set Qt6_DIR=C:\Qt\6.5.0\msvc2019_64
)

if not exist "%Qt6_DIR%" (
    echo 错误: Qt目录不存在: %Qt6_DIR%
    pause
    exit /b 1
)

set PATH=%Qt6_DIR%\bin;%PATH%
echo Qt路径: %Qt6_DIR%

REM 检查Visual Studio环境
if "%VCINSTALLDIR%"=="" (
    echo 正在设置Visual Studio环境...
    call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"
)

REM 清理旧的构建
if exist build (
    echo 清理旧的构建目录...
    rmdir /s /q build
)

REM 创建构建目录
mkdir build
cd build

echo 配置CMake...
cmake .. -DCMAKE_BUILD_TYPE=Release -DQt6_DIR=%Qt6_DIR% -G "Visual Studio 16 2019" -A x64

if errorlevel 1 (
    echo CMake配置失败!
    pause
    exit /b 1
)

echo 开始编译...
cmake --build . --config Release --parallel

if errorlevel 1 (
    echo 编译失败!
    pause
    exit /b 1
)

echo 创建发布包...
%Qt6_DIR%\bin\windeployqt.exe Release\QtVPNClient.exe

echo 构建完成!
echo 可执行文件位置: %CD%\Release\QtVPNClient.exe
pause

5. 部署脚本

scripts/deploy_android.sh

#!/bin/bash

echo "Android部署脚本"
echo "=================="

# 检查Android环境
if [ -z "$ANDROID_SDK_ROOT" ]; then
    echo "错误: 请设置 ANDROID_SDK_ROOT 环境变量"
    exit 1
fi

if [ -z "$ANDROID_NDK_ROOT" ]; then
    echo "错误: 请设置 ANDROID_NDK_ROOT 环境变量"
    exit 1
fi

# 设置Qt Android路径
Qt6_ANDROID_DIR="/opt/Qt/6.5.0/android_arm64_v8a"
if [ ! -d "$Qt6_ANDROID_DIR" ]; then
    echo "错误: Qt Android目录不存在: $Qt6_ANDROID_DIR"
    exit 1
fi

export PATH="$Qt6_ANDROID_DIR/bin:$PATH"

# 清理构建
rm -rf build-android
mkdir build-android
cd build-android

# 配置CMake for Android
cmake .. \
    -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake" \
    -DANDROID_ABI=arm64-v8a \
    -DANDROID_PLATFORM=android-23 \
    -DQt6_DIR="$Qt6_ANDROID_DIR" \
    -DCMAKE_BUILD_TYPE=Release

# 编译
make -j$(nproc)

# 打包APK
"$Qt6_ANDROID_DIR/bin/androiddeployqt" \
    --input android-libQtVPNClient.so-deployment-settings.json \
    --output android-build \
    --android-platform android-30 \
    --jdk "$JAVA_HOME" \
    --gradle

echo "Android APK构建完成!"
echo "APK位置: android-build/build/outputs/apk/debug/android-build-debug.apk"

6. 文档文件

docs/README.md

# Qt VPN Client

一个基于Qt和Xray核心的跨平台VPN客户端应用程序。

## 功能特性

- 🌍 跨平台支持 (Windows, macOS, Linux, iOS, Android)
- 🔒 VMess协议支持
- 🎨 现代化Qt用户界面
- 📊 实时流量监控
- 🔔 系统托盘集成
- 📁 配置导入导出
- 🌐 多语言支持
- 🔄 自动重连功能

## 系统要求

### 桌面平台
- **Windows**: Windows 10或更高版本
- **macOS**: macOS 10.15或更高版本  
- **Linux**: Ubuntu 18.04+, CentOS 7+或等效发行版

### 移动平台
- **Android**: Android 6.0 (API 23)或更高版本
- **iOS**: iOS 12.0或更高版本

### 开发要求
- Qt 6.5.0或更高版本
- CMake 3.16或更高版本
- C++17兼容编译器
- Xray核心文件

## 快速开始

### 1. 克隆项目
```bash
git clone https://github.com/your-repo/QtVPNClient.git
cd QtVPNClient

2. 安装依赖

# Linux
sudo apt install qt6-base-dev qt6-tools-dev cmake build-essential

# macOS
brew install qt@6 cmake

# Windows
# 下载并安装Qt 6.5.0和Visual Studio 2019+

3. 构建项目

# Linux/macOS
chmod +x scripts/build.sh
./scripts/build.sh

# Windows
scripts\build.bat

4. 运行应用

# Linux/macOS
./build/QtVPNClient

# Windows
build\Release\QtVPNClient.exe

配置说明

VMess配置格式

{
    "server": "example.com",
    "port": 443,
    "uuid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "security": "auto",
    "network": "tcp",
    "remarks": "My Server"
}

支持的导入格式

  • VMess URL (vmess://)
  • JSON配置文件
  • 文本配置

使用指南

  1. 配置服务器: 在”服务器配置”区域填入服务器信息
  2. 连接VPN: 点击”连接”按钮建立VPN连接
  3. 监控流量: 在”流量统计”区域查看实时数据
  4. 查看日志: 在”连接日志”区域查看连接状态
  5. 系统托盘: 最小化到系统托盘继续运行

开发指南

项目结构

src/
├── main.cpp              # 程序入口
├── mainwindow.*          # 主窗口实现
├── vpnmanager.*          # VPN连接管理
├── configparser.*        # 配置解析
└── ui/                   # UI文件

添加新功能

  1. 在相应的类中添加功能实现
  2. 更新UI文件(如需要)
  3. 添加单元测试
  4. 更新文档

编码规范

  • 使用Qt编码规范
  • 函数名使用camelCase
  • 类名使用PascalCase
  • 常量使用UPPER_CASE

故障排除

常见问题

Q: 连接失败怎么办? A: 检查服务器配置是否正确,确保网络连接正常,查看连接日志获取详细错误信息。

Q: 无法启动Xray核心? A: 确保Xray核心文件存在于系统PATH中,或放置在应用程序同目录下。检查文件权限,Linux/macOS需要执行权限。

Q: Android版本无法连接? A: 确保已授予所有必要权限,包括网络访问权限。某些Android版本可能需要额外配置。

Q: 流量统计不准确? A: 流量统计基于Xray API,确保API端口(10085)未被占用。

日志文件位置

  • Windows: %APPDATA%/VPN Client Team/Qt VPN Client/logs/
  • macOS: ~/Library/Application Support/VPN Client Team/Qt VPN Client/logs/
  • Linux: ~/.config/VPN Client Team/Qt VPN Client/logs/
  • Android: /Android/data/com.vpnclient.qt/files/logs/

贡献指南

欢迎贡献代码!请遵循以下步骤:

  1. Fork项目
  2. 创建特性分支 (git checkout -b feature/AmazingFeature)
  3. 提交更改 (git commit -m 'Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 开启Pull Request

许可证

本项目基于MIT许可证 – 查看 LICENSE 文件了解详情。

致谢

联系方式

  • 项目主页: https://github.com/your-repo/QtVPNClient
  • 问题反馈: https://github.com/your-repo/QtVPNClient/issues
  • 邮箱: support@vpnclient.com

### docs/BUILD.md
```markdown
# 构建指南

本文档详细说明如何在各个平台上构建Qt VPN Client。

## 开发环境准备

### 通用要求
- Qt 6.5.0或更高版本
- CMake 3.16+
- Git
- C++17编译器

### Windows
```powershell
# 安装Chocolatey(如果没有)
Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))

# 安装依赖
choco install cmake git visualstudio2019community

# 下载Qt 6.5.0
# 访问 https://www.qt.io/download 下载Qt在线安装器

macOS

# 安装Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 安装依赖
brew install qt@6 cmake git

# 设置环境变量
echo 'export PATH="/usr/local/opt/qt@6/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc

Linux (Ubuntu/Debian)

# 更新包列表
sudo apt update

# 安装依赖
sudo apt install -y \
    qt6-base-dev \
    qt6-tools-dev \
    qt6-l10n-tools \
    cmake \
    build-essential \
    git \
    pkg-config

# CentOS/RHEL
sudo yum groupinstall -y "Development Tools"
sudo yum install -y \
    qt6-qtbase-devel \
    qt6-qttools-devel \
    cmake \
    git

获取源码

git clone https://github.com/your-repo/QtVPNClient.git
cd QtVPNClient
git submodule update --init --recursive

平台特定构建

Windows构建

使用Visual Studio

# 设置环境
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat"

# 设置Qt路径
set Qt6_DIR=C:\Qt\6.5.0\msvc2019_64
set PATH=%Qt6_DIR%\bin;%PATH%

# 构建
mkdir build
cd build
cmake .. -G "Visual Studio 16 2019" -A x64 -DCMAKE_BUILD_TYPE=Release
cmake --build . --config Release --parallel

# 部署
%Qt6_DIR%\bin\windeployqt.exe Release\QtVPNClient.exe

使用MinGW

set Qt6_DIR=C:\Qt\6.5.0\mingw_64
set PATH=%Qt6_DIR%\bin;C:\Qt\Tools\mingw900_64\bin;%PATH%

mkdir build
cd build
cmake .. -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release
cmake --build . --parallel

%Qt6_DIR%\bin\windeployqt.exe QtVPNClient.exe

macOS构建

# 设置Qt路径
export Qt6_DIR="/usr/local/Qt-6.5.0"
export PATH="$Qt6_DIR/bin:$PATH"

# 构建
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.15
make -j$(sysctl -n hw.ncpu)

# 创建应用包
$Qt6_DIR/bin/macdeployqt QtVPNClient.app

# 创建DMG(可选)
$Qt6_DIR/bin/macdeployqt QtVPNClient.app -dmg

Linux构建

# 设置环境
export Qt6_DIR="/opt/Qt/6.5.0/gcc_64"  # 或系统Qt路径
export PATH="$Qt6_DIR/bin:$PATH"

# 构建
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)

# 创建AppImage(需要linuxdeployqt)
wget -c -nv "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage"
chmod a+x linuxdeployqt-continuous-x86_64.AppImage
./linuxdeployqt-continuous-x86_64.AppImage QtVPNClient -appimage

Android构建

# 设置Android环境
export ANDROID_SDK_ROOT="/path/to/android-sdk"
export ANDROID_NDK_ROOT="/path/to/android-ndk"
export JAVA_HOME="/path/to/jdk"

# 设置Qt Android
export Qt6_ANDROID_DIR="/opt/Qt/6.5.0/android_arm64_v8a"
export PATH="$Qt6_ANDROID_DIR/bin:$PATH"

# 构建
mkdir build-android
cd build-android

cmake .. \
    -DCMAKE_TOOLCHAIN_FILE="$ANDROID_NDK_ROOT/build/cmake/android.toolchain.cmake" \
    -DANDROID_ABI=arm64-v8a \
    -DANDROID_PLATFORM=android-23 \
    -DQt6_DIR="$Qt6_ANDROID_DIR" \
    -DCMAKE_BUILD_TYPE=Release

make -j$(nproc)

# 打包APK
$Qt6_ANDROID_DIR/bin/androiddeployqt \
    --input android-libQtVPNClient.so-deployment-settings.json \
    --output android-build \
    --android-platform android-30 \
    --gradle

iOS构建

# 设置Xcode环境
sudo xcode-select -s /Applications/Xcode.app/Contents/Developer

# 设置Qt iOS
export Qt6_IOS_DIR="/opt/Qt/6.5.0/ios"
export PATH="$Qt6_IOS_DIR/bin:$PATH"

# 构建
mkdir build-ios
cd build-ios

cmake .. \
    -DCMAKE_SYSTEM_NAME=iOS \
    -DCMAKE_OSX_DEPLOYMENT_TARGET=12.0 \
    -DQt6_DIR="$Qt6_IOS_DIR" \
    -DCMAKE_BUILD_TYPE=Release \
    -DCMAKE_OSX_ARCHITECTURES="arm64"

make -j$(sysctl -n hw.ncpu)

# 在Xcode中打开项目进行签名和部署
open QtVPNClient.xcodeproj

构建选项

CMake选项

# 启用调试模式
-DCMAKE_BUILD_TYPE=Debug

# 指定安装前缀
-DCMAKE_INSTALL_PREFIX=/usr/local

# 启用测试
-DBUILD_TESTING=ON

# 静态链接
-DBUILD_STATIC=ON

# 自定义Xray路径
-DXRAY_CORE_PATH=/path/to/xray

qmake构建(替代方案)

# 生成Makefile
qmake QtVPNClient.pro CONFIG+=release

# 编译
make -j$(nproc)  # Linux/macOS
nmake            # Windows

打包发布

Windows安装程序

# 使用NSIS
makensis installer.nsi

# 使用WiX Toolset
candle installer.wxs
light installer.wixobj

macOS PKG

productbuild --component QtVPNClient.app /Applications QtVPNClient.pkg

Linux包

DEB包

# 创建debian目录结构
mkdir -p debian/DEBIAN
mkdir -p debian/usr/local/bin
mkdir -p debian/usr/share/applications

# 复制文件
cp QtVPNClient debian/usr/local/bin/
cp platforms/linux/qtxrayvpn.desktop debian/usr/share/applications/

# 创建控制文件
cat > debian/DEBIAN/control << EOF
Package: qtxrayvpn
Version: 1.0.0
Section: net
Priority: optional
Architecture: amd64
Depends: libc6, libqt6core6, libqt6gui6, libqt6widgets6
Maintainer: VPN Client Team <support@vpnclient.com>
Description: Cross-platform VPN client based on Qt and Xray
EOF

# 构建DEB包
dpkg-deb --build debian qtxrayvpn_1.0.0_amd64.deb

RPM包

# 创建spec文件
cat > qtxrayvpn.spec << EOF
Name: qtxrayvpn
Version: 1.0.0
Release: 1%{?dist}
Summary: Cross-platform VPN client

License: MIT
URL: https://github.com/your-repo/QtVPNClient
Source0: %{name}-%{version}.tar.gz

BuildRequires: qt6-qtbase-devel, cmake, gcc-c++
Requires: qt6-qtbase, qt6-qttools

%description
A cross-platform VPN client based on Qt and Xray core.

%prep
%autosetup

%build
%cmake
%cmake_build

%install
%cmake_install

%files
%{_bindir}/qtxrayvpn
%{_datadir}/applications/qtxrayvpn.desktop
%{_datadir}/pixmaps/qtxrayvpn.png

%changelog
* $(date "+%a %b %d %Y") VPN Client Team <support@vpnclient.com> - 1.0.0-1
- Initial release
EOF

# 构建RPM
rpmbuild -ba qtxrayvpn.spec

持续集成

GitHub Actions配置

# .github/workflows/build.yml
name: Build

on: [push, pull_request]

jobs:
  build:
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]
        
    runs-on: ${{ matrix.os }}
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Install Qt
      uses: jurplel/install-qt-action@v3
      with:
        version: '6.5.0'
        
    - name: Configure CMake
      run: cmake -B build -DCMAKE_BUILD_TYPE=Release
      
    - name: Build
      run: cmake --build build --config Release
      
    - name: Test
      run: ctest --test-dir build -C Release
      
    - name: Package
      run: |
        if [ "${{ runner.os }}" == "Windows" ]; then
          windeployqt build/Release/QtVPNClient.exe
        elif [ "${{ runner.os }}" == "macOS" ]; then
          macdeployqt build/QtVPNClient.app -dmg
        else
          linuxdeployqt build/QtVPNClient -appimage
        fi

故障排除

常见构建错误

Qt not found

# 确保Qt路径正确
export Qt6_DIR=/path/to/qt6
export PATH="$Qt6_DIR/bin:$PATH"

CMake version too old

# 更新CMake
pip install cmake --upgrade

Missing dependencies

# 检查pkg-config
pkg-config --list-all | grep -i qt

# 安装缺失的包
sudo apt install qt6-*-dev

Android NDK not found

# 确保NDK路径正确
export ANDROID_NDK_ROOT=/path/to/ndk

清理构建

# 完全清理
rm -rf build build-*
git clean -xdf

# 重新开始
mkdir build && cd build
cmake .. && make

## 7. 翻译文件

### translations/qtxrayvpn_zh_CN.ts
```xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN">
<context>
    <name>MainWindow</name>
    <message>
        <source>Qt VPN Client</source>
        <translation>Qt VPN客户端</translation>
    </message>
    <message>
        <source>Connect</source>
        <translation>连接</translation>
    </message>
    <message>
        <source>Disconnect</source>
        <translation>断开</translation>
    </message>
    <message>
        <source>Connection Status</source>
        <translation>连接状态</translation>
    </message>
    <message>
        <source>Server Configuration</source>
        <translation>服务器配置</translation>
    </message>
    <message>
        <source>Traffic Statistics</source>
        <translation>流量统计</translation>
    </message>
    <message>
        <source>Connection Log</source>
        <translation>连接日志</translation>
    </message>
    <message>
        <source>Server:</source>
        <translation>服务器:</translation>
    </message>
    <message>
        <source>Port:</source>
        <translation>端口:</translation>
    </message>
    <message>
        <source>UUID:</source>
        <translation>UUID:</translation>
    </message>
    <message>
        <source>Security:</source>
        <translation>加密方式:</translation>
    </message>
    <message>
        <source>Remarks:</source>
        <translation>备注:</translation>
    </message>
    <message>
        <source>Upload:</source>
        <translation>上传:</translation>
    </message>
    <message>
        <source>Download:</source>
        <translation>下载:</translation>
    </message>
    <message>
        <source>Total:</source>
        <translation>总计:</translation>
    </message>
</context>
</TS>

8. 完整的资源文件

resources.qrc

<RCC>
    <qresource prefix="/">
        <file>icons/app_icon.png</file>
        <file>icons/connected.png</file>
        <file>icons/disconnected.png</file>
        <file>icons/connecting.png</file>
        <file>icons/error.png</file>
        <file>icons/settings.png</file>
        <file>icons/about.png</file>
        <file>icons/exit.png</file>
        <file>icons/import.png</file>
        <file>icons/export.png</file>
        <file>translations/qtxrayvpn_zh_CN.qm</file>
        <file>translations/qtxrayvpn_en_US.qm</file>
        <file>translations/qtxrayvpn_ja_JP.qm</file>
        <file>stylesheets/default.qss</file>
        <file>stylesheets/dark.qss</file>
    </qresource>
</RCC>

快速搭建指南

为了快速搭建这个项目,请按以下步骤操作:

1. 创建项目目录

mkdir QtVPNClient
cd QtVPNClient

2. 创建所有必要的文件

按照上述文档中的内容,创建相应的文件和目录结构。

3. 准备图标资源

icons/ 目录下放置所需的PNG图标文件:

  • app_icon.png (128×128)
  • connected.png (24×24)
  • disconnected.png (24×24)
  • connecting.png (24×24)
  • error.png (24×24)

4. 下载Xray核心

Xray Releases 下载对应平台的xray可执行文件,放置在 third_party/xray/ 目录下。

5. 构建项目

# 使用CMake
mkdir build && cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j$(nproc)

# 或使用qmake
qmake QtVPNClient.pro CONFIG+=release
make

这个完整的项目结构提供了:

  • 跨平台支持的CMake和qmake构建系统
  • 完整的Qt应用程序框架
  • 国际化支持
  • 平台特定的配置文件
  • 自动化构建和部署脚本
  • 详细的文档和使用指南

您可以基于这个框架快速搭建一个功能完整的VPN客户端应用程序。

关于Zeno Chen

本人涉及的领域较多,杂而不精 程序设计语言: Perl, Java, PHP, Python; 数据库系统: MySQL,Oracle; 偶尔做做电路板的开发,主攻STM32单片机
此条目发表在C/C++分类目录。将固定链接加入收藏夹。