1.安装及介绍

【Qt杂谈2.快速体验Qt for WebAssembly(Windows平台)】
【qt for webassembly环境搭建图文教程】

2.问题及解决方案

2.1.在C++中调用js函数

关于在wasm编译环境中,在c++中调用js,可以参考以下网址:
【emscripten.h】
【asm.js 和 Emscripten 入门教程】
【EM_JS : unable to free const char* in cpp】

2.2.中文无法显示(乱码):

【Qt for WebAssembly中文显示异常】
弄一个otf或者ttf字体文件,然后加到资源库中,然后

1
2
//注意选择你自己的文件
QFontDatabase::addApplicationFont(":/qml/Font/Alibaba-PuHuiTi-Light.otf");

2.3.无法输入中文

好像没有有效的资料解决这个问题,所以我只能调用html的api了。(Qt6.8能够输入中文了,请看这篇文章的最后讨论【Unable to input Chinese (Chinese characters) ?】
具体实现代码请看另外一篇文章【QtWebAssembly实现中文输入】

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
#ifdef Q_OS_WASM
#include <emscripten.h>
#include <emscripten/html5.h>

//获取用户输入,因为Qt不支持直接输入中文。。
EM_JS(const char*, getInput, (const char *str), {
const text = UTF8ToString(str);
val = prompt("", text);

if(val == null)
{
val = ""
}
var jstring = val;

var lengthBytes = lengthBytesUTF8(jstring)+1;
var stringOnWasmHeap = _malloc(lengthBytes);
stringToUTF8(jstring, stringOnWasmHeap, lengthBytes);
return stringOnWasmHeap;
})

#endif

......
// 此函数可以作为静态函数,在适当的时候使用
// 调用此函数的效果为:在页面上弹出啊一个输出窗口,用户在输入好信息后,点击确定,窗口消失,此函数返回用户输入的字符串
QString Manager::getUserInput(QString currentText)
{
QString input = "";

#ifdef Q_OS_WASM
input = getInput(currentText.toUtf8().data());
#else

#endif

return input;
}

2.4.qt对应的emsdk版本

【Qt for WebAssembly】在这里插入图片描述
设置的时候,直接在 Tools --》Options --》device–》webAssembly设置emsk的根目录就行。(记得在设置之前要先安装好python并设置好环境变量,因为QtCreator会调用)

假如在emsdk install 比较新的版本时,可能会出现:

1
2
D:\Qt\emsdk\emsdk>emsdk install 3.1.25
error: tool or SDK not found: '3.1.25'

此时可以先pull一下再install

1
D:\Qt\emsdk\emsdk>git pull

2.5.文件的下载以及上传:

【webassembly: support local system file access】
文件的下载(保存)可以选择用label显示下载链接(点击label后触发下载)。

1
2
ui->label->setText("<a style='color: green;' href = https://download.qt.io/archive/online_installers/4.1/qt-unified-windows-x86-4.1.1-online.exe> click to download</a>");
ui->label->setOpenExternalLinks(true);

或者选择稍微复杂一点的,通过wasm提供的接口,调用js实现。

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
#ifdef Q_OS_WASM
#include <emscripten.h>
#include <emscripten/html5.h>
#endif

//获取服务器的地址、端口之类的。
//这个EM_JS是用来声明js函数的,声明之后就可以直接在c++里面用了。
EM_JS(const char*, getTitle, (), {
var urlPath = window.document.location.href;
console.log(urlPath);

var jstring = urlPath;

var lengthBytes = lengthBytesUTF8(jstring)+1;
var stringOnWasmHeap = _malloc(lengthBytes);
stringToUTF8(jstring, stringOnWasmHeap, lengthBytes);
return stringOnWasmHeap;
})

void MainWindow::on_pushButton_download_clicked()
{

#ifdef Q_OS_WASM
//执行js程序,这个是直接执行的。
EM_ASM({
window.open("http://127.0.0.1/resources/main.cpp");
});
#endif

//前面用EM_JS声明的函数
const char *str = getTitle();
qDebug() << str;
free((void*)str);
}

文件的上传这样(这个是会读取整个文件内容的)

1
2
3
4
5
6
7
8
9
10
11
void something(const QString &name, const QByteArray &content)
{
qDebug() << "name:" << name;
qDebug() << "content" << content;
}
void MainWindow::on_pushButton_clicked()
{
// QFileDialog::getSaveFileUrl();
//这个会打开选择的文件,然后将文件的名称以及内容通过上面的something来反馈出来。对于小文件的处理应该是够了。
QFileDialog::getOpenFileContent("*", something);
}

2.6.设置调试时的网页浏览器

调试时默认为ie,可以更改为其他浏览器
在这里插入图片描述
假如你这里的列表有ie一个,但是实际上你已经装了其他浏览器;那么,你需要在电脑的环境变量path上加上你的浏览器的路径,然后重启QtCreator
在这里插入图片描述

2.7.编译时报空间太小

wasm-ld: error: initial memory too small, 18222032 bytes needed
【解决 wasm-ld: error: initial memory too small, 18319040 bytes needed】

修改emsdk/upstream/emscripten/src目录里面的settings.js
里面的 INITIAL_MEM 旧版叫 TOTAL_MEMORY

或者在pro文件中增加

1
2
#值为64KB的倍数
wasm:QMAKE_LFLAGS += -s \"TOTAL_MEMORY=33554432\"

2.8.编译时报 The program “mingw32-make.exe” does not exist or is not executable.

参考【 QtCreator无法启动进程“mingw32-make.exe】
到project里面看,的确是没有找到这个mingw32-make.exe.
在这里插入图片描述ok,用everything来查看一下,这个东西在哪里。
在这里插入图片描述有好几个,但我用的是Qt5.15.2版本的,所以我选择这个:D:\Qt5.15\Tools\mingw810_64\bin\mingw32-make.exe。
将这个:D:\Qt5.15\Tools\mingw810_64\bin路径加到环境变量path中去。
在这里插入图片描述
重启一下QtCreator就好了。

2.9.无法显示SVG格式图片,报错误:qrc:/xxx.qml:70:11: QML Image: Error decoding: qrc:/xxx.svg: Unsupported image format。.

在.pro文件中添加:

1
QT += svg xml

2.10.获取服务器IP(不适用于域名访问的方式)

参考:【Getting server IP within wasm application】

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
#ifdef Q_OS_WASM
#include <emscripten.h>
#include <emscripten/val.h>
#include <emscripten/html5.h>
#endif

// ---这是第一种方式---
void getServerInfo1()
{
#ifdef Q_OS_WASM
emscripten::val location = emscripten::val::global("location");
auto host = QString::fromStdString(location["host"].as<std::string>());
auto port = QString::fromStdString(location["port"].as<std::string>());
qDebug() << "Server Host:" << host;
qDebug() << "Server Port:" << port;
#endif
}

// ---这是第二种方式---
//获取服务器的地址、端口之类的。
//这个EM_JS是用来声明js函数的,声明之后就可以直接在c++里面用了。
EM_JS(const char*, getTitle, (), {
var urlPath = window.document.location.href;
console.log(urlPath);

var jstring = urlPath;

var lengthBytes = lengthBytesUTF8(jstring)+1;
var stringOnWasmHeap = _malloc(lengthBytes);
stringToUTF8(jstring, stringOnWasmHeap, lengthBytes);
return stringOnWasmHeap;
})

2.11.Qt5.15.2的webAssembly版本不支持多线程

因为不支持多线程,因此无法使用QEventLoop,因为一旦调用QEventLoop::quit(),程序就会退出Qt主循环。
【Qt for WebAssembly官网介绍】
【Qt WebAssembly Platform Notes】
在这里插入图片描述

而试图同步QNetwrokReply的数据获取,也是不可能的。哪怕你如此处理,整个系统还是会卡住。

do{
qApp->processEvents(); // 这个函数没有生效
}
while(reply->isFinshed() == false)

难搞。
貌似qt6的webAssembly版本才支持多线程,但是我的代码是Qt5的,Qt6在qml上与Qt5差异挺大,所以我换不了Qt6.
在这里插入图片描述