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

问题描述 投票:0回答:3

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

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

所以,例如,从我的 C++ 代码中,我可以简单地请求

fopen("resources/images/blah0.png",...)

对于安卓,它似乎需要

#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中的所有

files
,但没有列举directories。 (当我将它指向我的
resources
文件夹时,它什么也没列举)。我不知道那是因为
AAssetDir_getNextFileName
字面上只获取files,或者如果gradle的
srcDirs
copies文件,或者如果整个
AAssetManager
生态系统只适用于平面目录,或者什么。

令我惊讶的是,没有明确的文档显示“在您的 NDK 应用程序中包含资源目录”的用例,因为这似乎是一件非常正常的事情。


edit:有人要求我澄清:“cmake 是如何运行的”。作为我的

build.gradle
文件的一部分,我有以下片段:

  externalNativeBuild {
    cmake {
      version "3.18.1"
      path "../CMakeLists.txt"
      buildStagingDirectory buildDir
    }
  }
android c++ gradle android-ndk
3个回答
2
投票

好吧,我的问题有三方面:

  1. gradle 负责构建我的 cmake 项目,该项目构建了资源文件夹。因为在 cmake 进程和资产打包之间没有给出明确的依赖关系,它似乎是在不可预测的时间(可能在其构建完成之前)从该文件夹中提取的。 (如果有人知道如何指定这样的依赖关系,请告诉我!)
  2. 当我将文件夹设置为
    resources
    时,它doesn't导致
    root/resources/{images,shaders}
    ;结果是
    root/{images,shaders}
    。 (如果有人知道如何指定而不是前者,请告诉我!)
  3. AAssetDir_getNextFileName
    枚举文件夹。 (对此我无能为力!)

1
投票
  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(如here)。


0
投票

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

但遗憾的是,目前的NDK cmake中还没有比较稳定的输出路径。所以我们没有办法直接为'assets.srcDirs'设置一个稳定的路径。

但是我在cmake中找到了'CMAKE_ANDROID_ASSETS_DIRECTORIES'。根据标准,这个宏定义将指向'assets.srcDirs'。

为此,我们只需要在cmake(如下给出)中编写一个复制脚本,每次编译后将资源复制到'CMAKE_ANDROID_ASSETS_DIRECTORIES'目录下即可。

另外,cmake的执行阶段会早于android studio中的'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}”目录路径。

© www.soinside.com 2019 - 2024. All rights reserved.