[Android-development] Attempting a port to Android - Notes and Suggestions

Eskil Abrahamsen Blomfeldt eskil.abrahamsen-blomfeldt at digia.com
Mon Feb 25 14:36:51 CET 2013


On 02/25/2013 01:52 PM, Patricia Aas wrote:
> B ) A lot of resource file path fiddling : this is because all of my
> resources are in assets - which means file paths are all broken, Qt seems
> to assume they are in files, which is completely empty, unless you
> actually copy stuff there. Path fiddling results:
>
> for cpp : If I change everywhere to use assets:/ then they are found, but
> all my code as #ifdef __ANDROID__ everywhere
> for qml : I don't even know if I can have #ifdefs in qml files, so what I
> did was copy all of my pngs into files on startup, in java code, which
> takes forever (see AssetHandler.java attached for how I did that)
>
> Suggestion : The Qt port should transparently handle all paths to be in
> either files or assets, and relative paths should work across these - see
> point D about qmls in qrc's.

Most paths you specify in Qt are file system paths, i.e. relative to the 
working directory. This is not so easily solvable, I think, because we 
don't have the concept of search paths (where passing a relative path to 
e.g. QPixmap would make it search a set of different root paths for 
instance.)

I wonder how much would break if the "working directory" was the assets 
root...

I think the main cross-platform way of doing this if you can't store 
your resources as qrc, is to have some platform-specific path resolving 
mechanism in your code (which would limit the number of #ifdef ANDROID 
to 1). Then it would resolve to assets in Android, to the working 
directory on desktop, etc. I think other mobile platforms might have the 
need for similar customization. You would have to expose it as a 
property in QML and update all the paths there (file:/ for desktop, 
assets:/ for Android, etc.).

Or it might be possible to add a new storage location to (the aptly 
named) QDesktopServices, but the code you have which specifies loading 
from the file system will still have to be updated.

> C.3 : Even if C.1 and C.2 had worked, it still wouldn't work, because 
> when
> it does find the qmldir, it looks for the plugin lib in the same 
> directory
> and doesn't search the whole QML_IMPORT_PATH for it making it impossible
> to have them separated.

Would it be possible to put one qmldir for the plugin next to the plugin 
in lib/, and another for the QML files next to the QML files in assets?

>
>
> Second possibility that I have not managed to make work is to make a
> directory structure in libs/armeabi-v7a where the qmldirs are placed, 
> this
> has two issues even if I could make it work : 1) it is very non-standard
> Android 2) because of 1 the tools support will be non-existent

It will also mean duplicating the QML files in the import for every 
architecture you want to support, I guess.

>
> D ) qmls in qrc's:
>
> Now given the following hack for C) : I copied my imports folder from
> assets into files and my qml plugin so's into the folders containing the
> corresponding qmldir (see AssetHandler.java attached for how I did that)
>
> So now I got my plugins up and running.
>
> None of my images were available because the qmls are qrc's and the 
> images
> are in assets, the path in the qmls was "file:images/..." and that
> apparently meant the files directory - which now only contains the 
> imports
> directory I copied.

I think this is a down-side of specifying file system paths in the QMLs 
explicitly.

>
> I have three choices : 1) copy all of the images from assets into 
> files 2)
> change all of the "file:images/..." to "assets:/images" or 3) make some
> qml code that depended on a property in cpp that used an #ifdef 
> __ANDROID__
>
> Number 2) is not possible - it would break existing products and, even if
> it didn't, I tried it, and it still did not find them, relative paths
> across qrc and assets apparently is not ok.
> Number 3) would not fly with the rest of the developers, they felt I had
> already too many ifdefs ;)
> so left with Number 1) that is what I did, now that will not fly either :
> the startup delay with copying the files is not acceptable.
>
> So I have no workaround that is acceptable for production.

When you use the file:/ scheme, you are telling QML to load the files 
from the file system. That's what the scheme is for. This is probably a 
work-around for wanting to have the QML-files in the qrc and the images 
stored on the file system relative to the executable. Maybe it's because 
the qrc files became to large for the compiler (in which case it might 
work to split it up in several qrcs instead, since Qt's resource system 
can easily adapt to that.) If there are limitations to the size of the 
application binary that make it impossible to put the resources in the 
qrc, it's also possible to make an external resource file which could be 
bundled with the application. On Android, if you have a very large set 
of resources, this will usually be distributed as a separate 
downloadable file (.obb) since the possible size of an .apk is very 
limited in Google Play. There is no out-of-the-box solution for this in 
the tooling yet though, so it would mean editing the Java code.

To minimize the impact for other platforms, what I would do would be to 
add a platform abstraction file (android: SOURCES += 
platform_android.cpp else: SOURCES += platform_desktop.cpp),  with an 
asset-scheme property which is exposed to the QML code. In the desktop 
implementation it will be "file:" whereas it will be "assets:/" on 
Android. Then you can update the QML to use the correct scheme for 
loading the files based on this property. You could also make a special 
AssetImage.qml or something which automatically prepends the scheme to 
the paths, so that you can easily update it later if you need to.

>
> Suggestion : Mentioned in B already, but relative paths from qrc to 
> assets
> would have to work, plus the resource files would have to be found even
> though they are in assets, without the "assets:/" being hardcoded in the
> qmlfile

We did have a suggestion to enable qrc:/ to also load from assets:/ so 
that you can have a single resource prefix, but in your case that 
wouldn't work since you are explicitly telling QML to load from the file 
system with the file: prefix. So far we've opted against it, since it 
would be a little bit too magic and we thought qrc:/ would be the scheme 
of choice for writing cross-platform resource handling.

>
> E ) Order of command-line arguments :
>
> Now this is a silly thing in our code really, but we need to support
> existing client code. Our main expect to get two parameters first in the
> command line args, now I can add command line args in
> QtActivity.java::APPLICATION_PARAMETERS but these are added after the
> "-platform android" parameter added automatically. I added #ifdef
> __ANDROID__ to fix that up :D

Ah, I think removing "-platform android" and making it the default is 
needed. We shouldn't really force command line arguments on the apps.

Thanks for being so thorough in documenting the problems you had. I 
think a lot of this should be addressed and you have good suggestions. I 
do think your code needs to be updated a bit as well, though, to make it 
more generic, since the idea of accessing files using file:/ does not 
seem portable to me, since not all platforms will support the idea of a 
regular file system and definitely not the idea that the application 
bundle is a regular directory structure in the file system. Overriding 
file:/ for Android code would break any case where you specifically want 
to load a file from the file system (which is also possible on Android).

Do you think any of the suggestions I've made would be helpful to you?

-- Eskil



More information about the Android-development mailing list