How can I add resources (images, sound files, shaders, etc...) to an NDK project with Gradle?

Viewed 254

In the PC version of this codebase, I simply have the following directory structure:

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

So, from my C++ code, I can simply request fopen("resources/images/blah0.png",...), for example.

With android, it appears to instead be required to

#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);

Unfortunately, file is coming up nullptr, likely because it can't find that resources tree.

My build.gradle script has the following snippet:

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

^ That points to the same resources directory outlined at the top of this list.


What do I need to do to ensure that the above resources hierarchy gets simply transferred into my .apk such that it might be accessed via the AAssetManager snippet above?


Some additional experimentation:

I altered the assets.srcDirs path to some/random/path/on/my/hd, and then ran

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

which simply enumerates the found files in the top directory. I noticed that it enumerated all of the files which were in some/random/path/on/my/hd, but none of the directories. (When I point it to my resources folder, it enumerates nothing). I have no idea if that's because AAssetDir_getNextFileName literally only gets files, or if gradle's srcDirs only copies files, or if the whole AAssetManager ecosystem only works on flat directories, or what.

I'm astounded that there isn't clear documentation showing the use case of "including a resources directory with your NDK app", as that seems like a really normal thing to need to do.


edit: I was asked for clarification re: "how cmake is run". I have as part of my build.gradle file, the following snippet:

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

Ok so my problem was three fold:

  1. gradle is in charge of building my cmake project which constructs the resources folder. because there is no explicit dependency given between the cmake process and the packing of assets, it seemed to have been pulling from that folder at an unpredictable time (potentially before its construction is finished). (If someone knows how to specify such a dependency, please let me know!)
  2. when I set the folder to be resources, it doesn't result in root/resources/{images,shaders}; it results in root/{images,shaders}. (If someone knows how to specify to instead do the former, please let me know!)
  3. AAssetDir_getNextFileName does not enumerate folders. (There's nothing I can do about this!)
  1. I would suggest to simply use AAssetManager_open(aassman, "/images/blah0.png") instead of fopen("resources/images/blah0.png", "r"), but if it's so important to you, you can set assets.srcDirs 'build/cmake/release/arm64-v8a and exclude everything except "resources".

  2. Here is an outline of a pure-C++ solution. Alternatively, you can also call the Java API (as here) via JNI.

Related