Qt for android : 简单实现弹窗创建文件,并使用JNI进行读写实例
简介
Qt版本 : Qt6.6.2
手机: RedMi 7A
本例使用JNI方式打开窗体创建文件, handleActivityResult中处理创建文件之后通过InputStream/OutputStream简单读写文件
代码
项目添加
QT += core-private
头文件
代码来之参考中的连接, 稍微修改
需要注意的是 QAndroidActivityResultReceiver, 继承之后可以接收startActivity执行之后的返回结果,handleActivityResult槽中处理结果
#ifndef HARDWAREUTILS_ANDROID_H
#define HARDWAREUTILS_ANDROID_H
#include "private/qandroidextras_p.h"
#include "qjniobject.h"
#include <QObject>
#include <QJniObject>
#include <QJniEnvironment>
#include <QFile>
class HardwareUtilsAndroid: public QObject, public QAndroidActivityResultReceiver
{
private:
HardwareUtilsAndroid(QObject *parent = 0);
public:
virtual ~HardwareUtilsAndroid();
static HardwareUtilsAndroid* Instance(QObject *parent = 0);
virtual void handleActivityResult(int receiverRequestCode, int resultCode, const QJniObject & data);
virtual bool writeOnUSB(QString filename);
private:
void writeFile(QJniObject &fileUri, const QString &text);
void readFile(QJniObject &fileUri, QString &text);
private:
QFile m_file;
};
#endif // HARDWAREUTILS_ANDROID_H
源文件
#include "HardwareUtils_Android.h"
#include <jni.h>
#include <QDebug>
HardwareUtilsAndroid *HardwareUtilsAndroid::Instance(QObject *parent) {
static HardwareUtilsAndroid *instance = NULL;
if(!instance) {
instance = new HardwareUtilsAndroid(parent);
}
return instance;
}
HardwareUtilsAndroid::HardwareUtilsAndroid(QObject *parent):
QObject(parent)
{
}
HardwareUtilsAndroid::~HardwareUtilsAndroid()
{
}
bool HardwareUtilsAndroid::writeOnUSB(QString filename)
{
QJniObject ACTION_CREATE_DOCUMENT = QJniObject::fromString("android.intent.action.CREATE_DOCUMENT");
QJniObject intent("android/content/Intent");
if (ACTION_CREATE_DOCUMENT.isValid() && intent.isValid())
{
intent.callObjectMethod("setAction", "(Ljava/lang/String;)Landroid/content/Intent;", ACTION_CREATE_DOCUMENT.object<jstring>());
intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QJniObject::fromString("text/plain").object<jstring>());
intent.callObjectMethod("putExtra", "(Ljava/lang/String;Ljava/lang/String;)Landroid/content/Intent;",
QJniObject::fromString("android.intent.extra.TITLE").object<jstring>(),
QJniObject::fromString(filename).object<jstring>());
QtAndroidPrivate::startActivity(intent.object<jobject>(), 123, this);
return true;
}
else
{
return false;
}
}
void HardwareUtilsAndroid::writeFile(QJniObject &fileUri, const QString &text)
{
// 获取文件输出流
QJniObject activity = QtAndroidPrivate::activity();
QJniObject contentResolver = activity.callObjectMethod("getContentResolver",
"()Landroid/content/ContentResolver;");
QJniObject outputStream = contentResolver.callObjectMethod("openOutputStream",
"(Landroid/net/Uri;)Ljava/io/OutputStream;",
fileUri.object<jobject>());
if (outputStream.isValid())
{
QJniObject stringToWrite = QJniObject::fromString(text);
QJniObject bytes = stringToWrite.callObjectMethod("getBytes", "()[B");
QJniEnvironment env;
jbyteArray byteArray = static_cast<jbyteArray>(bytes.object<jarray>());
jbyte* byteData = env->GetByteArrayElements(byteArray, nullptr);
int length = env->GetArrayLength(byteArray);
outputStream.callMethod<void>("write", "([B)V", byteArray);
env->ReleaseByteArrayElements(byteArray, byteData, 0);
outputStream.callMethod<void>("close", "()V");
qDebug() << "File written successfully";
}
else
{
qDebug() << "Failed to open output stream";
}
}
void HardwareUtilsAndroid::readFile(QJniObject &fileUri, QString &text)
{
QJniEnvironment env;
QJniObject activity = QtAndroidPrivate::activity();
QJniObject contentResolver = activity.callObjectMethod("getContentResolver",
"()Landroid/content/ContentResolver;");
// 创建InputStream
QJniObject inputStream = contentResolver.callObjectMethod("openInputStream",
"(Landroid/net/Uri;)Ljava/io/InputStream;", fileUri.object<jobject>());
// 创建缓冲区
jbyteArray bufferArray = env->NewByteArray(1024);
// 读取数据
QByteArray fileData;
jint bytesRead;
while ((bytesRead = inputStream.callMethod<jint>("read", "([B)I", bufferArray)) != -1)
{
jbyte* buffer = env->GetByteArrayElements(bufferArray, nullptr);
fileData.append(reinterpret_cast<const char*>(buffer), bytesRead);
env->ReleaseByteArrayElements(bufferArray, buffer, JNI_ABORT);
}
// 关闭流
if (inputStream.isValid())
{
inputStream.callMethod<void>("close", "()V");
if (env->ExceptionCheck())
{
env->ExceptionClear();
}
}
text = QString::fromUtf8(fileData);
// 删除局部引用
env->DeleteLocalRef(bufferArray);
}
void HardwareUtilsAndroid::handleActivityResult(int receiverRequestCode, int resultCode, const QJniObject & data)
{
qDebug() << "Receive activity result";
jint RESULT_OK = QJniObject::getStaticField<jint>("android/app/Activity", "RESULT_OK");
if (receiverRequestCode == 123 && resultCode == RESULT_OK)
{
QJniObject uri = data.callObjectMethod("getData", "()Landroid/net/Uri;");
if (!uri.isValid())
{
qDebug() << "Invalid URI";
return;
}
QString text;
writeFile(uri, QString("hello world!!!!"));
readFile(uri, text);
qDebug() << "read: " << text;
}
else
{
qDebug() << "Failed to create file";
}
}
调用
可以搭配QFileDialog进行使用,打开U盘的路径创建文件
HardwareUtilsAndroid::Instance()->writeOnUSB(dlg.selectedFiles().value(0));
参考:
https://github.com/jbflamant/android-usb-access