Comment puis-je ajouter des ressources (images, fichiers son, shaders, etc…) à un projet NDK avec Gradle?

Aug 19 2020

Dans la version PC de cette base de code, j'ai simplement la structure de répertoires suivante:

 - myApp.exe
 - resources
 - - images
 - - - blah0.png
 - - - blah1.png
 - - shaders
 - - - blahA.spv
 - - - blahB.spv

Donc, à partir de mon code C ++, je peux simplement demander fopen("resources/images/blah0.png",...), par exemple.

Avec Android, il semble plutôt nécessaire de

#include <android/native_activity.h>
...
AAsset* file = AAssetManager_open(aassman, "resources/images/blah0.png", AASSET_MODE_STREAMING);
size_t len = AAsset_getRemainingLength64(file);
char *buff = malloc(len);
size_t read = AAsset_read(file, buff, len);
AAsset_close(file);

Malheureusement, cela filearrive nullptr, probablement parce qu'il ne trouve pas cet arbre de ressources.

Mon script build.gradle contient l'extrait de code suivant:

  sourceSets {
    main {
      manifest.srcFile 'AndroidManifest.xml'
      assets.srcDirs 'build/cmake/release/arm64-v8a/resources'
    }
  }

^ Cela pointe vers le même répertoire de ressources décrit en haut de cette liste.


Que dois-je faire pour m'assurer que la hiérarchie des ressources ci-dessus est simplement transférée dans mon .apk de sorte qu'elle puisse être accessible via l' AAssetManagerextrait ci-dessus?


Quelques expérimentations supplémentaires:

J'ai changé le assets.srcDirschemin vers some/random/path/on/my/hd, puis j'ai couru

  AAssetDir *rootAssets = AAssetManager_openDir(aassman, "");
  const char *f = AAssetDir_getNextFileName(rootAssets);
  while(f)
  {
    print(f);
    f = AAssetDir_getNextFileName(rootAssets);
  }
  AAssetDir_close(rootAssets);

qui énumère simplement les fichiers trouvés dans le répertoire supérieur. J'ai remarqué qu'il a énuméré tous les fichiers qui étaient dans some/random/path/on/my/hd, mais aucun des répertoires . (Quand je le pointe vers mon resourcesdossier, il n'énumère rien). Je n'ai aucune idée si c'est parce que AAssetDir_getNextFileNamelittéralement ne reçoit que des fichiers , ou si gradle srcDirsne copie que des fichiers, ou si tout l' AAssetManagerécosystème ne fonctionne que sur des répertoires plats, ou quoi.

Je suis étonné qu'il n'y ait pas de documentation claire montrant le cas d'utilisation de "inclure un répertoire de ressources avec votre application NDK", car cela semble être une chose vraiment normale à faire.


edit: on m'a demandé des éclaircissements concernant "comment cmake est exécuté". J'ai dans mon build.gradlefichier, l'extrait suivant:

  externalNativeBuild {
    cmake {
      version "3.18.1"
      path "../CMakeLists.txt"
      buildStagingDirectory buildDir
    }
  }

Réponses

1 Phildo Aug 18 2020 at 23:23

Ok donc mon problème était triple:

  1. gradle est en charge de la construction de mon projet cmake qui construit le dossier des ressources. comme il n'y a pas de dépendance explicite entre le processus cmake et le conditionnement des actifs, il semblait avoir été extrait de ce dossier à un moment imprévisible (potentiellement avant la fin de sa construction). (Si quelqu'un sait comment spécifier une telle dépendance, faites-le moi savoir!)
  2. quand je mis le dossier à resources, il ne résulte en root/resources/{images,shaders}; il en résulte root/{images,shaders}. (Si quelqu'un sait comment spécifier de faire le premier, merci de me le faire savoir!)
  3. AAssetDir_getNextFileName n'énumère pas les dossiers. (Je ne peux rien y faire!)
1 AlexCohn Aug 24 2020 at 15:54
  1. Je suggérerais d'utiliser simplement à la AAssetManager_open(aassman, "/images/blah0.png")place de fopen("resources/images/blah0.png", "r"), mais si c'est si important pour vous, vous pouvez définir assets.srcDirs 'build/cmake/release/arm64-v8aet exclure tout sauf "resources".

  2. Voici un aperçu d'une solution purement C ++. Vous pouvez également appeler l'API Java (comme ici ) via JNI.