Sharing Files on Android or iOS from or with your Qt App - Part 4

Welcome to Part 4 of my Blog series about Sharing Files to and from mobile Qt Apps.

Part 1  was 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 other native iOS Apps.
Part 4 implements FileProvider to share Files from your Qt App with native Android  Apps.

01_blog_overview

 

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 AndroidManifest.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:

02__sdk_manager_support_lib

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:

03_filepaths_xml

The content of filepaths.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 :)

As a positive side effect, it's now much safer to share Files because they are inside your App Sandbox located and not in public shared Folder.

Overview

Here‘s a short Overview about the Android FileProvider implementation:

04_fileprovider_overview

 

Some issues from Sharing Files to other Android Apps

Android: Sharing to Google Fotos App

If you try to edit an Image in Google Fotos App using the FileProvider, the Fotos App appears in the list of available Apps, but then reports that the File cannot be edited. Viewing works as before.

Only current workaround is to use another Foto Editing App.

Thanks

Thanks again to Thomas K. Fischer @taskfabric for his valuable input on this topic.

Have Fun

In the first part of this blog series, I told you that I needed sharing between Apps on Android and iOS for a DropBox – like customer App. This App is running very well since some months as inHouse App at customer site, so it's not publicly available. But my example App is Open Source and now it‘s a good time to download current Version from Github, build and run the Sharing Example App.

This was the last part of this blog series, but stay tuned for some other blogs about „Qt mobile Apps in the Enterprise“ and „QML Camera on Android and iOS“.


Blog Topics:

Comments