项目目录结构
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>文件(&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>帮助(&H)</string>
</property>
<addaction name="actionAbout"/>
<addaction name="actionAboutQt"/>
</widget>
<widget class="QMenu" name="menuView">
<property name="title">
<string>视图(&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>导入配置(&I)</string>
</property>
<property name="shortcut">
<string>Ctrl+I</string>
</property>
</action>
<action name="actionExportConfig">
<property name="text">
<string>导出配置(&E)</string>
</property>
<property name="shortcut">
<string>Ctrl+E</string>
</property>
</action>
<action name="actionExit">
<property name="text">
<string>退出(&X)</string>
</property>
<property name="shortcut">
<string>Ctrl+Q</string>
</property>
</action>
<action name="actionAbout">
<property name="text">
<string>关于(&A)</string>
</property>
</action>
<action name="actionAboutQt">
<property name="text">
<string>关于Qt(&Q)</string>
</property>
</action>
<action name="actionShowLog">
<property name="text">
<string>显示日志(&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>置顶窗口(&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配置文件
- 文本配置
使用指南
- 配置服务器: 在”服务器配置”区域填入服务器信息
- 连接VPN: 点击”连接”按钮建立VPN连接
- 监控流量: 在”流量统计”区域查看实时数据
- 查看日志: 在”连接日志”区域查看连接状态
- 系统托盘: 最小化到系统托盘继续运行
开发指南
项目结构
src/
├── main.cpp # 程序入口
├── mainwindow.* # 主窗口实现
├── vpnmanager.* # VPN连接管理
├── configparser.* # 配置解析
└── ui/ # UI文件
添加新功能
- 在相应的类中添加功能实现
- 更新UI文件(如需要)
- 添加单元测试
- 更新文档
编码规范
- 使用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/
贡献指南
欢迎贡献代码!请遵循以下步骤:
- Fork项目
- 创建特性分支 (
git checkout -b feature/AmazingFeature
) - 提交更改 (
git commit -m 'Add some AmazingFeature'
) - 推送到分支 (
git push origin feature/AmazingFeature
) - 开启Pull Request
许可证
本项目基于MIT许可证 – 查看 LICENSE 文件了解详情。
致谢
- Qt Framework – 跨平台应用程序框架
- Xray-core – 网络代理工具
- V2Ray – 协议支持
联系方式
- 项目主页: 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客户端应用程序。