Android Tips

Assets

Les projets Android disposent d'un répertoire assets/ dans lequel on peut mettre les fichiers utiles au programme… Néanmoins ces fichiers sont uniquement disponibles dans le package APK et ne sont pas accessible directement via le système de fichier interne/externe. De plus ces fichiers sont le plus souvent stockés dans un format compressé (sauf mp3, png, …). On utilise alors l'AssetManager pour manipuler ces fichiers…

Dans le cas où l'on travaille avec la NDK en C, en se basant sur une Java Activity (et non pas une Native Activity), voilà comment faire…

testasset.c
#include "SDL_system.h"  // TRY DONT USE THIS
#include <jni.h>
#include <android/asset_manager.h>
#include <android/asset_manager_jni.h>
 
// retrieve the JNI environment.
JNIEnv* jnienv = (JNIEnv*)SDL_AndroidGetJNIEnv();   // REPLACE THIS
int version = (*jnienv)->GetVersion(jnienv);
// SDL_Log("version %d\n", version);
 
// retrieve the Java instance of the SDLActivity
jobject activity = (jobject)SDL_AndroidGetActivity();  // REPLACE THIS
 
// find the Java class of the activity. It should be SDLActivity or a subclass of it.
jclass activityclass = (*jnienv)->GetObjectClass(jnienv, activity);    
 
/* context = SDLActivity.getContext(); */
jmethodID mid = (*jnienv)->GetStaticMethodID(jnienv, activityclass, "getContext","()Landroid/content/Context;");
jobject context = (*jnienv)->CallStaticObjectMethod(jnienv, activityclass, mid);
jclass contextclass = (*jnienv)->GetObjectClass(jnienv, context);
 
/* assetManager = context.getAssets(); */
mid = (*jnienv)->GetMethodID(jnienv, contextclass, "getAssets", "()Landroid/content/res/AssetManager;");
jobject assetmanager = (*jnienv)->CallObjectMethod(jnienv, context, mid);
 
// finally get AAssetManager instance
AAssetManager* mgr = AAssetManager_fromJava(jnienv, assetmanager);
if(!mgr)  ERROR("Fail to get AAssetManager\n");
 
AAsset* asset = AAssetManager_open(mgr, "game_easy.txt", AASSET_MODE_UNKNOWN);
if(!asset) ERROR("Fail to get file %s from Assets\n", "game_easy.txt");
 
/* AAsset_openFileDescriptor() only works with uncompressed files as mp3, png, ... */
// off_t start, length;
// int fd = AAsset_openFileDescriptor(asset, &start, &length);
// SDL_Log("fd = %d\n", fd);
 
/* Use either AAsset_read or AAsset_getBuffer. */
 
// copy all files on local storage */
 
AAssetDir* assetDir = AAssetManager_openDir(mgr, "");
const char* filename = (const char*)NULL;
while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {
  AAsset* asset = AAssetManager_open(mgr, filename, AASSET_MODE_STREAMING);
  char buf[BUFSIZ];
  int nb_read = 0;
  FILE* out = fopen(filename, "w");
  while ((nb_read = AAsset_read(asset, buf, BUFSIZ)) > 0)
    fwrite(buf, nb_read, 1, out);
  fclose(out);
  AAsset_close(asset);
}
AAssetDir_close(assetDir);
 
 
// env->DeleteLocalRef(activity);
// env->DeleteLocalRef(activityclass);

Bon il faut nettoyer ce code pour pouvoir se passer complètement des appels à la SDL System. Ne pas oublier de faire un link avec -landroid.