我正在尝试为用C ++编写的Android应用程序加载一些着色器文件。它使用的是NativeActivity
和native_app_glue
。我真的很难让Android Asset系统按预期工作。
我尝试过的最简单的案例是:
#include <android_native_app_glue.h>
void android_main(struct android_app *app) {
AAssetDir *dir = AAssetManager_openDir(app->activity->assetManager, "");
if (dir != nullptr) {
LOGD("Opened Dir");
LOGD("Filename: %s", AAssetDir_getNextFileName(dir));
AAssetDir_close(dir);
} else {
LOGE("Failed to open dir");
}
}
AAssetManager_openDir
返回一个有效的AAssetDir
ptr,但AAssetDir_getNextFileName
总是返回nullptr。 NDK的asset_manager.h
标题似乎意味着我的电话应该绝对有效。
/**
* Open the named directory within the asset hierarchy. The directory can then
* be inspected with the AAssetDir functions. To open the top-level directory,
* pass in "" as the dirName.
*
* The object returned here should be freed by calling AAssetDir_close().
*/
我似乎无法通过其他AAssetManager
调用的已知文件路径引用任何文件。
AAssetManager_open(app->activity->assetManager, "shaders/triangle.vert.spv", AASSET_MODE_BUFFER);
也失败,即使在我的APK我可以清楚地看到文件生活在assets/shaders
正确。我在Logcat中找不到我的应用程序中的任何相关错误。我在Android权限文档中找不到任何与需要某种权限来读取内部资产相关的内容。
我目前正在使用最新的NDK r19对抗Android 28。这是我正在使用的当前android-sdk包集:
Installed packages:
Path | Version | Description | Location
------- | ------- | ------- | -------
build-tools;27.0.3 | 27.0.3 | Android SDK Build-Tools 27.0.3 | build-tools\27.0.3\
emulator | 28.0.25 | Android Emulator | emulator\
ndk-bundle | 19.2.5345600 | NDK | ndk-bundle\
patcher;v4 | 1 | SDK Patch Applier v4 | patcher\v4\
platform-tools | 28.0.2 | Android SDK Platform-Tools | platform-tools\
platforms;android-21 | 2 | Android SDK Platform 21 | platforms\android-21\
platforms;android-28 | 6 | Android SDK Platform 28 | platforms\android-28\
tools | 26.0.1 | Android SDK Tools 26.0.1 | tools\
我目前通过部署到带有最新补丁的Pixel 2 XL进行测试。
我将资产放在错误的文件夹中吗?我错过了最近的一些许可变更吗?
编辑#1:
做了一些调查。在我的APK资源目录的根目录放置了一个test.txt
,所以APK现在有assets/test.txt
。我试过用以下方法打开这个文件的句柄:
AAsset *asset = AAssetManager_open(app->activity->assetManager, "test.txt",
AASSET_MODE_BUFFER);
if (asset != nullptr) {
LOGD("Opened test file");
AAsset_close(asset);
} else {
LOGE("Failed to open test file");
}
该应用程序将“无法打开测试文件”打印到Logcat。对于可能造成这种情况的原因仍然感到茫然。
编辑#2:回复第一个答案。
按照建议尝试更完整的代码示例不会产生任何新结果:
#include <android_native_app_glue.h>
void android_main(struct android_app *app) {
AAssetManager *assetManager = app->activity->assetManager;
if (assetManager != nullptr) {
AAssetDir *assetDir = AAssetManager_openDir(assetManager, "");
if (assetDir != nullptr) {
uint32_t fileOpenedCounter = 0;
const char *filename = (const char *)NULL;
while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {
AAsset *asset =
AAssetManager_open(assetManager, filename, AASSET_MODE_BUFFER);
if (asset != nullptr) {
LOGD("Opened test file");
fileOpenedCounter++;
char buf[1024];
int nb_read = 0;
while ((nb_read = AAsset_read(asset, buf, 27)) > 0) {
LOGD("buf: %s", buf);
}
AAsset_close(asset);
} else {
LOGE("Failed to open test file");
}
}
LOGD("Opened %d files from root directory", fileOpenedCounter);
AAssetDir_close(assetDir);
} else {
LOGE("Failed to open root directory");
}
} else {
LOGE("Asset Manager was invalid");
}
}
我从Logcat得到的只是调试日志:“从根目录打开0个文件”。这似乎意味着我拥有的AAssetManager指针是有效的,它可以打开目录,但它找不到任何文件或子目录。
试试下面的代码
AAssetManager *assetManager = AAssetManager_fromJava(env, assetManagerFromJava);
if(assetManager != nullptr) {
AAssetDir* assetDir = AAssetManager_openDir(assetManager, "");
const char* filename = (const char*)NULL;
while ((filename = AAssetDir_getNextFileName(assetDir)) != NULL) {
AAsset* asset = AAssetManager_open(assetManager, filename, AASSET_MODE_BUFFER);
if (asset != nullptr) {
ALOGI("Opened test file");
char buf[1024];
int nb_read = 0;
while ((nb_read = AAsset_read(asset, buf, 27)) > 0) {
ALOGI("buf: %s", buf);
}
AAsset_close(asset);
} else {
ALOGI("Failed to open test file");
}
}
AAssetDir_close(assetDir);
}
asset
指针很好,文件内容从Logcat打印,如下面的截图所示:
编辑#1:
对于您的具体情况,请尝试替换
AAssetManager *assetManager = AAssetManager_fromJava(env, assetManagerFromJava);
使用您自己的Native指针(请确保app->activity->assetManager
是一个正确的有效指针)
AAssetManager *assetManager = app->activity->assetManager
我已经弄清楚了。这是一个非常愚蠢的问题,我怀疑大多数会遇到,但我会在这里记录它。
我认为没有相关的一些背景故事。我没有使用Android Studio。我正在使用fips构建系统。它有一个包装APK的simple python script。该脚本是从CMake调用的。
我不明白aapt包装资产文件是怎么回事。所以我正在做的是运行一个后期构建脚本,它将运行aapt add
并将我的着色器文件添加到APK中,然后重新对齐并重新压缩APK。
再看一下aapt工具的帮助命令输出,我意识到在APK编译期间有一个-A
标志用于添加资产目录。我首先将我的资产不正确地添加到APK中
修复很简单:
assets
目录旁边。'-A', 'assets'
添加到fips打包脚本中的AAPT打包命令快速浏览一下这个变化:
# package the APK
cmd = [
AAPT,
'package',
'-v', '-f',
'-S', 'res',
'-M', 'AndroidManifest.xml',
'-A', 'assets',
'-I', SDK_HOME + 'platforms/android-' + args.version + '/android.jar',
'-F', args.path + args.name + '-unaligned.apk',
'bin'
]
是的。这与Android NDK API无关,而且与实际的APK打包步骤有关。太糟糕了,NDK API中没有任何内容可以报告找不到文件,这本来就是一个小举措。 aapt工具也没有警告说使用aapt add
并没有像我想象的那样真正地将资产添加到资产目录中。