Retrieving Folder Contents - SDL_RWops or Asset Manager?

I’ve just discovered the SDL_RWops functions for pulling out Android assets etc. Very cool. The only question I have is “Is it possible to get a list of folder contents?”.

In the iOS version of my app, I copy files from my iOS ‘bundle’ into the app’s working folder. I want to be able to do the same thing with my Android app - ie - copy all files from the .APK’s assets folder into my app’s working folder. But… I don’t want to have to list each file that I want to copy. There must be a way of enumerating through these files using SDL in a cross-platform manner, surely?

If not I’m going to have to find out how to use the Android Asset Manager… and at the moment I have no idea how to get the JNI ‘env’ value from within my SDL app. Would I have to purposely modify SDL_Activity.java in order to pass the JNI environment values back into my SDL C++ app?

How do you get the ‘env’ or ‘assetManager’ parameters below from within an SDL C++ app?

Code:
AAssetManager_fromJava (JNIEnv *env, jobject assetManager)

For reference, this is what I do…

I extend the SDLActivity class for my app, in Java:

public class TangibleMath extends SDLActivity
{
public String list_assets(String path, boolean get_directories, boolean
get_files) {
List files = new LinkedList();
if(path.length() > 1 && path.charAt(path.length()-1) == ‘/’)
path = path.substring(0, path.length()-1);

try {
String ls = getAssets().list(path);
for(String file : ls) {
// Lame problem… AssetManager::list() is super slow (does it unpack the
whole apk each time?).
// This is a lame workaround, but assumes files have extensions and
directories don’t.
boolean has_dot = file.contains(“.”);
if((get_files && has_dot) || (get_directories && !has_dot))
files.add(file);
}
} catch (IOException e) {
e.printStackTrace();
}
return files.toArray(new String[files.size()]);
}
}

Then in C++, I do this in my directory listing function (fileList is a
std::liststd::string):

if(dirname.size() > 0 && dirname[0] == '/')  // Absolute file name, not

an asset
{
fileList = ioListUsingOpendir(dirname, directories, files);
}
else // Look in assets
{
// retrieve the JNI environment.
JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();

    // retrieve the Java instance of the SDLActivity
    jobject activity = (jobject)SDL_AndroidGetActivity();

    // find the Java class of the activity. It should be SDLActivity or

a subclass of it.
jclass clazz( env->GetObjectClass(activity) );

    // find the identifier of the method to call
    jmethodID method_id = env->GetMethodID( clazz, "list_assets",

“(Ljava/lang/String;ZZ)[Ljava/lang/String;” );

    // Prepare Java arguments
    char* path_str_storage = new char[dirname.size()+1];
    strcpy(path_str_storage, dirname.c_str());
    jstring path_str = env->NewStringUTF(path_str_storage);
    jboolean dirs_j = directories;
    jboolean files_j = files;

    // call the Java method
    jobjectArray stringArrays = (jobjectArray) env->CallObjectMethod(

activity, method_id, path_str, dirs_j, files_j);

    delete[] path_str_storage;

    int size = env->GetArrayLength(stringArrays);

    for(int i = 0; i < size; i++)
    {
        jstring string = (jstring)

env->GetObjectArrayElement(stringArrays, i);
const char* myarray = env->GetStringUTFChars(string, 0);

        fileList.push_back(myarray);

        env->ReleaseStringUTFChars(string, myarray);
        env->DeleteLocalRef(string);
    }

    // clean up the local references.
    env->DeleteLocalRef(activity);
}

Using JNI with C instead of C++ is very similar, you just have to pass
around the extra self/this object argument if I recall correctly.

Jonny DOn Fri, Jun 3, 2016 at 5:50 PM, SparkyNZ wrote:

I’ve just discovered the SDL_RWops functions for pulling out Android
assets etc. Very cool. The only question I have is “Is it possible to get a
list of folder contents?”.

In the iOS version of my app, I copy files from my iOS ‘bundle’ into the
app’s working folder. I want to be able to do the same thing with my
Android app - ie - copy all files from the .APK’s assets folder into my
app’s working folder. But… I don’t want to have to list each file that I
want to copy. There must be a way of enumerating through these files using
SDL in a cross-platform manner, surely?

If not I’m going to have to find out how to use the Android Asset
Manager… and at the moment I have no idea how to get the JNI ‘env’ value
from within my SDL app. Would I have to purposely modify SDL_Activity.java
in order to pass the JNI environment values back into my SDL C++ app?

How do you get the ‘env’ or ‘assetManager’ parameters below from within an
SDL C++ app?

Code:

AAssetManager_fromJava (JNIEnv *env, jobject assetManager)


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

Jonny D wrote:

For reference, this is what I do…

?? ?? ?? ?? // retrieve the JNI environment.
?? ?? ?? ?? JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv();

?? ?? ?? ?? // retrieve the Java instance of the SDLActivity
?? ?? ?? ?? jobject activity = (jobject)SDL_AndroidGetActivity();

Oh excellent! The above lines are what I wanted to see. I’ve written an app in the past that is Java based but uses some of my cross-platform C++ code so I’m familiar with JNI etc. Sometimes its just getting bits of ‘glue’ that I find fiddly and frustrating. I had no idea I could get the JNI environment via an SDL call.

Might give extending the SDLActivity a try too. Thanks for the info.

Jonny D wrote:

For reference, this is what I do…

Just realised - another way would be to get the contents of the .APK file itself from with my C++ code. A .APK file is just a ZIP file so I could easily list the contents of the ZIP file too. :slight_smile:

Yeah, you can open the apk as a zip file. You need to know the absolute
path of the apk in order to do that. Also, reading zip files nested inside
the apk has been problematic, in my experience.

Jonny DOn Sat, Jun 4, 2016 at 4:22 PM, SparkyNZ wrote:

Jonny D wrote:

For reference, this is what I do…

Just realised - another way would be to get the contents of the .APK file
itself from with my C++ code. A .APK file is just a ZIP file so I could
easily list the contents of the ZIP file too. [image: Smile]


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

Jonny D wrote:

?? ?? ?? ?? // Prepare Java arguments
?? ?? ?? ?? char* path_str_storage = new char[dirname.size()+1];
?? ?? ?? ?? strcpy(path_str_storage, dirname.c_str());
?? ?? ?? ?? jstring path_str = env->NewStringUTF(path_str_storage);

Hi Jonny. What are you passing in for ‘dirname’ when you want to list the files within the .APK? I’m guessing this is the path to the .APK file but how are you determining that?

My method uses the assets folder in the apk, just as SDL_rwops does.
dirname is a relative path in the assets folder. E.g. I have a
data/images folder, so dirname would be “data/images” when I want to list
the contents of myapp.apk/assets/data/images. So the way I have it, you
can’t list arbitrary files in the apk, only assets.

Jonny DOn Sunday, June 5, 2016, SparkyNZ wrote:

Jonny D wrote:

? ? ? ? // Prepare Java arguments
? ? ? ? char* path_str_storage = new char[dirname.size()+1];
? ? ? ? strcpy(path_str_storage, dirname.c_str());
? ? ? ? jstring path_str = env->NewStringUTF(path_str_storage);

Hi Jonny. What are you passing in for ‘dirname’ when you want to list the
files within the .APK? I’m guessing this is the path to the .APK file but
how are you determining that?

Jonny D wrote:> My method uses the assets folder in the apk, just as SDL_rwops does. ??dirname is a relative path in the assets folder.?? E.g.??I have a data/images??folder, so dirname would be “data/images” when I want to list the contents of myapp.apk/assets/data/images.?? So the??way I have it, you can’t list arbitrary files in the apk, only assets.

From what I’ve seen you can only get file lists for specifically named folders within the APK assets folders? I thought I’d be able to get a list of ‘assets’ subfolders back but I only get the assets folder ‘root’ files. I have to specifically ask for subfolder contents with AAssetManager_openDir(). In my case I’m specifically asking for my “Fonts” subfolder but I guess that’s good enough really. :slight_smile: Thanks for your help.