QT6 Android应用文件分享故障:文件无法成功附加
QT6 Android 文本文件分享失败问题解决
我在QT6 Android应用中尝试将文本文件分享至Google Drive、WhatsApp或邮件等应用,目前能唤起可选的分享应用,但文件始终无法被附加,消息为空。已确认文件可读,怀疑问题和JNI路径处理有关。
初始实现代码
void myapp::shareTextDocument(const QString& documentPath) { qDebug() << documentPath; QString m_downloadfilename; m_downloadfilename = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); //test if file is readable -> result is positive QFile inputFile(documentPath); if (inputFile.open(QIODevice::ReadOnly)) { QTextStream in(&inputFile); while (!in.atEnd()) { QString line = in.readLine(); qDebug() << line; } inputFile.close(); } //text is readable. QJniObject jniDocumentPath = QJniObject::fromString(documentPath); // Create an Intent to share the text document QJniObject intent("android/content/Intent", "(Ljava/lang/String;)V", jniDocumentPath.object<jstring>()); // Set the action and MIME type QJniObject action = QJniObject::getStaticObjectField<jstring>( "android/content/Intent", "ACTION_SEND"); QJniObject mimeType = QJniObject::fromString("text/plain"); intent.callObjectMethod( "setAction", "(Ljava/lang/String;)Landroid/content/Intent;", action.object()); intent.callObjectMethod( "setType", "(Ljava/lang/String;)Landroid/content/Intent;", mimeType.object()); // Get the current QtActivity and start the sharing activity QNativeInterface::QAndroidApplication::runOnAndroidMainThread ([intent]() { QJniObject currentActivity = QtAndroidPrivate::activity(); QJniObject chooserIntent = QJniObject::callStaticObjectMethod( "android/content/Intent", "createChooser", "(Landroid/content/Intent;Ljava/lang/CharSequence;)Landroid/content/Intent;", intent.object(), QJniObject::fromString("Share via").object()); currentActivity.callMethod<void>( "startActivity", "(Landroid/content/Intent;)V", chooserIntent.object()); }); }
问题现象:分享应用可正常唤起、选择及发送,但文件未被附加。
改用FileProvider后的配置与代码
AndroidManifest.xml 配置
<application ....... <provider android:name="androidx.core.content.FileProvider" android:authorities="org.my.myap.authority" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths"/> </provider> </application> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
C++ 代码实现
void myApp::shareTextDocument(const QString& documentPath) { QJniObject activity = QtAndroidPrivate::activity(); QJniObject context = QtAndroidPrivate::context(); QJniEnvironment env; QJniObject file = QJniObject::fromString(QDir::toNativeSeparators(documentPath)); QString providerAuthority = "org.my.myap.authority"; QJniObject provider = QJniObject::callStaticObjectMethod("androidx/core/content/FileProvider", "getUriForFile", "(Landroid/content/Context;Ljava/lang/String;Ljava/io/File;)Landroid/net/Uri;", context.object(), QJniObject::fromString(providerAuthority).object(), file.object<jobject>()); QJniObject intent("android/content/Intent"); intent.callObjectMethod("setAction", "(Ljava/lang/String;)Landroid/content/Intent;", QJniObject::fromString("android.intent.action.SEND").object()); intent.callObjectMethod("putExtra", "(Ljava/lang/String;Landroid/os/Parcelable;)Landroid/content/Intent;", QJniObject::fromString("android.intent.extra.STREAM").object(), provider.object()); intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QJniObject::fromString("application/octet-stream").object()); QtAndroidPrivate::startActivity(intent.object(), 0); }
CMakeLists.txt 配置
if(ANDROID) set(ANDROID_XML_FILES android/res/xml/filepaths.xml) qt_add_resources(TARGET HyundaiMeteoQML SOURCES ${ANDROID_XML_FILES}) endif()
filepaths.xml 配置
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="."/> </paths>
问题现象:接收应用(Drive、邮件、WhatsApp等)提示无数据,问题依旧。
问题排查与修复方案
1. 修复FileProvider的文件对象创建错误
原代码中用QJniObject::fromString直接创建File对象是错误的,需通过Java File类的构造函数传入路径字符串:
// 替换原有的file创建代码 QJniObject filePathStr = QJniObject::fromString(QDir::toNativeSeparators(documentPath)); QJniObject file("java/io/File", "(Ljava/lang/String;)V", filePathStr.object<jstring>());
2. 正确授予URI权限
在启动Intent前,必须给目标应用授予URI的读权限,避免因权限不足导致无法访问文件:
// 添加权限标记 QJniObject readFlag = QJniObject::getStaticObjectField<jint>("android/content/Intent", "FLAG_GRANT_READ_URI_PERMISSION"); intent.callObjectMethod("addFlags", "(I)Landroid/content/Intent;", readFlag.object<jint>());
3. 匹配正确的MIME类型
对于文本文件,优先使用text/plain而非通用的application/octet-stream,部分应用对二进制类型的支持有限:
intent.callObjectMethod("setType", "(Ljava/lang/String;)Landroid/content/Intent;", QJniObject::fromString("text/plain").object());
4. 完善FileProvider路径配置
如果文件存放在应用私有Documents目录,需在filepaths.xml中添加对应路径配置:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_files" path="."/> <files-path name="app_documents" path="Documents/"/> <!-- 适配应用私有Documents目录 --> </paths>
5. 规范Intent初始化与Chooser调用
使用系统常量而非硬编码字符串创建Intent,并通过Chooser唤起分享选择器:
// 用系统常量创建Intent QJniObject actionSend = QJniObject::getStaticObjectField<jstring>("android/content/Intent", "ACTION_SEND"); QJniObject intent("android/content/Intent", "(Ljava/lang/String;)V", actionSend.object<jstring>()); // 创建分享选择器 QJniObject chooser = QJniObject::callStaticObjectMethod("android/content/Intent", "createChooser", "(Landroid/content/Intent;Ljava/lang/CharSequence;)Landroid/content/Intent;", intent.object(), QJniObject::fromString("分享文件").object()); QtAndroidPrivate::startActivity(chooser.object(), 0);
内容的提问来源于stack exchange,提问作者Kurt Dewulf
相关产品推荐
相关产品推荐

