如何使用Gradle向NDK项目添加资源(图像、声音文件、着色器等)



在这个代码库的PC版本中,我只拥有以下目录结构:

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

因此,例如,从我的C++代码中,我可以简单地请求fopen("resources/images/blah0.png",...)

对于android,它似乎是所必需的

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

不幸的是,file即将出现nullptr,可能是因为它找不到资源树。

我的build.gradle脚本有以下片段:

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

^这指向该列表顶部列出的相同资源目录。


我需要做什么来确保上面的资源层次结构被简单地转移到我的.apk中,以便可以通过上面的AAssetManager片段访问它


一些额外的实验:

我将assets.srcDirs路径更改为some/random/path/on/my/hd,然后运行

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

其简单地列举在顶部目录中找到的文件。我注意到它枚举了some/random/path/on/my/hd中的所有文件,但没有枚举目录。(当我把它指向我的resources文件夹时,它什么也不枚举(。我不知道这是因为AAssetDir_getNextFileName实际上只获得文件,还是gradle的srcDirs只复制文件,或者整个AAssetManager生态系统只在平面目录上工作,等等。

我感到惊讶的是,没有明确的文档显示";包括具有NDK应用程序的资源目录";,因为这似乎是一件非常正常的事情需要做


编辑:我被要求澄清:";如何运行cmake";。作为build.gradle文件的一部分,我有以下片段:

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

好的,所以我的问题有三个:

  1. gradle负责构建我的cmake项目,该项目构建资源文件夹。由于cmake过程和资产打包之间没有明确的依赖关系,它似乎是在一个不可预测的时间(可能在构建完成之前(从该文件夹中提取的。(如果有人知道如何指定这样的依赖项,请告诉我!(
  2. 当我将文件夹设置为resources时,不会导致root/resources/{images,shaders};得到CCD_ 15。(如果有人知道如何指定使用前者,请告诉我!(
  3. AAssetDir_getNextFileName不枚举文件夹。(对此我无能为力!(
  1. 我建议简单地使用AAssetManager_open(aassman, "/images/blah0.png")而不是fopen("resources/images/blah0.png", "r"),但如果它对您非常重要,您可以设置assets.srcDirs 'build/cmake/release/arm64-v8a并排除除"resources"之外的所有内容。

  2. 以下是一个纯C++解决方案的概要。或者,您也可以通过JNI调用Java API(如这里所示(。

目前,转移资源的入口可以正常化。目前,我只能想到AAssetManager。所以这个问题的本质是:如果在cmake中,将资源复制到"assets.srcDirs"中?

但不幸的是,在当前的NDK cmake中没有相对稳定的输出路径。因此,我们无法直接为"assets.srcDirs"设置稳定的路径。

但我在CMAKE中找到了"CMAKE_ANDROID_ASSETS_DIRECTORIES"。根据标准,此宏定义将指向"assets.srcDirs"。

要做到这一点,我们只需要在cmake中编写一个复制脚本(如下所示(,并在每次编译后将资源复制到"cmake_ANDROID_ASSETS_DIRECTORIES"目录中。

此外,cmake的执行阶段将早于android工作室中的"AssetPack"。因此,cmake复制的资源最终会正确进入android apk。

当然,前线是一个理想的情况"CMAKE_ANDROID_ASSETS_DIRECTORIES"未包含在ANDROID studio NDK脚本标准中。为此,我们需要手动将"CMAKE_ANDROID_ASSETS_DIRECTORIES"定义添加到build.gradle文件和CMAKE编译参数中。特定的脚本可以在build.gradle文件中添加以下定义:

android {
defaultConfig {
externalNativeBuild {
cmake {
arguments "-DCMAKE_ANDROID_ASSETS_DIRECTORIES=${android.sourceSets.main.assets.srcDirs[0]}"
}
}
}
}

关于cmake如何复制资源,可以参考以下内容:

add_custom_command(
TARGET ${target}
POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"${RES_BASE_PATH}/${FNAME}"
"${CMAKE_ANDROID_ASSETS_DIRECTORIES}/${FNAME}"
COMMENT "Copy ${FNAME}"
)

请将"${target}"更改为"add_target"中显示的名称${RES_BASE_PATH}'是资源的根路径。请将"${FNAME}"设置为您的相对目录路径"${RES_BASE_PATH}"。

最新更新