安装Qt Android 模块、Qt Creator、JDK8
Qt Creator版本太高不行,亲测最新版的会导致无法使用jdk 8(2024-05-04
我的Qt版本是5.15.2,所以我选择了Qt Creator5.0.3进行开发
5.0.3
下载JDK8
安装Qt Creator、JDK8
安装Qt Creator没什么好说的,都是默认选择就行
安装JDK8也是全部默认的就行
Qt Creator安卓环境配置
- 确认是否开启了Android 开发插件Android 帮助-》关于插进
- 配置Android开发环境 工具-》选项
JDK location:JDK安装路径,此处是默认的安装路径
Android SDk的路径:此处请新建一个非中文路径的名为《android-sdk-windows》的文件夹,这一步在我测试,好像必须是这个名字,不然set up sdk不行
然后请将sdk_definitions.json文件中的“cmdline-tools;latest” 修改为 “cmdline-tools;6.0”。
修改完成后点击[Android SDk的路径]后面的set up sdk
如果不出意外的,会自动下载相关依赖,最终正常效果如下
配置openssl,先选择保存路径,然后再download openssl即可
下载对应Android 版本sdk,我的机器是Android 9 ,下载了下面勾选的三个东西,然后点击update installed.
然后点击Kits-》Qt Versions,将Android qmake.exe添加进来,然后就会会自动的检测并配置Android 编译套件 ,如果没有就重新启动下Qt Creator,或者手动设置下
至此,环境搭配完成
PDA连接https服务器、并获取PDA扫码数据
重点来了
这里默认值就行
点击完成,此时,会在源码路径生成一个android文件夹,在里面建立一个src文件夹(这里一定要建立)。
双击AndroidManifest.xml
org.qtproject.example:这里表示的是java代码的包名,根据官方示例的做法,是在刚建立的src文件夹中依次建立org》qtproject》example,(其实不这样直接放入src也是没问题的,但是既然官方都这样写,我还是这样做)。当然你也可以写成org.qtproject.example.test,然后在example下面再建立一个test文件夹即可,把java源文件放入最后一个目录中。
然后在设置如下两样参数
将手机进入开发者模式,然后勾选:USB调试
连接电脑
PDA设备扫码数据获取
我这使用的方法是以Android广播的形式,获取设备扫码数据的,但是Qt没有办法直接获取广播数据,只有借助java代码。
这里借鉴的是如来说法同志的QT for android 获取PDA扫码的广播数据博客中的代码,
代码如下
ActivityUtils.java
package org.qtproject.example;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.content.BroadcastReceiver;
import android.content.IntentFilter;
public class ActivityUtils {
private static native void sendToQt(String message);
private static final String TAG = "ActivityUtils";
public static final String BROADCAST_NAME_ACTION = "com.android.server.scannerservice.broadcast";//这里填广播名称
public void registerServiceBroadcastReceiver(Context context) {
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(BROADCAST_NAME_ACTION);
context.registerReceiver(serviceMessageReceiver, intentFilter);
Log.i(TAG, "Registered broadcast receiver");
}
private BroadcastReceiver serviceMessageReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "In OnReceive broadcast receiver");
if (BROADCAST_NAME_ACTION.equals(intent.getAction())) {
String name = intent.getStringExtra("scannerdata");
Log.i(TAG, "Service received name: " + name);
String message = "Hello " + name;
sendToQt(message);
Log.i(TAG, "Service sent back message: " + message);
}
}
};
}
然后将此源文件放入上面说的android文件夹里面的码包文件夹中
然后在cpp中代码调用
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSslKey>
#include <QNetworkAccessManager>
#include <QFile>
#include <QNetworkReply>
#include <QAndroidJniEnvironment>
#include <QAndroidIntent>
#include <QtAndroid>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
signals:
void sendCodeMessage(QString mess);
public slots:
void setCodeMessage(QString mess);
private:
bool requestPermission();\\动态申请权限
void registerNatives();\\将c++函数注册进入java,等待被java调用
void registerBroadcastReceiver();\\这里应该是调用java中的注册函数,将接收数据函数注册到广播中
static void receivedFromAndroidService(JNIEnv *env, jobject /*thiz*/, jstring value);\\当有扫码的广播时被调用
private:
void readQSslConfiguration();\\读取密钥
void networkRequest();\\发送请求
private:
static MainWindow* mainWindow;
//服务器地址
QString domainName;
static QNetworkAccessManager* manager;
QSslConfiguration sslConfigurationnfig;
quint16 port;
QString hostName;
private:
Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow* MainWindow::mainWindow = nullptr;
QNetworkAccessManager* MainWindow::manager= nullptr;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
mainWindow = this,
domainName = "https://dmmd:1111";
hostName = "dmmd";
port = 1111;
manager = new QNetworkAccessManager(this);
ui->setupUi(this);
registerNatives();
registerBroadcastReceiver();
readQSslConfiguration();
networkRequest();
connect(this, &MainWindow::sendCodeMessage, this, &MainWindow::setCodeMessage);
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::requestPermission() {
QtAndroid::PermissionResult r = QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE");
if(r == QtAndroid::PermissionResult::Denied) {
QtAndroid::requestPermissionsSync( QStringList() << "android.permission.WRITE_EXTERNAL_STORAGE" );
r = QtAndroid::checkPermission("android.permission.WRITE_EXTERNAL_STORAGE");
if(r == QtAndroid::PermissionResult::Denied) {
return false;
}
}
return true;
}
void MainWindow::registerNatives()
{
JNINativeMethod methods[] {
{"sendToQt", "(Ljava/lang/String;)V", reinterpret_cast<void *>(MainWindow::receivedFromAndroidService)}};
QAndroidJniObject javaClass("org/qtproject/example/ActivityUtils");
QAndroidJniEnvironment env;
jclass objectClass = env->GetObjectClass(javaClass.object<jobject>());
env->RegisterNatives(objectClass,
methods,
sizeof(methods) / sizeof(methods[0]));
env->DeleteLocalRef(objectClass);
}
void MainWindow::registerBroadcastReceiver()
{
QAndroidJniEnvironment env;
jclass javaClass = env.findClass("org/qtproject/example/ActivityUtils");
QAndroidJniObject classObject(javaClass);
classObject.callMethod<void>("registerServiceBroadcastReceiver",
"(Landroid/content/Context;)V",
QtAndroid::androidContext().object());
}
void MainWindow::receivedFromAndroidService(JNIEnv *env, jobject /*thiz*/, jstring value){
qDebug()<<env->GetStringUTFChars(value, nullptr);
emit mainWindow->sendCodeMessage(env->GetStringUTFChars(value, nullptr));
}
void MainWindow::setCodeMessage(QString mess){
ui->textBrowser_2->append(mess);
}
void MainWindow::readQSslConfiguration(){
QString p12Path = R"(/storage/emulated/0/ssl/client.p12)";
QFile file1(p12Path);
if (!file1.open(QIODevice::ReadOnly)) {
qWarning() << u8"p12文件读取失败";
return;
}
QSslKey priKey;
QSslCertificate cert;
QList<QSslCertificate> certList;
bool state = QSslCertificate::importPkcs12(&file1, &priKey, &cert, &certList, "dddddd122317");
if(!state){
qDebug()<<u8"解密失败";
}
sslConfigurationnfig.setPeerVerifyMode(QSslSocket::VerifyPeer);
sslConfigurationnfig.setProtocol(QSsl::TlsV1_1);
sslConfigurationnfig.setPrivateKey(priKey);
sslConfigurationnfig.setLocalCertificate(cert);
sslConfigurationnfig.setCaCertificates(certList);
sslConfigurationnfig.setAllowedNextProtocols({QSslConfiguration::NextProtocolHttp1_1});
file1.close();
}
void MainWindow::networkRequest(){
QUrl url(domainName);
url.setPath("/app/customer/query");
QEventLoop eventLoop;
QNetworkRequest request;
request.setUrl(url);
//设置请求头
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
manager->connectToHostEncrypted(hostName, port, sslConfigurationnfig);
QNetworkReply* reply = manager->post(request, QByteArray{});
connect(reply, &QNetworkReply::finished, &eventLoop, &QEventLoop::quit);
connect(reply, &QNetworkReply::downloadProgress, this, [=](qint64 size, qint64 line) {
//qDebug() << size << line;
});
connect(reply, &QNetworkReply::errorOccurred, this, [=](QNetworkReply::NetworkError code) {
QString error = code + reply->errorString();
qWarning() << error;
});
eventLoop.exec();
QByteArray data = reply->readAll();
ui->textBrowser->append(data);
qDebug()<<data;
}
Virtual-Hosts
Virtual-Hosts
使用这个软件可以不用修改hosts文件也能使用自定义的主机名进行访问
首先在电脑上命名一个hosts文件(无后缀)
然后写入自定义的主机名
127.0.0.1 mddm
然后放入手机里面
然后点击:重新选择HOSTS文件
打开开关即可正常访问
大功告成!服务器可以正常连接返回数据、软件也可以正常接收到扫码数据