Sharing Files on Android or iOS from or with your Qt App
Welcome to Part 4 of my Blog series about Sharing Files to and from mobile Qt Apps.
Part 1was about sharing Files or Content from your Qt App with native Android or iOS Apps,
Part 2 explained how to share Files with your Qt App from other native Android Apps,
Part 3 covered sharing Files with your Qt App from
Part 4 implements FileProvider to share Files from your Qt App with native Android Apps.
FileProvider Content URIs
Starting with Android 7 (SDK 24) you cannot use File URIs anymore to share Files to other Android Apps – you must use a FileProvider to share Files using a Content URI.
To avoid this you could use Target SDK 23 as I did for the first parts of this blog.
But starting November 1, 2018 Google requires for updates to Apps or new Apps on Google Play to target Android 8 (Oreo, API level 26) or higher, so there’s no way to share Files on Android without using a FileProvider.
Here’s the workflow to update your sharing App from File URI to FileProvider with Content URI.
Android Manifest
As a first step we have to add some info to .xml :
<application ...> <provider android:name="android.support.v4.content.FileProvider" android:authorities="org.ekkescorner.examples.sharex.fileprovider" android:grantUriPermissions="true" android:exported="false"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths"/> </provider> </application>
The Provider needs the com.android.support.v4 Libraries. To include them, please add com.android.support to your build.gradle file:
dependencies{ ... compile'com.android.support:support-v4:25.3.1' }
This will only work if you have installed the Android Support Repository.
In your QtCreator Preferences → Devices → Android, you get easy access to Android SDK Manager. Please check that under Extras the Android Support Repository is installed:
In your Android Manifest you see a reference to resources @xml/filepaths. You have to add a new File filepaths.xml under android/res/xml:
<paths xmlns:android="http://schemas.android.com/apk/res/android"> <files-path name="my_shared_files" path="share_example_x_files/" /> </paths>
This is the mapping to the folder where Android will find your File to be shared. This Folder is inside your AppData Location. Remember: in blog part 1 we used a shared documents location to provide Files to other apps. Now for Android we don’t use a shared location but a path inside our AppData location. Starting the app I always check if the folder exists:
#if defined (Q_OS_IOS) QString docLocationRoot = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).value(0); #endif #if defined(Q_OS_ANDROID) QString docLocationRoot = QStandardPaths::standardLocations(QStandardPaths::AppDataLocation).value(0); #endif mDocumentsWorkPath = docLocationRoot.append("/share_example_x_files"); if (!QDir(mDocumentsWorkPath).exists()) { // create the QDir }
Last important part in Android Manifest specifies an Authority:
android:authorities="org.ekkescorner.examples.sharex.fileprovider"
This name must be unique – so it’s a good idea to use your package name and append .fileprovider.
QShareUtils Java Code
As a last step you must do some small changes in QShareUtils.java.
Import FileProvider and ShareCompat from android.support:
import android.support.v4.content.FileProvider; import android.support.v4.app.ShareCompat;
Reference the Authority as defined in AndroidManifest:
private static String AUTHORITY="org.ekkescorner.examples.sharex.fileprovider";
You must also create your Intents in a different way:
// the old way: Intent sendIntent = new Intent(); Intent sendIntent = ShareCompat.IntentBuilder.from(QtNative.activity()).getIntent();
You’re done