diff --git a/BatteryQuick/BatteryQuick.pro b/BatteryQuick/BatteryQuick.pro index 1271e23..669a189 100644 --- a/BatteryQuick/BatteryQuick.pro +++ b/BatteryQuick/BatteryQuick.pro @@ -4,7 +4,7 @@ SOURCES += \ main.cc resources.files = Main.qml -resources.prefix = /qml +resources.prefix = /qt/qml/BatteryQuickResources RESOURCES += resources # Additional import path used to resolve QML modules in Qt Creator's code model diff --git a/BatteryQuick/CMakeLists.txt b/BatteryQuick/CMakeLists.txt index e2580ce..e3a2cbc 100644 --- a/BatteryQuick/CMakeLists.txt +++ b/BatteryQuick/CMakeLists.txt @@ -3,7 +3,7 @@ qt_add_executable(BatteryQuick main.cc) qt_add_qml_module( BatteryQuick URI - qml + BatteryQuickResources VERSION 1.0 QML_FILES @@ -23,3 +23,10 @@ set_target_properties( WIN32_EXECUTABLE TRUE) target_link_libraries(BatteryQuick PRIVATE Qt6::Quick) + +include(GNUInstallDirs) +install( + TARGETS BatteryQuick + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/BatteryQuick/main.cc b/BatteryQuick/main.cc index 0a43b3c..ad007cd 100644 --- a/BatteryQuick/main.cc +++ b/BatteryQuick/main.cc @@ -6,15 +6,14 @@ auto main(int argc, char *argv[]) -> int QGuiApplication app(argc, argv); QQmlApplicationEngine engine; - const QUrl url(u"qrc:/qml/Main.qml"_qs); + const QUrl url(QStringLiteral("qrc:/qt/qml/BatteryQuickResources/Main.qml")); QObject::connect( &engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { - if ((obj == nullptr) && url == objUrl) { + if (!obj && url == objUrl) QCoreApplication::exit(-1); - } }, Qt::QueuedConnection); engine.load(url); diff --git a/BubbleWindow/bubblewidget.cpp b/BubbleWindow/bubblewidget.cpp index 68edd29..6f5660c 100644 --- a/BubbleWindow/bubblewidget.cpp +++ b/BubbleWindow/bubblewidget.cpp @@ -137,6 +137,8 @@ void BubbleWidget::exec() void BubbleWidget::paintEvent(QPaintEvent *event) { + Q_UNUSED(event) + QPainter painter(this); painter.setRenderHint(QPainter::Antialiasing); painter.setPen(d_ptr->pen); diff --git a/CMakeLists.txt b/CMakeLists.txt index d71e411..ddfb17d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,7 +12,7 @@ project( include(cmake/common.cmake) find_package( - Qt6 REQUIRED + Qt6 6.5 REQUIRED COMPONENTS Core Widgets Charts @@ -21,8 +21,8 @@ find_package( Sql Quick) -qt_standard_project_setup(I18N_SOURCE_LANGUAGE en I18N_TRANSLATED_LANGUAGES - zh_CN) +qt_standard_project_setup(REQUIRES 6.5) +qt_policy(SET QTP0001 NEW) # qt_standard_project_setup will set CMAKE_RUNTIME_OUTPUT_DIRECTORY, we need to # set it back, and use EXECUTABLE_OUTPUT_PATH unset(CMAKE_RUNTIME_OUTPUT_DIRECTORY) diff --git a/Chart/datetimechart.cpp b/Chart/datetimechart.cpp index c5def72..51d6348 100644 --- a/Chart/datetimechart.cpp +++ b/Chart/datetimechart.cpp @@ -22,7 +22,7 @@ class DateTimeChart::DateTimeChartPrivate PointList pointList = generateRandomDataPoints(5, 101); int year = 2020; int mouth = 1; - for (const QPointF &p : qAsConst(pointList)) { + for (const QPointF &p : std::as_const(pointList)) { QDateTime momentInTime(QDate(year, mouth, 15), QTime()); scatterSeries->append(momentInTime.toMSecsSinceEpoch(), p.y()); lineSeries->append(momentInTime.toMSecsSinceEpoch(), p.y()); diff --git a/FlowLayout/flowlayout.cpp b/FlowLayout/flowlayout.cpp index 35e35e2..14a49f9 100644 --- a/FlowLayout/flowlayout.cpp +++ b/FlowLayout/flowlayout.cpp @@ -160,7 +160,7 @@ auto FlowLayout::sizeHint() const -> QSize auto FlowLayout::minimumSize() const -> QSize { QSize size; - for (const QLayoutItem *item : qAsConst(itemList)) + for (const QLayoutItem *item : std::as_const(itemList)) size = size.expandedTo(item->minimumSize()); const QMargins margins = contentsMargins(); @@ -181,7 +181,7 @@ auto FlowLayout::doLayout(const QRect &rect, bool testOnly) const -> int //! [9] //! [10] - for (QLayoutItem *item : qAsConst(itemList)) { + for (QLayoutItem *item : std::as_const(itemList)) { const QWidget *wid = item->widget(); int spaceX = horizontalSpacing(); if (spaceX == -1) diff --git a/FlowLayout/flowwidget.cc b/FlowLayout/flowwidget.cc index bb4ced1..2c97250 100644 --- a/FlowLayout/flowwidget.cc +++ b/FlowLayout/flowwidget.cc @@ -59,7 +59,7 @@ void FlowWidget::setItems(const QStringList &list) QList widgets = findChildren(); qDeleteAll(widgets); - for (const QString &text : qAsConst(list)) { + for (const QString &text : std::as_const(list)) { addItem(text); } } @@ -75,7 +75,7 @@ QStringList FlowWidget::items() const { QStringList list; QList widgets = findChildren(); - for (LabelWidget *widget : qAsConst(widgets)) { + for (LabelWidget *widget : std::as_const(widgets)) { list.append(widget->text()); } return list; diff --git a/GridViewModel/mainwindow.cpp b/GridViewModel/mainwindow.cpp index 6d60a4c..691f727 100644 --- a/GridViewModel/mainwindow.cpp +++ b/GridViewModel/mainwindow.cpp @@ -20,7 +20,7 @@ void MainWindow::setupUI() m_imageVector.clear(); auto colorNames = QColor::colorNames(); - for (const QString &colorName : qAsConst(colorNames)) { + for (const QString &colorName : std::as_const(colorNames)) { QImage image(WIDTH, WIDTH, QImage::Format_ARGB32); image.fill(Qt::transparent); QPainter painter(&image); diff --git a/ImageCarousel/imagecarousel.cc b/ImageCarousel/imagecarousel.cc index 1b14692..6846889 100644 --- a/ImageCarousel/imagecarousel.cc +++ b/ImageCarousel/imagecarousel.cc @@ -57,7 +57,7 @@ auto ImageCarousel::addImage(const QString &filename) -> bool auto ImageCarousel::addImages(const QStringList &filenames) -> int { int count = 0; - for (const auto &filename : qAsConst(filenames)) { + for (const auto &filename : std::as_const(filenames)) { if (addImage(filename)) { ++count; } @@ -67,7 +67,7 @@ auto ImageCarousel::addImages(const QStringList &filenames) -> int void ImageCarousel::clearImages() { - for (auto item : qAsConst(d_ptr->items)) { + for (auto item : std::as_const(d_ptr->items)) { scene()->removeItem(item); delete item; } diff --git a/LogAsynchronous/LogAsynchronous.pro b/LogAsynchronous/LogAsynchronous.pro index 3afefa3..9ca9974 100644 --- a/LogAsynchronous/LogAsynchronous.pro +++ b/LogAsynchronous/LogAsynchronous.pro @@ -1,6 +1,4 @@ -QT += core gui concurrent - -greaterThan(QT_MAJOR_VERSION, 4): QT += widgets +QT += core gui concurrent widgets CONFIG += c++17 diff --git a/LogAsynchronous/mainwindow.cpp b/LogAsynchronous/mainwindow.cpp index 22d4686..2db3a6c 100644 --- a/LogAsynchronous/mainwindow.cpp +++ b/LogAsynchronous/mainwindow.cpp @@ -30,6 +30,7 @@ MainWindow::~MainWindow() m_watcher.cancel(); m_watcher.waitForFinished(); } + LogAsync::instance()->stop(); qDebug() << "Stop Log!"; } @@ -39,8 +40,9 @@ void MainWindow::testLog() timer.start(); for (int i = 0; i < 1000; i++) { - if (!m_running) + if (!m_running) { break; + } qInfo() << "1234567890qwertyuiopasdfghjklzxcvbnm" << i; QThread::msleep(1); //主界面无响应,上下文切换太快 } diff --git a/README.md b/README.md index b071317..a3f4912 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,16 @@ ## [QT实用小技巧(想到就更新) | 自由意志 (realchuan.github.io)](https://realchuan.github.io/2021/10/12/QT%E5%AE%9E%E7%94%A8%E5%B0%8F%E6%8A%80%E5%B7%A7%EF%BC%88%E6%83%B3%E5%88%B0%E5%B0%B1%E6%9B%B4%E6%96%B0%EF%BC%89/) -## [Battery](/Battery/)——电池控件 +## [Battery](Battery/)——电池控件 - - - - - -
+
+ + +
-## [BatteryQuick](/BatteryQuick/)--电池控件(`QtQuick`) +## [BatteryQuick](BatteryQuick/)--电池控件(`QtQuick`) -## [Bootstarp](/Bootstarp/)--程序开机自启动设置和检测 +## [Bootstarp](Bootstarp/)--程序开机自启动设置和检测 1. Windows下读写注册表实现开机自启动,有两个位置可以写入; @@ -32,46 +30,64 @@ 2. systemctl命令用于.timer文件,.timer文件用于定时执行.service文件,防止图形界面启动后,出现qxcbconnection: could not connect to display错误; 2. 把/usr/share/Application/下的.desktop文件拷贝到~/.config/autostart/下,实现开机自启动(未验证); -## [BubbleWindow](/BubbleWindow/)——气泡式对话框,也可作工具提示(ToolTip) +## [BubbleWindow](BubbleWindow/)——气泡式对话框,也可作工具提示(ToolTip) -
+
+ +
## [Chart](Chart/)——可视化图表绘制,参考[使用 QChart 显示实时动态曲线](https://qtdebug.com/qtbook-paint-realtime-curve-qchart/ "qtdebug/公孙二狗") 和QChart相关示例 -
图一二是动态曲线
-
图一二是动态曲线, 图二坐标轴也会动态变化
+
+ +
图一、二动态曲线
+ +
图二坐标轴也会滚动
+
-## [CheckBoxStandardItem](/CheckBoxStandardItem/)——可以勾选的StandardItem,而且根据勾选状态自动更新父节点状态或者子节点状态 +## [CheckBoxStandardItem](CheckBoxStandardItem/)——可以勾选的StandardItem,而且根据勾选状态自动更新父节点状态或者子节点状态 -
+
+ +
-## [Clock](/Clock/)——时钟 +## [Clock](Clock/)——时钟 -
+
+ +
-## [DashBoard](/DashBoard/)——仪表盘 +## [DashBoard](DashBoard/)——仪表盘 -
+
+ +
-## [FlowLayout](/FlowLayout/)——流式布局,来自QT示例Flow Layout Example +## [FlowLayout](FlowLayout/)——流式布局,来自QT示例Flow Layout Example -
+
+ +
-## [DragDrop](/DragDrop/)——简单控件拖拽,参考QT示例Drag and Drop Puzzle Example +## [DragDrop](DragDrop/)——简单控件拖拽,参考QT示例Drag and Drop Puzzle Example -## [HttpClient](/HttpClient/)——http客户端 +## [HttpClient](HttpClient/)——http客户端 -## [IconButton](/IconButton/)——支持Icon跟随状态切换的EventFilter和Button +## [IconButton](IconButton/)——支持Icon跟随状态切换的EventFilter和Button -## [ImageCarousel](/ImageCarousel/)——简易图片轮播 +## [ImageCarousel](ImageCarousel/)——简易图片轮播 -
+
+ +
-## [GridViewModel](/GridViewModel/)——基于QListView的自适应宫图 +## [GridViewModel](GridViewModel/)——基于QListView的自适应宫图 -
+
+ +
-## [LogAsynchronous](/LogAsynchronous/)——异步日志,开辟一个线程专门往文件里写日志,前后端分离 +## [LogAsynchronous](LogAsynchronous/)——异步日志,开辟一个线程专门往文件里写日志,前后端分离 1. 日志文件名:应用程序名(appname).时间(time,精确到秒).主机hostname.进程ID(Tid).log(.count),假如一天内写的单个日志大约接近1G,会自动加后缀(.1,.2.3...,以此类推)新建新的日志文件去写,每天0点依然会rollFile; 1. 正常文件名:LogAsynchronous.2020-04-26-20-29-03.Youth.11828.log; @@ -80,51 +96,53 @@ 1. 比如:2020-04-26 20:38:55.818 2052 [Debug] 123456789qwertyuioplkjhgfdsa 8412789-File:(..\logAsynchronous\main.cpp) Line:(19); 3. [Qt-App](https://github.com/RealChuan/Qt-App/blob/main/src/utils/logasync.h),这个项目中也有对日志的封装,与本项目的代码大致一致,由于两个项目更新频率可能不同,建议在查看日志模块时,同时检查[Qt-App](https://github.com/RealChuan/Qt-App/blob/main/src/utils/logasync.h)的最新更新。 -## [MulClient](/MulClient/)——多线程客户端,一个线程一个客户端(怎么可以绕开系统限制,模拟百万个客户端) +## [MulClient](MulClient/)——多线程客户端,一个线程一个客户端(怎么可以绕开系统限制,模拟百万个客户端) -## [MulServer](/MulServer/)——多线程服务端,一个线程一个客户端处理(处理实时性很高的TCP通讯) +## [MulServer](MulServer/)——多线程服务端,一个线程一个客户端处理(处理实时性很高的TCP通讯) -## [NavigationProgressBar](/NavigationProgressBar/)——导航进度栏 +## [NavigationProgressBar](NavigationProgressBar/)——导航进度栏 -
+
+ +
-## [PasswordLineEdit](/PasswordLineEdit/)——密码输入框 +## [PasswordLineEdit](PasswordLineEdit/)——密码输入框 - - - - - -
+
+ + +
-## [ProgressArc](/ProgressArc/)——圆弧进度条 +## [ProgressArc](ProgressArc/)——圆弧进度条 -
+
+ +
-## [ProgressBar](/ProgressBar/)——QProgressBar圆角替代方案 +## [ProgressBar](ProgressBar/)——QProgressBar圆角替代方案 -
+
+ +
-## [ReactorServer](/ReactorServer/)——多线程服务端,Reactor模式(Echo) +## [ReactorServer](ReactorServer/)——多线程服务端,Reactor模式(Echo) -## [SimpleUdp](/SimpleUdp/)——简单UDP例子,广播和接收 +## [SimpleUdp](SimpleUdp/)——简单UDP例子,广播和接收 -## [ShowInMyComputer](/ShowInMyComputer/)——在我的电脑中显示当前应用程序 +## [ShowInMyComputer](ShowInMyComputer/)——在我的电脑中显示当前应用程序 防火墙白名单。 -## [SlipButton](/SlipButton/)——滑动按钮 +## [SlipButton](SlipButton/)——滑动按钮 - 另:更简单的实现:[有动画效果的 CheckBox](http://qtdebug.com/qtbook-animated-checkbox/); +> 另:更简单的实现:[有动画效果的 CheckBox](http://qtdebug.com/qtbook-animated-checkbox/); - - - - - -
+
+ + +
-## [SqliteWAL](/SqliteWAL/)——Sqlite WAL 模式下多线程并发写入数据库程序 +## [SqliteWAL](SqliteWAL/)——Sqlite WAL 模式下多线程并发写入数据库程序 ### WAL模式的优点 @@ -138,7 +156,7 @@ 2. 增加了磁盘使用量:与回滚模式相比,WAL模式需要更多的磁盘空间,因为它在提交更改之前将所有更改都写入日志文件; 3. 读取性能较慢:在WAL模式下,读取操作不会被写入操作阻塞,如果同时进行读取和写入操作,可能导致数据不一致。 -## [TableViewModel](/TableViewModel/)——表格视图 +## [TableViewModel](TableViewModel/)——表格视图 1. 各种自定义代理 1. [ButtonDelegate](./TableViewModel/buttondelegate.h); @@ -148,31 +166,30 @@ 5. [StarDelegate](./TableViewModel/stardelegate.h)----来自Qt示例Star Delegate Example; 2. 十万级数据渲染; -
+
+ +
-## [Thread](/Thread/)——多线程例子,6种写法 +## [Thread](Thread/)——多线程例子,6种写法 -## [TreeViewModel](/TreeViewModel/)——树形视图(MVC),QtCreator源码 +## [TreeViewModel](TreeViewModel/)——树形视图(MVC),QtCreator源码 -
-
+
+ + +
-## [Validator](/Validator/)——加强版IntValidator(QIntValidator)和DoubleValidator(QDoubleValidator) +## [Validator](Validator/)——加强版IntValidator(QIntValidator)和DoubleValidator(QDoubleValidator) -## [packaging](/packaging/)——打包脚本 +## [packaging](packaging/)——打包脚本 -1. [macos](/packaging/macos/)——macos qmake编译、打包dmg包脚本(`python`/`appdmg`); -2. [ubuntu](/packaging/ubuntu/)——ubuntu qmake编译、打包AppImage/deb包脚本(`linuxdeployqt-continuous-x86_64.AppImage`/`dpkg-deb`); - 1. [使用root权限打开应用程序的一种方法](/packaging/ubuntu/opt/MyApp/MyApp.sh): - - ```shell - #!/bin/sh - pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY /opt/MyApp/MyApp - ``` - -3. [windows](/packaging/windows/)——windows qmake编译、打包安装脚本(`Innosetup`); - 1. `Innosetup` `signtool` - - ``` - sha256="C:\\Program Files (x86)\\Windows Kits\\10\\bin\\10.0.18362.0\\x86\\signtool.exe" sign /f C:\\certificate\\certificate.pfx /p password /fd SHA256 /tr http://timestamp.digicert.com/scripts/timestamp.dll /td SHA256 $f - ``` +1. [macos](packaging/macos/) + 1. [`qmake`](packaging/macos/build.py) 编译; + 2. 打包pkg和dmg包并签名(`python`/`appdmg`),具体可以参考[Qt-App](https://github.com/RealChuan/Qt-App/tree/main/packaging/macos); +2. [ubuntu](packaging/ubuntu/) + 1. [`qmake`](packaging/ubuntu/build.py) 编译; + 2. 打包deb包可以参考[Qt-App](https://github.com/RealChuan/Qt-App/tree/main/packaging/ubuntu); +3. [windows](packaging/windows/) + 1. [`qmake`](packaging/windows/build.py) 编译; + 2. [`signtool`](packaging/windows/sign.bat) 签名; + 3. Inno Setup打包可以参考[Qt-App](https://github.com/RealChuan/Qt-App/tree/main/packaging/windows),签名的话可以把[sign.bat](packaging/windows/sign.bat)中的签名脚本复制到Inno Setup工具中的`Tools`->`Configure Sign Tools`,然后在需要的文件后加上sign flags; diff --git a/SimpleUdp/sendthread.cc b/SimpleUdp/sendthread.cc index 4ece87d..53f1e9e 100644 --- a/SimpleUdp/sendthread.cc +++ b/SimpleUdp/sendthread.cc @@ -45,9 +45,9 @@ void SendThread::run() while (d_ptr->runing && loop > 0) { const QByteArray buf = "Hello " + QByteArray::number(loop); QList interfaceList = QNetworkInterface::allInterfaces(); - for (const QNetworkInterface &interface : qAsConst(interfaceList)) { + for (const QNetworkInterface &interface : std::as_const(interfaceList)) { QList entryList = interface.addressEntries(); - for (const QNetworkAddressEntry &entry : qAsConst(entryList)) { + for (const QNetworkAddressEntry &entry : std::as_const(entryList)) { const QHostAddress broadcastAdress = entry.broadcast(); if (broadcastAdress == QHostAddress::Null || broadcastAdress == QHostAddress::LocalHost) { diff --git a/TreeViewModel/fileitem.cc b/TreeViewModel/fileitem.cc index a69c1db..be3139e 100644 --- a/TreeViewModel/fileitem.cc +++ b/TreeViewModel/fileitem.cc @@ -21,7 +21,7 @@ FileItem::FileItem(const QFileInfo &fileInfo, bool depth) .entryInfoList(QDir::AllEntries | QDir::Hidden | QDir::NoDotAndDotDot, QDir::DirsFirst); //qDebug() << fileInfo.absoluteFilePath(); - for (const auto &item : qAsConst(itemList)) { + for (const auto &item : std::as_const(itemList)) { appendChild(new FileItem(item, depth)); } } diff --git a/TreeViewModel/listview.cc b/TreeViewModel/listview.cc index bfe384a..50ee63a 100644 --- a/TreeViewModel/listview.cc +++ b/TreeViewModel/listview.cc @@ -38,7 +38,7 @@ void ListView::onSelectionChanged(const QItemSelection &selected, const QItemSel { //qDebug() << selected << deselected; const QModelIndexList selectedList(selected.indexes()); - for (auto index : qAsConst(selectedList)) { + for (auto index : std::as_const(selectedList)) { if (!index.isValid()) { continue; } @@ -50,7 +50,7 @@ void ListView::onSelectionChanged(const QItemSelection &selected, const QItemSel } const QModelIndexList deselectedList(deselected.indexes()); - for (auto index : qAsConst(deselectedList)) { + for (auto index : std::as_const(deselectedList)) { if (!index.isValid()) { continue; } @@ -66,6 +66,8 @@ void ListView::onSelectionChanged(const QItemSelection &selected, const QItemSel void ListView::onDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { + Q_UNUSED(bottomRight) + if (!topLeft.isValid()) { return; } diff --git a/TreeViewModel/normaltreeview.cc b/TreeViewModel/normaltreeview.cc index d294bc1..7c73d55 100644 --- a/TreeViewModel/normaltreeview.cc +++ b/TreeViewModel/normaltreeview.cc @@ -19,7 +19,7 @@ void NormalTreeModel::setDatas(const QFileInfoList &fileInfos, bool depth) { clear(); TreeItem *root = rootItem(); - for (const auto &fileInfo : qAsConst(fileInfos)) { + for (const auto &fileInfo : std::as_const(fileInfos)) { root->appendChild(new FileItem(fileInfo, depth)); } @@ -34,6 +34,8 @@ auto NormalTreeModel::rowCount(const QModelIndex &idx) const -> int auto NormalTreeModel::headerData(int section, Qt::Orientation orientation, int role) const -> QVariant { + Q_UNUSED(orientation) + switch (role) { case Qt::TextAlignmentRole: return Qt::AlignVCenter; case Qt::CheckStateRole: { diff --git a/TreeViewModel/normaltreeview.hpp b/TreeViewModel/normaltreeview.hpp index 58a65a6..e5c610b 100644 --- a/TreeViewModel/normaltreeview.hpp +++ b/TreeViewModel/normaltreeview.hpp @@ -21,6 +21,7 @@ class NormalTreeModel : public BaseTreeModel protected: [[nodiscard]] auto columnCount(const QModelIndex &idx) const -> int override { + Q_UNUSED(idx) return m_headerList.size(); } [[nodiscard]] auto headerData(int section, Qt::Orientation orientation, int role) const diff --git a/TreeViewModel/treeview.cc b/TreeViewModel/treeview.cc index 8d09f2f..38c3958 100644 --- a/TreeViewModel/treeview.cc +++ b/TreeViewModel/treeview.cc @@ -16,7 +16,7 @@ auto TreeView::selectedIndexes() const -> QModelIndexList { QModelIndexList indexList(QTreeView::selectedIndexes()); QModelIndexList list; - for (const auto &index : qAsConst(indexList)) { + for (const auto &index : std::as_const(indexList)) { QModelIndex i(index.siblingAtColumn(0)); if (list.contains(i)) { continue; diff --git a/packaging/macos/build.py b/packaging/macos/build.py index 0f49618..a4b5bff 100644 --- a/packaging/macos/build.py +++ b/packaging/macos/build.py @@ -5,11 +5,11 @@ build_list = [ { - "qmake": r"/Users/runner/Qt/6.7.0/macos/bin/qmake", - "qmake_params": r'"CONFIG+=qml_debug"', + "qmake": r"/Users/runner/Qt/6.7.0/clang_64/bin/qmake", + "qmake_params": r'"CONFIG+=qtquickcompiler"', "make": r"make", - "project": r"/Users/runner/myapp/MyApp.pro", - "build_directory": r"/Users/runner/myapp/build-MyApp-Desktop_Qt_6_7_0_macos_64bit-Release", + "project": r"/Users/runner/code/Qt-App/Qt-App.pro", + "build_directory": r"/Users/runner/code/Qt-App/build/Desktop_Qt_6_7_0_clang_64bit-Release", } ] diff --git a/packaging/macos/distribution.xml b/packaging/macos/distribution.xml new file mode 100644 index 0000000..fbcca51 --- /dev/null +++ b/packaging/macos/distribution.xml @@ -0,0 +1,31 @@ + + + Qt-App + org.youth + + + + + + + tmp.pkg + + + + + + + + + + + + \ No newline at end of file diff --git a/packaging/macos/dmg.json b/packaging/macos/dmg.json index e97a468..bb6c4cd 100644 --- a/packaging/macos/dmg.json +++ b/packaging/macos/dmg.json @@ -1,5 +1,5 @@ { - "title": "MyApp", + "title": "Qt-App", "icon-size": 100, "background": "", "icon": "app.icns", @@ -19,7 +19,7 @@ "x": 200, "y": 180, "type": "file", - "path": "MyApp.app" + "path": "Qt-App.app" }, { "x": 400, diff --git a/packaging/macos/package.py b/packaging/macos/package.py index 1f8c0c5..cb37684 100644 --- a/packaging/macos/package.py +++ b/packaging/macos/package.py @@ -1,77 +1,27 @@ +#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os import time -import build import sys - sys.path.append(sys.path[0] + "/../") import utils -def build_program(): - build.build(build.build_list) - - os.chdir(sys.path[0]) - build.execute("cp -af ./../../src/bin-64/release/MyApp.app/ ./../packet/MyApp.app/") - build.execute("rm -rf ./../releases/MyApp.app") - - -def deploy(program_path): - macdeployqt = r"/Users/runner/Qt/6.7.0/clang_64/bin/macdeployqt" - build.execute("{0} {1} -always-overwrite".format(macdeployqt, program_path)) - - -def sign(): - certificate = "Developer ID Application: ******(******)" - entitlements = "./entitlements.plist" - build.execute("plutil -convert xml1 {0}".format(entitlements)) - build.execute( - 'security unlock-keychain -p "password" "$HOME/Library/Keychains/login.keychain"' - ) - build.execute( - 'codesign --options=runtime --timestamp --deep --force --verify --verbose --sign "{0}" "{1}"'.format( - certificate, "./../releases/MyApp.app" - ) - ) - build.execute( - 'codesign --options=runtime --timestamp --force --verify --verbose --sign "{0}" --entitlements "{1}" "{2}"'.format( - certificate, - entitlements, - "./../releases/MyApp.app/Contents/Frameworks/QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/MacOS/QtWebEngineProcess", - ) - ) - build.execute( - 'codesign --options=runtime --timestamp --force --verify --verbose --sign "{0}" "{1}"'.format( - certificate, "./../releases/MyApp.app/Contents/MacOS/MyApp" - ) - ) - - -def build_dmg_and_upload(): +def rename_and_upload(): version = "0.0.1" current_time = time.strftime("%Y%m%d", time.localtime()) - dmg_name = "MyApp{0}_{1}.dmg".format(version, current_time) - out_dmg_path = "./../releases/{0}".format(dmg_name) - - build.execute("cp -f ./../../src/app.icns ./../releases/app.icns") - build.execute("cp -f ./dmg.json ./../releases/dmg.json") - build.execute("rm -f {0}".format(out_dmg_path)) - build.execute("appdmg ./../releases/dmg.json {0}".format(out_dmg_path)) + dmg_path = "{0}/../releases/Qt-App.dmg".format(sys.path[0]) + dmg_name = "Qt-App_{0}_{1}_x86_64.dmg".format(version, current_time) + out_dmg_path = "{0}/../releases/{1}".format(sys.path[0], dmg_name) + utils.removeFile(out_dmg_path) + os.rename(dmg_path, out_dmg_path) - build.execute( - """xcrun altool --notarize-app --primary-bundle-id "com.youth.myapp" --username "1070753498@qq.com" --password "password" --file {0}""".format( - out_dmg_path - ) - ) - - # generate update.json - json_path = "./../releases/update.json" + json_path = "{0}/../releases/update.json".format(sys.path[0]) utils.generate_json(version, out_dmg_path, dmg_name, json_path) - # upload file - base_url = "http://192.168.1.111:80/webdav/admin/Packages/MyApp/MacOS/" + base_url = "http://192.168.1.111:80/webdav/index.php/admin/packages/Qt-App/macos/" username = "admin" password = "password" utils.upload_file(base_url + dmg_name, username, password, out_dmg_path) @@ -79,20 +29,15 @@ def build_dmg_and_upload(): def main(): - build_program() - - os.chdir(sys.path[0]) - deploy(sys.path[0] + "/../packet/MyApp.app") - build.execute("cp -af ./../packet/MyApp.app ./../releases/MyApp.app") - sign() - build_dmg_and_upload() + rename_and_upload() if __name__ == "__main__": main() -# sudo spctl -vvv --assess --type execute /Applications/MyApp.app + +# sudo spctl -vvv --assess --type execute /Applications/Qt-App.app # 输出如下: -# /Applications/MyApp.app: accepted +# /Applications/Qt-App.app: accepted # source=Notarized Developer ID # origin=Developer ID Application: ******(******) diff --git a/packaging/macos/package.sh b/packaging/macos/package.sh new file mode 100644 index 0000000..2102b13 --- /dev/null +++ b/packaging/macos/package.sh @@ -0,0 +1,96 @@ +#!/bin/bash -ex + +cd "$(dirname "$0")" +source utils.sh + +cd ../.. +project_root=$PWD +echo "Project root: ${project_root}" + +echo "Start compiling..." +qmake="/Users/runner/Qt/6.7.0/clang_64/bin/qmake" +build_dir="${project_root}/build/Desktop_Qt_6_7_0_clang_64bit-Release" + +rm -rf ${build_dir} +mkdir -p ${build_dir} +cd ${build_dir} +${qmake} ${project_root} -spec macx-clang "CONFIG+=qtquickcompiler" +make -j $(sysctl -n hw.ncpu) +echo "Complied successfully" + +cd ${project_root} + +packet_dir="${project_root}/packaging/packet" +release_dir="${project_root}/packaging/releases" +mkdir -p ${packet_dir} +mkdir -p ${release_dir} + +cp -af -v ${project_root}/bin-64/Release/Qt-App.app ${packet_dir}/ +delete_file_or_dir "${release_dir}/Qt-App.app" + +# deploy Qt-App +macdeployqt="/Users/fxy/Qt/6.7.0/clang_64/bin/macdeployqt" +${macdeployqt} ${packet_dir}/Qt-App.app -always-overwrite +cp -af -v ${packet_dir}/Qt-App.app ${release_dir}/ + +# sign Qt-App +certificate="Developer ID Application: ******(******)" +entitlements="${project_root}/packaging/macos/entitlements.plist" +process_plist "${entitlements}" +security unlock-keychain -p "123456" "$HOME/Library/Keychains/login.keychain" +codesign --options=runtime --timestamp --deep --force --verify --verbose --sign \ + "${certificate}" ${release_dir}/Qt-App.app +sign_list=( + "${release_dir}/Qt-App.app/Contents/MacOS/CrashReport" +) +for item in ${sign_list[@]}; do + codesign --options=runtime --timestamp --force --verify --verbose --sign \ + "${certificate}" --entitlements ${entitlements} ${item} +done +codesign --options=runtime --timestamp --force --verify --verbose --sign \ + "${certificate}" "${release_dir}/Qt-App.app/Contents/MacOS/Qt-App" + +certificate="Developer ID Installer: ******(******)" +version="0.0.1" +pkg_name="Qt-App.pkg" +out_pkg_path="${release_dir}/${pkg_name}" +dmg_name="Qt-App.dmg" +out_dmg_path="${release_dir}/${dmg_name}" + +delete_file_or_dir "${release_dir}/output" +delete_file_or_dir "${out_pkg_path}" +delete_file_or_dir "${pkg_tmp_path}" +delete_file_or_dir "${out_dmg_path}" + +mkdir -p ${release_dir}/output + +# create pkg +mkdir -p ${packet_dir}/output +# process_plist "${project_dir}/packaging/macos/distribution.xml" +sudo chmod -R +x ${project_dir}/packaging/macos/scripts +pkgbuild --root ${release_dir}/Qt-App.app --identifier org.Qt-App.client \ + --version ${version} \ + --scripts ${project_root}/packaging/macos/scripts \ + --ownership recommended ${release_dir}/output/output2.pkg \ + --install-location /Applications/Qt-App.app +pkg_tmp_path="${release_dir}/final.pkg" +productbuild --distribution ${project_root}/packaging/macos/distribution.xml \ + --resources resources --package-path ${release_dir}/output \ + --version ${version} ${pkg_tmp_path} +# sign pkg +productsign --sign "${certificate}" ${pkg_tmp_path} ${out_pkg_path} +delete_file_or_dir "${pkg_tmp_path}" +notarize_app "${out_pkg_path}" + +# install appdmg +brew install npm +npm install -g appdmg + +# create dmg +cp -f -v ${project_root}/src/apps/Qt-App/logo.icns ${release_dir}/app.icns +cp -f -v ${project_root}/packaging/macos/dmg.json ${release_dir}/dmg.json +appdmg ${release_dir}/dmg.json ${out_dmg_path} +notarize_app "${out_dmg_path}" + +cd "$(dirname "$0")" +./package.py diff --git a/packaging/macos/resources/conclusion.html b/packaging/macos/resources/conclusion.html new file mode 100644 index 0000000..aa955bc --- /dev/null +++ b/packaging/macos/resources/conclusion.html @@ -0,0 +1 @@ +The Qt-App has been successfully installed. \ No newline at end of file diff --git a/packaging/macos/resources/welcome.html b/packaging/macos/resources/welcome.html new file mode 100644 index 0000000..1be7887 --- /dev/null +++ b/packaging/macos/resources/welcome.html @@ -0,0 +1 @@ +Welcome to the installation of Qt-App 0.0.1. Please press continue to proceed with the installation. \ No newline at end of file diff --git a/packaging/macos/scripts/postinstall b/packaging/macos/scripts/postinstall new file mode 100644 index 0000000..82b1303 --- /dev/null +++ b/packaging/macos/scripts/postinstall @@ -0,0 +1,5 @@ +#!/bin/sh -ex + +echo "Postinstall script is not implemented for macOS." + +exit 0 diff --git a/packaging/macos/scripts/preinstall b/packaging/macos/scripts/preinstall new file mode 100644 index 0000000..549f7ee --- /dev/null +++ b/packaging/macos/scripts/preinstall @@ -0,0 +1,8 @@ +#!/bin/sh -ex + +echo "Preinstall script is not implemented for macOS." + +sudo killall -9 Qt-App || true +sudo killall -9 CrashReport || true + +exit 0 diff --git a/packaging/macos/utils.sh b/packaging/macos/utils.sh new file mode 100644 index 0000000..bcf4cda --- /dev/null +++ b/packaging/macos/utils.sh @@ -0,0 +1,56 @@ +#!/bin/bash -ex + +delete_file_or_dir() { + local target=$1 + + if [ -e "$target" ]; then + if [ -d "$target" ]; then + rm -rf "$target" + echo "Directory deleted: $target" + else + rm "$target" + echo "File deleted: $target" + fi + else + echo "Error: $target does not exist." + fi +} + +process_plist() { + local plist_path="$1" + + if [ -z "$plist_path" ]; then + echo "Error: Plist file path is not provided." + return 1 + fi + + if [ ! -f "$plist_path" ]; then + echo "Error: Plist file does not exist at path: $plist_path" + return 1 + fi + + echo "Converting plist to XML format..." + plutil -convert xml1 "$plist_path" 2>/dev/null + + echo "Linting plist file..." + plutil -lint "$plist_path" 2>/dev/null + + if [ $? -eq 0 ]; then + echo "Plist file processed successfully." + else + echo "Error occurred while processing plist file." + return 2 + fi +} + +notarize_app() { + local target=$1 + if [ ! -f "$target" ]; then + echo "Error: $target does not exist." + exit 1 + fi + + xcrun notarytool submit $target --apple-id "***@***" \ + --team-id "******" --password "******" --wait + xcrun stapler staple $target +} diff --git a/packaging/ubuntu/DEBIAN/control b/packaging/ubuntu/DEBIAN/control deleted file mode 100644 index f8e8757..0000000 --- a/packaging/ubuntu/DEBIAN/control +++ /dev/null @@ -1,5 +0,0 @@ -Package: myapp -Version: 0.0.1 -Architecture: amd64 -Description: myapp -Maintainer: 1070753498@qq.com diff --git a/packaging/ubuntu/DEBIAN/postinst b/packaging/ubuntu/DEBIAN/postinst deleted file mode 100644 index 5b22f06..0000000 --- a/packaging/ubuntu/DEBIAN/postinst +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -chmod 744 /opt/MyApp/MyApp.desktop -cp -f /opt/MyApp/MyApp.desktop /usr/share/applications/MyApp.desktop - -exit 0 diff --git a/packaging/ubuntu/DEBIAN/postrm b/packaging/ubuntu/DEBIAN/postrm deleted file mode 100644 index 961005d..0000000 --- a/packaging/ubuntu/DEBIAN/postrm +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh - -rm -f /usr/share/applications/MyApp.desktop - -if ["$1" = "purge"]; then - rm -rf ~/.config/MyApp -fi - -exit 0 diff --git a/packaging/ubuntu/DEBIAN/preinst b/packaging/ubuntu/DEBIAN/preinst deleted file mode 100644 index a06fd1d..0000000 --- a/packaging/ubuntu/DEBIAN/preinst +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -killall -q MyApp - -exit 0 diff --git a/packaging/ubuntu/DEBIAN/prerm b/packaging/ubuntu/DEBIAN/prerm deleted file mode 100644 index b04482b..0000000 --- a/packaging/ubuntu/DEBIAN/prerm +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -killall -q MyApp - -rm -f /usr/share/applications/MyApp.desktop - -exit 0 diff --git a/packaging/ubuntu/build.py b/packaging/ubuntu/build.py index d270aaa..4e1fbce 100644 --- a/packaging/ubuntu/build.py +++ b/packaging/ubuntu/build.py @@ -5,11 +5,11 @@ build_list = [ { - "qmake": r"/opt/Qt/6.7.0/gcc_64/bin/qmake", + "qmake": r"/opt/Qt/5.15.2/gcc_64/bin/qmake", "qmake_params": r'"CONFIG+=qtquickcompiler"', "make": r"make", - "project": r"/home/runner/myapp/MyApp.pro", - "build_directory": r"/home/runner/myapp/build-MyApp-Desktop_Qt_6_7_0_GCC_64bit-Release", + "project": r"/home/runner/work/code/Qt-App/Qt-App.pro", + "build_directory": r"/home/runner/work/code/Qt-App/build/Desktop_Qt_6_7_0_clang_64bit-Release", } ] diff --git a/packaging/ubuntu/opt/MyApp/MyApp.desktop b/packaging/ubuntu/opt/MyApp/MyApp.desktop deleted file mode 100644 index c1e7345..0000000 --- a/packaging/ubuntu/opt/MyApp/MyApp.desktop +++ /dev/null @@ -1,8 +0,0 @@ -[Desktop Entry] -Type=Application -Categories=Utility; -Name=MyApp -Exec=/opt/MyApp/MyApp %F -Icon=/opt/MyApp/logo.png -Comment=Edit this default file -Terminal=false diff --git a/packaging/ubuntu/opt/MyApp/MyApp.sh b/packaging/ubuntu/opt/MyApp/MyApp.sh deleted file mode 100644 index 2c0253d..0000000 --- a/packaging/ubuntu/opt/MyApp/MyApp.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -pkexec env DISPLAY=$DISPLAY XAUTHORITY=$XAUTHORITY /opt/MyApp/MyApp diff --git a/packaging/ubuntu/package.py b/packaging/ubuntu/package.py deleted file mode 100644 index 8171899..0000000 --- a/packaging/ubuntu/package.py +++ /dev/null @@ -1,74 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import time -import build -import sys - - -sys.path.append(sys.path[0] + "/../") -import utils - - -def build_program(): - build.build(build.build_list) - - os.chdir(sys.path[0]) - copy_exe_cmd = r"cp -rf ./../../code/bin-64/release/. ./../packet/opt/MyApp/" - build.execute(copy_exe_cmd) - copy_exe_cmd = r"cp -rf ./DEBIAN ./../packet/" - build.execute(copy_exe_cmd) - copy_exe_cmd = r"cp -rf ./opt ./../packet/" - build.execute(copy_exe_cmd) - copy_exe_cmd = r"cp -f logo.png ./../packet/opt/MyApp/" - build.execute(copy_exe_cmd) - - -def deploy(): - build.execute( - "cd ./../packet/opt/MyApp/ \n" - "export LD_LIBRARY_PATH=/home/runner/work/code/myapp/code/bin-64/release/. \n" - "'/home/runner/下载/linuxdeployqt-continuous-x86_64.AppImage' MyApp -always-overwrite -no-translations -qmake=/opt/Qt/6.7.0/gcc_64/bin/qmake -unsupported-allow-new-glibc -appimage\n" - ) - - -def build_deb_and_upload(): - version = "0.0.1" - current_time = time.strftime("%Y%m%d", time.localtime()) - deb_name = "MyApp{0}_{1}.deb".format(version, current_time) - out_deb_path = "./../releases/{0}".format(deb_name) - - build.execute("sed -i '/X-AppImage-Version/d' ./../packet/opt/MyApp/MyApp.desktop") - build.execute("rm -f {0}".format(out_deb_path)) - build.execute( - "echo 123456 | sudo -S dpkg -b ./../packet/. {0}".format(out_deb_path) - ) - build.execute("sudo chmod -R 777 ./../releases/") - - # update.json uploadfile - json_path = "./../releases/update.json" - utils.generate_json(version, out_deb_path, deb_name, json_path) - - # upload file - base_url = "http://192.168.1.111:80/apps/wanyoucloud/index.php/61646D696E/admin/Packages/MyApp/Ubuntu/" - username = "admin" - password = "password" - utils.upload_file(base_url + deb_name, username, password, out_deb_path) - utils.upload_file(base_url + "update.json", username, password, json_path) - - -def main(): - build_program() - - os.chdir(sys.path[0]) - deploy() - build_deb_and_upload() - - -if __name__ == "__main__": - main() - - -# dpkg -r MyApp -# dpkg -i MyApp_0.0.1_20230810.deb -# dpkg -i --force-overwrite MyApp_0.0.1_20230810.deb diff --git a/packaging/utils.py b/packaging/utils.py index 92311c0..bb71797 100644 --- a/packaging/utils.py +++ b/packaging/utils.py @@ -5,6 +5,28 @@ import json import base64 import requests +import subprocess +import os +import shutil + + +def execute_bash(bash_path, command): + print(bash_path, command) + try: + result = subprocess.run([bash_path, "-c", command], text=True, check=True) + return result.stdout + except subprocess.CalledProcessError as e: + return f"An error occurred: {e.stderr}" + + +def removeFile(path): + if os.path.exists(path): + os.remove(path) + + +def removeDir(path): + if os.path.exists(path): + shutil.rmtree(path) def generate_json(version, md5_file_path, file_name, json_path): diff --git a/packaging/windows/build.py b/packaging/windows/build.py index deb4024..5ef2248 100644 --- a/packaging/windows/build.py +++ b/packaging/windows/build.py @@ -1,3 +1,6 @@ +# -*- coding: utf-8 -*- + + import os import datetime import subprocess @@ -8,9 +11,9 @@ "qmake": r"C:\Qt\6.7.0\msvc2019_64\bin\qmake.exe", "qmake_params": r'"CONFIG+=qtquickcompiler"', "jom": r"C:\Qt\Tools\QtCreator\bin\jom\jom.exe", - "env_bat": r'C:\"Program Files (x86)"\"Microsoft Visual Studio"\2019\Community\VC\Auxiliary\Build\vcvarsall.bat amd64_x86', - "project": r"C:\myapp\MyApp.pro", - "build_directory": r"C:\build-MyApp-Desktop_Qt_6_7_0_MSVC2019_64bit-Release", + "env_bat": r'C:\"Program Files (x86)"\"Microsoft Visual Studio"\2019\Community\VC\Auxiliary\Build\vcvarsall.bat x64', + "project": r"C:\code\qt-app\qt-app.pro", + "build_directory": r"C:\work\code\qt-app\build\Desktop_Qt_6_7_0_MSVC2019_64bit-Release", } ] @@ -24,6 +27,8 @@ def __init__(self, project, qmake, qmake_params, jom, env_bat, build_directory): self.env_bat = env_bat self.build_directory = build_directory + os.makedirs(build_directory, exist_ok=True) + (self.qmake_path, self.qmake_name) = os.path.split(qmake) (self.jom_path, self.jom_name) = os.path.split(jom) (self.project_path, self.project_name) = os.path.split(project) @@ -35,15 +40,15 @@ def execute_qmake_cmd_line(self): create_qmake_cmd_line = ( self.qmake + " " + self.project + " -spec win32-msvc " + self.qmake_params ) - return True if execute(create_qmake_cmd_line) else False + return True if execute_cmd(create_qmake_cmd_line) else False def execute_make_cmd_line(self): cmd_line = "{0}".format(self.jom) - return True if execute(cmd_line) else False + return True if execute_cmd(cmd_line) else False def execute_make_clean_cmd_line(self): if os.path.exists("Makefile") | os.path.exists("makefile"): - return True if execute("{0} clean".format(self.jom)) else False + return True if execute_cmd("{0} clean".format(self.jom)) else False return True def init_env(self): @@ -86,17 +91,6 @@ def build(self): return isOk -def execute(cmd): - print(cmd) - result = subprocess.run( - cmd, encoding="gbk", stdout=sys.stdout, stderr=sys.stderr, shell=True - ) - if result.returncode != 0: - print(result.stderr) - - return True if result.returncode == 0 else False - - def build(build_list): for each in build_list: qmake = each.get("qmake") @@ -114,6 +108,45 @@ def build(build_list): exit(-1) +def execute_cmd(cmd): + print(cmd) + result = subprocess.run( + cmd, encoding="gbk", stdout=sys.stdout, stderr=sys.stderr, shell=True + ) + if result.returncode != 0: + print(result.stderr) + + return True if result.returncode == 0 else False + + +def change_powershell_execution_policy(execution_policy): + subprocess.run( + [ + "powershell", + "-Command", + f"Set-ExecutionPolicy {execution_policy} -Scope CurrentUser -Force", + ] + ) + + +def execute_powershell(script_path, is_script): + print("Execute powershell script: {0}".format(script_path)) + change_powershell_execution_policy("Unrestricted") + if is_script: + command = f"& '{script_path}'" + else: + command = script_path + + proc = subprocess.Popen( + ["powershell", "-Command", command], + stdout=sys.stdout, + stderr=sys.stderr, + shell=True, + ) + + return proc.wait() + + if __name__ == "__main__": print("[{0}] Start deploy...".format(datetime.datetime.now())) build(build_list) diff --git a/packaging/windows/package.iss b/packaging/windows/package.iss deleted file mode 100644 index 5b1f780..0000000 --- a/packaging/windows/package.iss +++ /dev/null @@ -1,155 +0,0 @@ -; Script generated by the Inno Setup Script Wizard. -; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! - -#define MyAppName "MyApp" -#define MyAppVersion "0.0.1" -#define MyAppPublisher "Youth Co.,Ld." -#define MyAppURL "https://github.com/RealChuan" -#define MyAppExeName "MyApp.exe" -#define MyAppAssocName MyAppName + "" -#define MyAppAssocExt ".myp" -#define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt -#define MyAppUninstallName "Uninstall" - -[Setup] -; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications. -; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) -AppId={{2B7CC760-21EC-4184-890E-2E1766C6CE04} -AppName={#MyAppName} -AppVersion={#MyAppVersion} -;AppVerName={#MyAppName} {#MyAppVersion} -AppPublisher={#MyAppPublisher} -AppPublisherURL={#MyAppURL} -AppSupportURL={#MyAppURL} -AppUpdatesURL={#MyAppURL} -DefaultDirName={autopf}\{#MyAppName} -ChangesAssociations=yes -DisableProgramGroupPage=yes -; Uncomment the following line to run in non administrative install mode (install for current user only.) -;PrivilegesRequired=lowest -OutputDir=C:myapp\releases -OutputBaseFilename=MyApp_Installation_Package -SetupIconFile=C:\myapp\app.ico -Compression=lzma -SolidCompression=yes -WizardStyle=modern -MinVersion=6.1.7600 -DefaultGroupName={#MyAppName} -UninstallDisplayIcon=C:\myapp\app.ico -Uninstallable=yes -UninstallDisplayName={#MyAppName} -VersionInfoCompany={#MyAppPublisher} -VersionInfoCopyright={#MyAppPublisher} -VersionInfoDescription={#MyAppName} -VersionInfoOriginalFileName={#MyAppName} -VersionInfoProductTextVersion={#MyAppVersion} -VersionInfoProductVersion={#MyAppVersion} -VersionInfoTextVersion={#MyAppVersion} -SignTool = sha256 -SignedUninstaller = yes - -[Languages] -Name: "Chinese"; MessagesFile: "compiler:Languages\Chinese.isl" -Name: "english"; MessagesFile: "compiler:Default.isl" - -[Tasks] -Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkablealone - -[Files] -Source: "..\packet\{#MyAppExeName}"; DestDir: "{app}"; Flags: ignoreversion signonce -; NOTE: Don't use "Flags: ignoreversion" on any shared system files -Source: "..\packet\D3Dcompiler_47.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\packet\opengl32sw.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\packet\Qt6Core.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\packet\Qt6Gui.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\packet\Qt6Network.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\packet\Qt6Pdf.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\packet\Qt6Svg.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\packet\Qt6Widgets.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "..\packet\generic\*"; DestDir: "{app}\generic"; Flags: ignoreversion createallsubdirs recursesubdirs -Source: "..\packet\iconengines\*"; DestDir: "{app}\iconengines"; Flags: ignoreversion createallsubdirs recursesubdirs -Source: "..\packet\imageformats\*"; DestDir: "{app}\imageformats"; Flags: ignoreversion createallsubdirs recursesubdirs -Source: "..\packet\networkinformation\*"; DestDir: "{app}\networkinformation"; Flags: ignoreversion createallsubdirs recursesubdirs -Source: "..\packet\platforms\*"; DestDir: "{app}\platforms"; Flags: ignoreversion createallsubdirs recursesubdirs -Source: "..\packet\styles\*"; DestDir: "{app}\styles"; Flags: ignoreversion createallsubdirs recursesubdirs -Source: "..\packet\tls\*"; DestDir: "{app}\tls"; Flags: ignoreversion createallsubdirs recursesubdirs -Source: "..\packet\translations\*"; DestDir: "{app}\translations"; Flags: ignoreversion createallsubdirs recursesubdirs -Source: "..\packet\msvcr100.dll"; DestDir: "{app}"; Flags: ignoreversion -Source: "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Redist\MSVC\14.29.30133\x86\Microsoft.VC142.CRT\*"; DestDir: "{app}"; Flags: ignoreversion createallsubdirs recursesubdirs -Source: "C:\Program Files (x86)\Windows Kits\10\Redist\10.0.19041.0\ucrt\DLLs\x86\*"; DestDir: "{app}"; Flags: ignoreversion createallsubdirs recursesubdirs - -[Registry] -Root: "HKA"; Subkey: "Software\Classes\{#MyAppAssocExt}\OpenWithProgids"; ValueType: string; ValueName: "{#MyAppAssocKey}"; Flags: uninsdeletevalue -Root: "HKA"; Subkey: "Software\Classes\{#MyAppAssocKey}"; ValueType: string; ValueData: "{#MyAppAssocName}"; Flags: uninsdeletekey -Root: "HKA"; Subkey: "Software\Classes\{#MyAppAssocKey}\DefaultIcon"; ValueType: string; ValueData: "{app}\{#MyAppExeName},0" -Root: "HKA"; Subkey: "Software\Classes\{#MyAppAssocKey}\shell\open\command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1""" -Root: "HKA"; Subkey: "Software\Classes\Applications\{#MyAppExeName}\SupportedTypes"; ValueType: string; ValueName: ".myp" - -Root: "HKCU"; Subkey: "SOFTWARE\Classes\CLSID\{{2B7CC760-21EC-4184-890E-2E1766C6CE04}"; ValueType: string; ValueData: "{#MyAppName}"; Flags: uninsdeletekey -Root: "HKCU"; Subkey: "SOFTWARE\Classes\CLSID\{{2B7CC760-21EC-4184-890E-2E1766C6CE04}\DefaultIcon"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"""; Flags: uninsdeletekey -Root: "HKCU"; Subkey: "SOFTWARE\Classes\CLSID\{{2B7CC760-21EC-4184-890E-2E1766C6CE04}\shell\Open\Command"; ValueType: string; ValueData: """{app}\{#MyAppExeName}"" ""%1"""; Flags: uninsdeletekey -Root: "HKCU"; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\MyComputer\NameSpace\{{2B7CC760-21EC-4184-890E-2E1766C6CE04}"; ValueType: string; ValueData: "{#MyAppName}"; Flags: uninsdeletekey - -Root: "HKCU"; Subkey: "SOFTWARE\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "{#MyAppName}"; ValueData: """{app}\{#MyAppExeName}"""; Flags: uninsdeletevalue - -[Icons] -Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" -Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon -Name: "{group}\{#MyAppUninstallName}"; Filename: "{uninstallexe}" - -[Run] -Filename: "{sys}\netsh.exe"; Parameters: "advfirewall firewall delete rule name=""MyApp"" program=""{app}\{#MyAppExeName}"" "; Flags: runhidden; -Filename: "{sys}\netsh.exe"; Parameters: "advfirewall firewall add rule name=""MyApp"" program=""{app}\{#MyAppExeName}"" dir=in action=allow enable=yes"; Flags: runhidden; -Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent - -[UninstallDelete] -Type: filesandordirs; Name: "{localappdata}\MyApp" -Type: filesandordirs; Name: "{localappdata}\Youth Co.,Ld\MyApp" - -[Code] -procedure ExitProcess(exitCode:integer); - external 'ExitProcess@kernel32.dll stdcall'; - -function KDetectSoft(strExeName: String): Boolean; -var ErrorCode: Integer; -var bRes: Boolean; -var strFileContent: AnsiString; -var strTmpPath: String; -var strTmpFile: String; -var strCmdFind: String; -var strCmdKill: String; -begin - strTmpPath := GetTempDir(); - strTmpFile := Format('%sfindSoftRes.txt', [strTmpPath]); - strCmdFind := Format('/c tasklist /nh|find /c /i "%s" > "%s"', [strExeName, strTmpFile]); - strCmdKill := Format('/c taskkill /f /t /im %s', [strExeName]); - bRes := ShellExec('open', ExpandConstant('{cmd}'), strCmdFind, '', SW_HIDE, ewWaitUntilTerminated, ErrorCode); - if bRes then begin - bRes := LoadStringFromFile(strTmpFile, strFileContent); - strFileContent := Trim(strFileContent); - if bRes then begin - if StrToInt(strFileContent) > 0 then begin - ShellExec('open', ExpandConstant('{cmd}'), strCmdKill, '', SW_HIDE, ewNoWait, ErrorCode);; - Result:= true; - end else begin - Result:= true; - Exit; - end; - end; - end; - Result :=true; -end; - -function NextButtonClick(CurPageID: Integer): Boolean; -begin - if 1=CurPageID then begin - Result := KDetectSoft('MyApp.exe'); - Exit; - end; - Result:= true; -end; - -function InitializeUninstall(): Boolean; -begin - Result := KDetectSoft('MyApp.exe'); -end; diff --git a/packaging/windows/package.py b/packaging/windows/package.py deleted file mode 100644 index 749a03b..0000000 --- a/packaging/windows/package.py +++ /dev/null @@ -1,64 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import time -import build -import sys - - -sys.path.append(sys.path[0] + "/../") -import utils - - -def build_program(): - build.build(build.build_list) - - os.chdir(sys.path[0]) - build.execute('xcopy /s /y ".\\..\\..\\src\\bin-32\\release\\" ".\\..\\packet\\"') - - -def deploy(program_path): - windeployqt = r"C:\Qt\6.7.0\msvc2019_64\bin\windeployqt.exe" - deploy_cmd = ( - f'{windeployqt} --force --no-translations --compiler-runtime "{program_path}"' - ) - build.execute(deploy_cmd) - - -def package_iss(iss_path): - iscc_exe = r'"C:\Program Files (x86)\Inno Setup 6\ISCC.exe"' - package_cmd = f"{iscc_exe} {iss_path}" - build.execute(package_cmd) - - -def upload_file(): - version = "0.0.1" - current_time = time.strftime("%Y%m%d", time.localtime()) - exe_name = "MyApp_{0}_{1}.exe".format(version, current_time) - out_exe_path = ".\\..\\releases\\{0}".format(exe_name) - - build.execute("del /q {0}".format(out_exe_path)) - build.execute("del /q .\\..\\releases\\MyApp_Installation_Package.exe") - os.rename(".\\..\\releases\\MyApp_Installation_Package.exe", out_exe_path) - - # generate update.json - json_path = ".\\..\\releases\\update.json" - utils.generate_json(version, out_exe_path, exe_name, json_path) - - # upload file - base_url = "http://192.168.1.111:80/webdav/admin/Packages/MyApp/Windows/" - username = "admin" - password = "password" - utils.upload_file(base_url + exe_name, username, password, out_exe_path) - utils.upload_file(base_url + "update.json", username, password, json_path) - - -def main(): - build_program() - deploy(sys.path[0] + "/../packet/MyApp.exe") - package_iss(sys.path[0] + "/package.iss") - upload_file() - - -if __name__ == "__main__": - main() diff --git a/packaging/windows/sign.bat b/packaging/windows/sign.bat new file mode 100644 index 0000000..5651409 --- /dev/null +++ b/packaging/windows/sign.bat @@ -0,0 +1,9 @@ +set input=%1% + +set signtool="C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86\signtool.exe" + +@REM 指纹签名方式,需要在弹窗中输入证书密码 +%signtool% sign /tr "http://timestamp.digicert.com" /td sha256 /fd sha256 /sha1 "******" %1% + +@REM pfx 文件签名方式 +@REM %signtool% sign /f "C:\code\certificate\digicert.pfx" /p password /fd SHA256 /tr "http://timestamp.digicert.com/scripts/timestamp.dll" /td SHA256 %1%