关于安装:Qt Installer Framework 离线更新 – 如何?

Qt Installer Framework Offline Update - how?

我已经能够为我的软件创建安装。但是,我不知道如何创建另一个可以更新以前安装的安装程序。

我已经更新了组件版本、软件版本和发布日期,但是每当我在带有预安装软件的文件夹上运行第二次安装时 - 我都会收到 The folder you selected already exists and contains an installation. Chose different target for installation.

非常欢迎任何有关如何使用 Qt 安装程序框架更新现有安装的提示!


我也遇到了同样的问题。所以我下载了最新的快照并研究了样本。一个特别有用的:dynamicpage

当用户选择现有位置时,我没有成功向用户显示弹出警告,所以我找到了一个解决方法:相反,在所选目录下显示一个红色标签。

这不是逐个更新组件的真正解决方案,但您将能够继续安装过程。

首先,我们需要替换默认页面"TargetDirectory"。

在文件 installerscript.qs 中,您需要添加以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
// Constructor
function Component()
{
    component.loaded.connect(this, Component.prototype.installerLoaded);
    installer.setDefaultPageVisible(QInstaller.TargetDirectory, false);
}

// Utility function like QString QDir::toNativeSeparators(const QString & pathName) [static]
var Dir = new function () {
    this.toNativeSparator = function (path) {
        if (installer.value("os") =="win")
            return path.replace(/\\//g, '\\\');
        return path;
    }
};

// Called as soon as the component was loaded
Component.prototype.installerLoaded = function()
{
    if (installer.addWizardPage(component,"TargetWidget", QInstaller.TargetDirectory)) {
        var widget = gui.pageWidgetByObjectName("DynamicTargetWidget");
        if (widget != null) {
            widget.targetDirectory.textChanged.connect(this, Component.prototype.targetChanged);
            widget.targetChooser.clicked.connect(this, Component.prototype.chooseTarget);

            widget.windowTitle ="Installation Folder";
            widget.targetDirectory.text = Dir.toNativeSparator(installer.value("TargetDir"));
        }
    }
}

// Callback when one is clicking on the button to select where to install your application
Component.prototype.chooseTarget = function () {
    var widget = gui.pageWidgetByObjectName("DynamicTargetWidget");
    if (widget != null) {
        var newTarget = QFileDialog.getExistingDirectory("Choose your target directory.", widget.targetDirectory.text);
        if (newTarget !="") {
            widget.targetDirectory.text = Dir.toNativeSparator(newTarget);
        }
    }
}

Component.prototype.targetChanged = function (text) {
    var widget = gui.pageWidgetByObjectName("DynamicTargetWidget");
    if (widget != null) {
        if (text !="") {
            widget.complete = true;
            installer.setValue("TargetDir", text);
            if (installer.fileExists(text +"/components.xml")) {
                var warning ="<font color='red'>" + qsTr("A previous installation exists in this folder. If you wish to continue, everything will be overwritten.") +"</font>";
                widget.labelOverwrite.text = warning;
            } else {
                widget.labelOverwrite.text ="";
            }
            return;
        }
        widget.complete = false;
    }
}

在文件 targetwidget.ui 中

这实际上不是真正的 .ui 文件,仅用于说明目的。在该文件的末尾,我添加了一个名为 labelOverwrite 的空 QLabel。 targetChanged callback.

中的文本用红色消息填充

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<widget class="QWidget" name="TargetWidget">
  <layout class="QVBoxLayout" name="verticalLayout">
    <item>
      <widget class="QLabel" name="label">
       <property name="text">
        <string>Please specify the folder where Miam-Player will be installed.</string>
       </property>
      </widget>
    </item>
    <item>
      <layout class="QHBoxLayout" name="horizontalLayout">
       <item>
        <widget class="QLineEdit" name="targetDirectory"/>
       </item>
       <item>
        <widget class="QToolButton" name="targetChooser"/>
       </item>
      </layout>
    </item>
    <item>
      <widget class="QLabel" name="labelOverwrite"/>
    </item>
  </layout>
</widget>

最后别忘了修改你现有的文件package.xml

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="UTF-8"?>
<Package>
    <DisplayName>Miam-Player</DisplayName>
    <Description>Miam-Player is the main program. It is required and cannot be unselected.</Description>
    <Name>org.miamplayer.core</Name>
    installscript.qs
    ...
    <UserInterfaces>
        <UserInterface>targetwidget.ui</UserInterface>
    </UserInterfaces>
</Package>


Matthieu 的回答是正确的,此外,如果您想要一个问题对话框,请在 installerscript.qs 中使用此功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Component.prototype.targetChanged = function (text)
{
    var widget = gui.currentPageWidget(); // get the current wizard page
    var install = false;

    if (widget != null)
    {
        if (text !="")
        {
            if (installer.fileExists(text +"/components.xml"))
            {
                var result = QMessageBox.question("quit.question","Installer","Do you want to overwrite previous installation?",
                    QMessageBox.Yes | QMessageBox.No);
                if (result == QMessageBox.Yes)
                {
                   install = true;
                }
            }
            else
                install = true;
        }
        else
            install = false;
    }

    widget.complete = install;

    if(install)
        installer.setValue("TargetDir", text);      
}

很简单。您应该执行以下操作:

  • 如果您没有安装程序文件夹,请查看 Qt/Tools/QtInstallerFramework/3.0/examples/。在这个例子中,我复制了一个 online 文件夹,我将把它叫做 my_installer_example.

  • 更新用于从 packages_update 上传的存储库。

  • my_installer_example 运行:

    ./../bin/repogen --update -p packages_update/ repoForUpload

    标志 --updade 允许将现有存储库 (repoForUpload) 作为输入,并且仅更改指定为附加参数的组件。

  • 在服务器上传repoForUpload,由config/config.xml.

    中的标签指定

  • 运行位于安装文件夹中的 maintenancetool


  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Controller.prototype.TargetDirectoryPageCallback = function()
    {
        var widget = gui.currentPageWidget();
        widget.TargetDirectoryLineEdit.textChanged.connect(this, Controller.prototype.targetChanged);
        Controller.prototype.targetChanged(widget.TargetDirectoryLineEdit.text);
    }

    Controller.prototype.targetChanged = function (text) {
        installer.setValue("RemoveTargetDir", true);
        if (text !="" && installer.fileExists(text +"/components.xml")) {
            if(QMessageBox.question("OverwriteTargetDirectory","Overwrite target directory","Do you want to overwrite previous installation?", QMessageBox.Yes | QMessageBox.No) == QMessageBox.Yes) {
                installer.setValue("RemoveTargetDir", false);
        }
    }