fopen/frad APK资产来自安卓系统上的NativeActivity
fopen/fread APK Assets from NativeActivity on Android
我只能找到2010年及更早的解决方案。所以我想看看在这方面是否有更新的立场。
我想避免使用Java,而纯粹使用C++来访问存储在APK中的文件(有些小于或大于1MB)。使用AssetManager
意味着我不能像其他操作系统(包括iOS)上的其他文件一样访问文件。
如果没有,C++中是否有一种方法可以将fopen/frad映射到AssetManager API?
事实上,我找到了这个问题的非常优雅的答案,并在这里写了博客。
总结如下:
- AAssetManager API具有NDK绑定。这允许您从APK加载资产
- 可以将一组知道如何对任何内容进行读/写/查找的函数组合起来,并将它们伪装成文件指针(file*)
- 如果我们创建一个使用资产名称的函数,使用AssetManager打开它,然后将结果伪装成FILE*,那么我们就有了与fopen非常相似的东西
- 如果我们定义一个名为fopen的宏,我们可以将该函数的所有使用替换为我们的
我的博客有一篇完整的文章,以及你需要在纯C中实现的所有代码。我用它为Android构建lua和libogg。
简短回答
没有。AFAIK无法将C++中的fread/fopen映射到AAssetManager。如果是这样的话,它可能会将您限制为资产文件夹中的文件。然而,有一个变通办法,但并不简单。
长答案
使用C++中的zlib和libzip可以访问APK中任何位置的任何文件。需求:一些java、zlib和/或libzip(为了方便使用,所以这就是我的选择)。您可以在此处获取libzip:http://www.nih.at/libzip/
libzip可能需要一些修改才能在android上运行,但没什么大不了的。
步骤1:在Java中检索APK位置并传递给JNI/C++
String PathToAPK;
ApplicationInfo appInfo = null;
PackageManager packMgmr = parent.getPackageManager();
try {
appInfo = packMgmr.getApplicationInfo("com.your.application", 0);
} catch (NameNotFoundException e) {
e.printStackTrace();
throw new RuntimeException("Unable to locate APK...");
}
PathToAPK = appInfo.sourceDir;
将PathToAPK传递给C++/JNI
JNIEXPORT jlong JNICALL Java_com_your_app(JNIEnv *env, jobject obj, jstring PathToAPK)
{
// convert strings
const char *apk_location = env->GetStringUTFChars(PathToAPK, 0);
// Do some assigning, data init, whatever...
// insert code here
//release strings
env->ReleaseStringUTFChars(PathToAPK, apk_location);
return 0;
}
假设您现在有一个带有APK位置的std::字符串,并且您在libzip上有zlib,那么您可以执行以下操作:
if(apk_open == false)
{
apk_file = zip_open(apk_location.c_str(), 0, NULL);
if(apk_file == NULL)
{
LOGE("Error opening APK!");
result = ASSET_APK_NOT_FOUND_ERROR;
}else
{
apk_open = true;
result = ASSET_NO_ERROR;
}
}
从APK读取文件:
if(apk_file != NULL){
// file you wish to read; **any** file from the APK, you're not limited to regular assets
const char *file_name = "path/to/file.png";
int file_index;
zip_file *file;
struct zip_stat file_stat;
file_index = zip_name_locate(apk_file, file_name, 0);
if(file_index == -1)
{
zip_close(apk_file);
apk_open = false;
return;
}
file = zip_fopen_index(apk_file, file_index, 0);
if(file == NULL)
{
zip_close(apk_file);
apk_open = false;
return;
}
// get the file stats
zip_stat_init(&file_stat);
zip_stat(apk_file, file_name, 0, &file_stat);
char *buffer = new char[file_stat.size];
// read the file
int result = zip_fread(file, buffer, file_stat.size);
if(result == -1)
{
delete[] buffer;
zip_fclose(file);
zip_close(apk_file);
apk_open = false;
return;
}
// do something with the file
// code goes here
// delete the buffer, close the file and apk
delete[] buffer;
zip_fclose(file);
zip_close(apk_file);
apk_open = false;
不完全是fopen/frad,但它能完成任务。将其封装到您自己的文件读取函数中以抽象zip层应该非常容易。
- C++,系统无法执行指定的程序
- 在UNIX系统中使用DIR查找文件的字节大小
- 错误处理.将系统错误代码映射到泛型
- 当系统的卷被修改时,如何修改WASAPI环回捕获卷
- 有什么好的方法可以让系统调用代理允许在单元测试中进行模拟
- 在C++游戏中与库存系统作斗争
- 文件系统:复制功能的速度秘诀是什么
- c++17文件系统::recursive_directory迭代器()在mac上没有给出这样的目录,但在windows上
- 在gtest.中使用fff.h模拟系统API
- 如何制作无限制照明系统
- 系统.将数组移交给c#中动态加载的c++DLL时发生AccessViolationException
- 如何传递多个 std::文件系统选项?
- 遍历顺序由 std::文件系统directory_iterator给出
- C++系统找不到指定的文件错误
- 系统参数信息A 与 SPI_GETMOUSE 返回 0
- libstdc++ 文件系统中未初始化的用法?
- 如何在ECS框架中更新组件数据和通知系统
- boost::文件系统::recursive_directory_iterator多线程安全
- 如果整个应用程序是虚拟映射的,为什么 new 会进行系统调用?
- SFML 碰撞永远不会在我的系统中注册