Qt Android目录操作技术咨询:文件存储路径修正与QProcess调用可行性问题
Hey there! Let's tackle your two Qt-on-Android questions one by one:
The problem here is that hardcoding absolute paths like /storage/emulated/0/Android/data/ doesn't work reliably on Android, thanks to scoped storage (introduced in Android 10) and Qt's path virtualization for Android apps. When you use a hardcoded external path without proper permissions or Qt's standard path utilities, Android redirects the write operation to your app's private internal storage (/data/user/0/org.qtproject.example.NameApp), which is why you're seeing files end up there.
Here's how to fix it:
- Use Qt's
QStandardPathsfor platform-safe paths: For Android,QStandardPaths::ExternalDataLocationpoints directly to your app's dedicated external storage directory:/storage/emulated/0/Android/data/<your_package_name>/files/. This directory is private to your app (no extra permissions needed on Android 11+), and Qt handles all platform-specific path resolution automatically. - Never hardcode paths: Absolute paths can vary across devices or Android versions, so always rely on Qt's path utilities.
Example code to build your target zip path:
#include <QStandardPaths> #include <QDir> // Get the app's external data directory QString externalDataPath = QStandardPaths::writableLocation(QStandardPaths::ExternalDataLocation); // Create the directory if it doesn't exist QDir().mkpath(externalDataPath); // Build your target zip path QString zipPath = externalDataPath + "/cache.zip"; // Now use this path for your QuaZip operations or rename m_file.rename(zipPath);
If you specifically need to write to /storage/emulated/0/Android/data/ (not your app's subdirectory):
- Add the
WRITE_EXTERNAL_STORAGEpermission to yourAndroidManifest.xml(for Android 9 and below). - For Android 10+, add
android:requestLegacyExternalStorage="true"to your<application>tag inAndroidManifest.xmlto temporarily bypass scoped storage (note this is deprecated in Android 11+—stick to your app's dedicated directory whenever possible).
Unfortunately, QProcess won't work for opening files on Android the way it does on Windows. Android uses an Intent-based system to launch apps that can handle specific file types, rather than directly executing commands like desktop systems.
To open a file, you'll need to use Qt's Android Extras module to call Android's native Intent system. Here's how:
Step 1: Add Qt Android Extras to your project
Add this line to your .pro file:
QT += androidextras
Step 2: Code to open a file using Intent
This example handles Android 7+'s FileProvider requirement (to avoid FileUriExposedException):
#include <QAndroidJniObject> #include <QAndroidIntent> #include <QFile> void openFile(const QString& filePath) { QFile file(filePath); if (!file.exists()) { // Handle file not found error return; } // Convert Qt file path to Android File object QAndroidJniObject javaFile = QAndroidJniObject::fromString(filePath); QAndroidJniObject fileUri; // Use FileProvider for Android 7.0 (API 24) and above if (QAndroidJniEnvironment().version() >= JNI_VERSION_1_6 && QAndroidJniObject::callStaticMethod<jint>("android/os/Build$VERSION", "SDK_INT") >= 24) { QAndroidJniObject authority = QAndroidJniObject::fromString("org.qtproject.example.NameApp.fileprovider"); // Replace with your package name + .fileprovider fileUri = QAndroidJniObject::callStaticObjectMethod("androidx/core/content/FileProvider", "getUriForFile", "(Landroid/content/Context;Ljava/lang/String;Ljava/io/File;)Landroid/net/Uri;", QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;").object(), authority.object(), javaFile.object()); } else { // Use file:// URI for older Android versions fileUri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "fromFile", "(Ljava/io/File;)Landroid/net/Uri;", javaFile.object()); } // Create ACTION_VIEW Intent to open the file QAndroidIntent intent(QAndroidJniObject::getStaticObjectField("android/content/Intent", "ACTION_VIEW", "Ljava/lang/String;")); intent.setData(fileUri); intent.setFlags(QAndroidJniObject::getStaticField<jint>("android/content/Intent", "FLAG_GRANT_READ_URI_PERMISSION")); // Launch the Intent QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative", "activity", "()Landroid/app/Activity;"); activity.callMethod<void>("startActivity", "(Landroid/content/Intent;)V", intent.handle()); }
Step 3: Configure FileProvider (for Android 7+)
- Create
res/xml/file_paths.xmlin your Android resources directory:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="my_files" path="."/> </paths>
This tells FileProvider to share files from your app's external files directory.
- Add the FileProvider to your
AndroidManifest.xml:
<application ...> <provider android:name="androidx.core.content.FileProvider" android:authorities="org.qtproject.example.NameApp.fileprovider" <!-- Match the authority in your code --> android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/> </provider> </application>
Replace org.qtproject.example.NameApp with your actual app's package name.
内容的提问来源于stack exchange,提问作者Ed Vestorn

