File copy fails on Android
-
Hi, I am copying a file to the download folder:
Q_INVOKABLE bool exportNutritionLogFile() { QString downloadFolder = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation); qDebug()<<"downloadFolder is: "<<downloadFolder; QString timeStamp = QDateTime::currentDateTime().toString("_yyyy-MM-dd_HH-mm-ss"); QString targetFilenameAndPath = downloadFolder+"/nutritionLogExport"+timeStamp+".json"; qDebug() << "targetFilenameAndPath: "<<targetFilenameAndPath; QFile logFile(QStringLiteral("logged_nutrition.json")); if (!logFile.exists()) return false; QFile testFile(targetFilenameAndPath); if (testFile.exists()) { testFile.remove(); } auto success = logFile.copy(targetFilenameAndPath); qDebug()<<"success: "<<success; return success; }
That works on my phone (Nokia8). But on my tablet (Galaxy Tab S4) I recieve:
D libPunktlandung_armeabi-v7a.so: downloadFolder is: "/storage/emulated/0/Download" D libPunktlandung_armeabi-v7a.so: targetFilenameAndPath: "/storage/emulated/0/Download/nutritionLogExport_2021-08-14_12-59-51.json" D libPunktlandung_armeabi-v7a.so: success: false
I have the WRITE_EXTERNAL_STORAGE permisison and the folder / the path does exist.
What could possibly be the problem here? Why does it work on one device and doesn't on a different one? -
I might come across as extremely cynical...
but after years of cross-platform development (on desktop and mobile), I have essentially "given up" on certain why questions, such as:
- Why does it work on one device and doesn't on a different one?
Instead, I have just come to EXPECT that these conundrums will reoccur at every possible opportunity...
Here is a sample of how I proactively attempt to "code around" such pain points:
QString OurLocalLogPathWithSeparatorAlreadyAppended() { // In order of preference. We expect the first to always succeed. const std::vector<QStandardPaths::StandardLocation> possibleLocations{ { QStandardPaths::DataLocation, QStandardPaths::ConfigLocation, QStandardPaths::GenericDataLocation, QStandardPaths::DownloadLocation, // truly a last resort. } }; QString chosenLocation; for( const auto possibility : possibleLocations ) { const QString location = QStandardPaths::writableLocation( possibility ); // mkpath was necessary on my Android phone when app was first installed! const bool madePath = QDir().mkpath( location ); if( location.length() > 3 && madePath ) { chosenLocation = location; break; } } qDebug() << chosenLocation; if( !chosenLocation.isEmpty() ) { chosenLocation += "/"; } return chosenLocation; }
In other words, plan to have 2 or 3 "backup locations" where you can read/write your files, in case your first location is off-limits for any reason.
-
@SeDi said in File copy fails on Android:
I have the WRITE_EXTERNAL_STORAGE permisison and the folder / the path does exist.
You may have that in your manifest file, but after a certain Android version it became a requirement to check&request them at run time, just before the copy operation.
Also I may be the case, that the default location, that your logged_nutrition.json is unavailable because its inside the AppSandbox.
I would recommend to store it withQStandardPaths::writableLocation(QStandardPaths::AppDataLocation)
That should work, from my experience. -
@J-Hilk said in File copy fails on Android:
That should work
It's been some time since I've opened this thread. But the solution, for posterity, is a bit disappointing (from me lazy programmer's point of view) as well as very positive in regards to data security:
It's just not possible to just write into a shared space on Android any more (if you want to address a current API in order to be able to push your app to the PlayStore, that is).
Instead we have to write the file locally and then share it with a share intent.
ekkesSHAREexample was a huge help, but I had to nudge it into using the (newer) androidx system. -
@SeDi thanks for returning here to share the outcome. This is good info that will surely help others (and likely me the next time I'm working on Android!).
-
This post is deleted!
-
@SeDi said in File copy fails on Android:
ekkesSHAREexample was a huge help, but I had to nudge it into using the (newer) androidx system.
would be great if you publish your code or if you tell me about your changes in Issues of my example. thx
-
@ekkescorner Sorry for not noticing this for more than half a year. And sorry again: I have been wrong with saying that I had to nudge your example. I have just checked. What I had to nudge was in my build.gradle:
dependencies { implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) compile 'androidx.appcompat:appcompat:1.1.0' // <-- THIS def billing_version = "4.0.0" implementation "com.android.billingclient:billing:$billing_version" }
and my gradle.properties:
android.useAndroidX=true
-
@SeDi thx. Will take a look at it soon - have to update / rewrite all my examples for Qt6 next months