Android resource management

Another slight hitch here: thus far I’ve been using “/data/” folder for resources, which is fine but means that the APK file and data files need to be uploaded separately from the app itself, a process which might seem trivial with the right script but which is beyond the layman and obviously incompatible with the appstore. My brief is that resources will need to be placed in a single APK archive, compressed, so impossible for me to get to file path to.

The only solution I can think of is to uncompress and export all the data to the file-system when the application is first loaded, but I’m not even sure if this is possible. It’s possible to “prefer” external installation (on the sd card, so in /data/) but there’s no way of forcing it if I understand correctly.

Ideas anyone?

Thanks,

William

On Lun 07 Nov 2011 17:17:11 wilbefast escribi?:

Another slight hitch here: thus far I’ve been using “/data/” folder for
resources, which is fine but means that the APK file and data files need
to be uploaded separately from the app itself, a process which might seem
trivial with the right script but which is beyond the layman and obviously
incompatible with the appstore. My brief is that resources will need to be
placed in a single APK archive, compressed, so impossible for me to get to
file path to.

The only solution I can think of is to uncompress and export all the data
to the file-system when the application is first loaded, but I’m not even
sure if this is possible. It’s possible to “prefer” external installation
(on the sd card, so in /data/) but there’s no way of forcing it if I
understand correctly.

Ideas anyone?

I don’t completely understand what you are asking, so apologies in advance if
I’m answering a question you didn’t ask, but SDL supports asset reading in
Android, just place your files in “assets” in the root of your Android project,
and they’ll be picked up by the Android build system when you build the
package. Accessing them (in read only mode at least) is trivial using IMG_Load
or any other function that works through RWops.
If you need to acces files somewhere else, I think you can just use fopen,
fread,etc.

Gabriel.

gabomdq wrote:

On Lun 07 Nov 2011 17:17:11 wilbefast escribi?:SDL supports asset reading in
Android, just place your files in “assets” in the root of your Android project,
and they’ll be picked up by the Android build system when you build the
package. Accessing them (in read only mode at least) is trivial using IMG_Load
or any other function that works through RWops.

Gabriel.

Not sure I understand. I’ve always given IMG_Load a filename, which clearly isn’t possible here as the file is compressed, inside an archive, somewhere in “/system/app” (I think). Yes, I know that since a .apk is just a .zip it should be theoretically possible to open it and read the contents with some library (zlib?). An yes, we can take this pointer and pass it to SDL (via RWops? Never heard of it up till now) or OpenGL directly.

But this seems like a rather dirty, round-about way of doing things, plus really dangerous to boot. I’d think it would be safest to send resources via the JNI, ie. open them in Java (Davlik has easy access to JNI contents) and pass them to the native code. What I’m wondering is whether the SDL port has anything like this implemented or whether it needs to be written from scratch. Is this what you meant?

But this seems like a rather dirty, round-about way of doing things, plus
really dangerous to boot. I’d think it would be safest to send resources
via the JNI, ie. open them in Java (Davlik has easy access to JNI
contents) and pass them to the native code. What I’m wondering is whether
the SDL port has anything like this implemented or whether it needs to be
written from scratch. Is this what you meant?

  1. Put a image.png inside an “assets” directory in the Android project root
    (that is where AndroidManifest.xml and build.xml live).
  2. Call IMG_Load(“image.png”)
  3. ndk-build, ant build, etc
  4. ???
  5. Profit.

SDL and Android work their magic behind the scenes, your image.png is going to
be placed inside the apk, and you don’t have to worry about compression, where
it is decompressed or when, it just works. If you want to know the details,
I’m afraid you’ll have to check for yourself in the source code.
This works for SDL_ttf as well if you want to load fonts for example using the
same technique (that’s as far as I’ve tried, _image and _ttf, though I think
anything that uses RWOps should work in the same way).

Gabriel.

gabomdq wrote:

  1. Put a image.png inside an “assets” directory in the Android project root
    (that is where AndroidManifest.xml and build.xml live).
  2. Call IMG_Load(“image.png”)
  3. ndk-build, ant build, etc

That’s nice and simple - I’ll give it a try…

Unfortunately it doesn’t seem to be working: IMG_Load fails to find the file in the working directory. This despite it being in the apk under /assets. Perhaps I’m using an older version of the port which doesn’t include this shortcut - is it a recent addition?

Unfortunately it doesn’t seem to be working: IMG_Load fails to find the
file in the working directory. This despite it being in the apk under
/assets. Perhaps I’m using an older version of the port which doesn’t
include this shortcut - is it a recent addition?

I don’t remember when these patches by Tim Angus where applied but I think it
was fairly recent, for more information you should check Bugzilla for the
"android" keyword, check the closed tickets, you’ll see this patch I’m
refering to, the multitouch stuff, and some other changes (like OpenGL ES 2
support).

Gabriel.

gabomdq wrote:

patches by Tim Angus

Found it:
http://bugzilla.libsdl.org/show_bug.cgi?id=1261

I guess it’s time I got the new release of Mercurial, since I don’t know whether the version I’m using is compatible with the patch. So: replaced the old SDL C code, plus the SDLActivity class with the new one.

Okay, so a little error:

Code:
11-08 23:54:53.890: ERROR/AndroidRuntime(23069): Caused by: java.lang.UnsatisfiedLinkError: Library main not found
11-08 23:54:53.890: ERROR/AndroidRuntime(23069): at java.lang.Runtime.loadLibrary(Runtime.java:461)
11-08 23:54:53.890: ERROR/AndroidRuntime(23069): at java.lang.System.loadLibrary(System.java:557)
11-08 23:54:53.890: ERROR/AndroidRuntime(23069): at org.libsdl.app.SDLActivity.(SDLActivity.java:43)

I replaced:

Code:
System.loadLibrary(“SDL”);
//System.loadLibrary(“SDL_image”);
//System.loadLibrary(“SDL_mixer”);
//System.loadLibrary(“SDL_ttf”);
System.loadLibrary(“main”);

With what I had before:

Code:
System.loadLibrary(“SDL”);
System.loadLibrary(“SDL_image”);
System.loadLibrary(“mikmod”);
System.loadLibrary(“SDL_mixer”);
System.loadLibrary(“SDL_ttf”);
System.loadLibrary(“main”);

Working now, except I notices touches are no longer interpreted as mouse clicks so I’ll need to modify my code to support the new multi-touch stuff… Still, thanks a lot gabomdq, I can now load images from the apk :smiley:

This works so well I forgot myself a moment and tried to use it for TinyXML - dang, looks like I’ll still need to write something that extracts the XML files. Well, if you’ll excuse me I’m off to cannibalise some code…

Did you look at TiXmlDocument::Parse()? I don’t know where the magic is
happening on Android, but if something like SDL_RWFromFile() works by
itself, then you might be able to pass the char data to Parse().

Jonny DOn Fri, Nov 11, 2011 at 4:54 PM, wilbefast wrote:

**
This works so well I forgot myself a moment and tried to use it for
TinyXML - dang, looks like I’ll still need to write something that extracts
the XML files. Well, if you’ll excuse me I’m off to cannibalise some code…


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Jonny D wrote:

Did you look at TiXmlDocument::Parse()? ?I don’t know where the magic is happening on Android, but if something like SDL_RWFromFile() works by itself, then you might be able to pass the char data to Parse().

Good idea :slight_smile: only one way to find out. Actually two ways: read the code or try it and see what happens. I’m too impatient to read code so I switched to loading using RWops to see what would happen. Here are my results:

Code:
int io::read_text(const char* source_file, char* destination)
{
// Open the file
SDL_RWops *file;
file = SDL_RWFromFile(source_file, “r”);
ASSERT(file, “Opening file using SDL_RWops”);

// Read text from file
int n_blocks = SDL_RWread(file, destination, BLOCK_SIZE, MAX_BLOCKS);
// BLOCK_SIZE = 8, MAX_BLOCKS = 1024
SDL_RWclose(file);

// Make sure the operation was successful
ASSERT(n_blocks >= 0, "Reading blocks of data from SDL_RWops");
WARN_IF(n_blocks == MAX_BLOCKS, "Reading data from SDL_RWops",
                                "Buffer full so may be too small for data");

// Success!
return EXIT_SUCCESS;

}

Used as follows:

Code:
// Generate world XML file name based on number
char file_name[32];
WARN_IF((sprintf(file_name, “%sworld_%d.xml”, ASSET_PATH, world_number) < 0),
“Game::load_things”, “buffer to small to create formatted string”);

/// ATTEMPT TO OPEN THE XML FILE
// Open with SDL_RWops
char file_contents[io::MAX_BLOCKS];
ASSERT(io::read_text(file_name, file_contents) == EXIT_SUCCESS,
        "Reading XML World contents");

// Pass string to the TinyXML document
TiXmlDocument doc;
doc.Parse(file_contents);
ASSERT_AUX(doc.Parse(file_contents), "Opening world XML file",
           doc.ErrorDesc());

Works on both Linux and Android :smiley:

Assertions are warning are used to wrap stderr or __android_log_print depending on platform. Long story short, XML can now be loaded from the assets folder. Thanks for the pointer :smiley:

Sweet.

Jonny DOn Sat, Nov 12, 2011 at 7:41 AM, wilbefast wrote:

**

Jonny D wrote:

Did you look at TiXmlDocument::Parse()? I don’t know where the magic is
happening on Android, but if something like SDL_RWFromFile() works by
itself, then you might be able to pass the char data to Parse().

Good idea [image: Smile] only one way to find out. Actually two ways:
read the code or try it and see what happens. I’m too impatient to read
code so I switched to loading using RWops to see what would happen. Here
are my results:

Code:

int io::read_text(const char* source_file, char* destination)
{
// Open the file
SDL_RWops *file;
file = SDL_RWFromFile(source_file, “r”);
ASSERT(file, “Opening file using SDL_RWops”);

// Read text from file
int n_blocks = SDL_RWread(file, destination, BLOCK_SIZE, MAX_BLOCKS);
// BLOCK_SIZE = 8, MAX_BLOCKS = 1024
SDL_RWclose(file);

// Make sure the operation was successful
ASSERT(n_blocks >= 0, "Reading blocks of data from SDL_RWops");
WARN_IF(n_blocks == MAX_BLOCKS, "Reading data from SDL_RWops",
                                "Buffer full so may be too small for

data");

// Success!
return EXIT_SUCCESS;

}

Used as follows:

Code:

 // Generate world XML file name based on number
char file_name[32];
WARN_IF((sprintf(file_name, "%sworld_%d.xml", ASSET_PATH,

world_number) < 0),
“Game::load_things”, “buffer to small to create formatted
string”);

/// ATTEMPT TO OPEN THE XML FILE
// Open with SDL_RWops
char file_contents[io::MAX_BLOCKS];
ASSERT(io::read_text(file_name, file_contents) == EXIT_SUCCESS,
        "Reading XML World contents");

// Pass string to the TinyXML document
TiXmlDocument doc;
doc.Parse(file_contents);
ASSERT_AUX(doc.Parse(file_contents), "Opening world XML file",
           doc.ErrorDesc());

Works on both Linux and Android [image: Very Happy]

Assertions are warning are used to wrap stderr or __android_log_print
depending on platform. Long story short, XML can now be loaded from the
assets folder. Thanks for the pointer [image: Very Happy]


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Blog post explaining all this in detail :slight_smile:
http://wilbefast.com/2011/11/16/tinyxmlsdl-glue-code/