Opening Files with Qt on Android
After addressing Android support in KF5Notifications another fairly generic task that so far required Android specific code is next: opening files. Due to the security isolation of apps and the way the native “file dialog” works on Android this is quite different from other platforms, which makes application code a bit ugly. This can be fixed in Qt though.
Qt 5.12 and before
On most platforms, allowing the user to open a file in an application works like this:
- Request the native file dialog via the corresponding widget or QML API, both of which go through the same internal platform integration plugin in Qt.
- Retrieve a file path from the file dialog.
- Open that path with QFile.
On Android so far we had to do the following:
- Request the native “file dialog” (it’s essentially the file brower app) via an Intent.
- Retrieve a
content:
URL from that Intent. - Use the Java ContentResolver API to open a file descriptor for that
content:
URL. - Pass that file descriptor to C++ and read it via QFile.
While the Intent details could be hidden behind the native file dialog abstraction in Qt, the problem then is still that the returned URL isn’t pointing to a local file that subsequent code might expect. There’s a good reason why Android does it that way though, as this allows applications to only access files that the user explicitly selected, without the need of full file system access permissions.
Qt 5.13 and beyond
A way to address this is a QAbstractFileEngine implementation to add support for content:
URLs to QFile.
This is the same approach taken already for e.g. asset:
URLs. It’s actually not particularly complicated
as all we need to do is obtain a file descriptor for a content:
URL, and then hand over to the existing
regualr file system backend, which implements everything else we need already.
KDE Itinerary is already using this approach as a testing ground, and this week this also landed upstream in Qt, to be included in the 5.13 release.
At the same time Nicolas added support for native file dialogs on Android, as well as content URL support in QML. With all that combined opening a file should (almost) work with identical code on all platforms.
One small caveat remains, the fact that you have to deal with URLs correctly throughout your file handling code.
If you at some point convert to a local file path, this is going to break when encountering a content:
URL.