Qt 5.8 Apple 通知服务器握手失败

Posted

技术标签:

【中文标题】Qt 5.8 Apple 通知服务器握手失败【英文标题】:Qt 5.8 Apple Notification Server Handshake failed 【发布时间】:2017-06-30 06:01:40 【问题描述】:

我现在尝试了一些我们的,但我无法让它工作。我想从 Qt 应用程序推送一些通知。试图让它在安装了 Qt 5.8 的 macOS Sierra 上工作,也可以在安装 Qt 5.8 的 Pi3 上工作。

我用“fastlane pem”创建了我的推送证书,并用“Pusher”对其进行了测试,它工作正常。但我无法让它在 Qt 中工作......

首先是我用来初始化和连接 QSslSocket 的代码:

QSslSocket * ssl = new QSslSocket;

connect(ssl, &QSslSocket::encrypted, this, &iosPusher::encrypted );
connect(ssl, static_cast<void(QSslSocket::*)(const QList<QSslError> &)>(&QSslSocket::sslErrors),this,&IOSPusher::sslErrors);
connect(ssl, static_cast<void(QSslSocket::*)(QAbstractSocket::SocketError)>(&QSslSocket::error),this, &IOSPusher::error );
connect(ssl,&QSslSocket::stateChanged,this,&IOSPusher::stateChanged );

加载证书

QString path = QStandardPaths::writableLocation(certificateLocation) + "/apns.pem";

const auto certs =  QSslCertificate::fromPath(path);

if(certs.count() > 0)
    qDebug() << "IOSPusher: Certificate loaded successfully";
else
    qDebug() << "Could not load certificate : " + path;


QSslConfiguration config = QSslConfiguration::defaultConfiguration();
config.setCaCertificates(certs);

ssl->setSslConfiguration(config);
ssl->connectToHostEncrypted( gateway.sandbox.push.apple.com,2195 );

这就是我得到的输出:

IOSPusher: Certificate loaded successfully
IOSPusher::stateChanged  QAbstractSocket::HostLookupState
IOSPusher::stateChanged  QAbstractSocket::ConnectingState
IOSPusher::stateChanged  QAbstractSocket::ConnectedState
IOSPusher::error  QAbstractSocket::SocketError(13)
IOSPusher::stateChanged  QAbstractSocket::ClosingState
IOSPusher::stateChanged  QAbstractSocket::UnconnectedState

所以根据 Qt 文档的错误:

QAbstractSocket::SocketError(13)

意思如下:

SslHandshakeFailedError

还有

> SSL/TLS 握手失败,无法建立加密通道。 sslErrors() 信号应该已经发出。

但是在我的情况下不会发出sslErrors() 信号....

SSL/TLS 握手失败,所以连接被关闭(仅在 QSslSocket 中使用)

任何想法或示例如何建立与苹果的加密连接?

提前致谢!

【问题讨论】:

【参考方案1】:

好吧,就像我经常尝试从我现在得到的任何人那里获得帮助时一样:D

现在对我有用的解决方案是:

使用fastlane pem 和密码创建*.pem 证书(也许它也可以在没有密码的情况下工作,但这是我现在尝试的最后一次......永远不要更改正在运行的系统哈哈)

 fastlane pem --development -p <private_key_password> -a <your_app_identifier>

然后要与 QSslSocket 连接,请执行以下操作...就像我的问题之前一样...

QSslSocket * ssl = new QSslSocket;
QString path = QStandardPaths::writableLocation(certificateLocation) + "/apns.pem";

connect(ssl, &QSslSocket::encrypted, this, &IOSPusher::encrypted );
connect(ssl, static_cast<void(QSslSocket::*)(const QList<QSslError> &)>(&QSslSocket::sslErrors),this,&IOSPusher::sslErrors);
connect(ssl, static_cast<void(QSslSocket::*)(QAbstractSocket::SocketError)>(&QSslSocket::error),this, &IOSPusher::error );
connect(ssl,&QSslSocket::stateChanged,this,&IOSPusher::stateChanged );

QSslCertificate cert;
const auto certs =  QSslCertificate::fromPath(path);

if(certs.count() > 0)
    cert = certs.at(0);
    qDebug() << "IOSPusher: Certificate loaded successfully";
else
    qDebug() << "Could not load certificate : " + path;
    return false;

现在神奇的是它为我做了什么

使用也将使用fastlane pem 创建的 private_key (.pkey) 文件

//Use the path to the .pkey file from fastlane
QFile keyfile(path + "/apns.pkey");
keyfile.open(QFile::ReadOnly);

//Create the QSslKey as private key
QSslKey privateKey(&keyfile,QSsl::Rsa,QSsl::Pem,QSsl::PrivateKey,QByteArray("<private_key_password_from_fastlane>"));
//Close the file
keyfile.close();

并将私钥和证书添加到 ssl 配置中

QSslConfiguration config = QSslConfiguration::defaultConfiguration();

config.setLocalCertificate(cert);
config.setPrivateKey(privateKey);

正如你在这里看到的,这次我没有使用config.setCaCertificates 方法,而是使用config.setLocalCertificate 方法。那是我的错误......

至少将配置添加到 ssl 套接字和 FIRE!

ssl->setSslConfiguration(config);
ssl->connectToHostEncrypted( "gateway.sandbox.push.apple.com",2195 );

仅此而已

现在encrypted() 信号被发出!是的。。

【讨论】:

以上是关于Qt 5.8 Apple 通知服务器握手失败的主要内容,如果未能解决你的问题,请参考以下文章

VS2015社区版Qt 5.8项目构建失败

由 arm-none-linux-gnueabi 进行的 Qt 5.8 交叉编译失败?

Apple 不保证推送的交付?

Qt & SSL,握手失败

基于 GAE 的 iOS 推送通知 (APN)、SSL 握手失败

Qt/OSX WebSocket 打开握手超时