我只能找到 2010 年或更早的解决方案。所以我想看看在这方面是否有更新的立场。
我想避免使用 Java 并纯粹使用 C++ 来访问存储在 APK 中的文件(一些小于或大于 1MB)。使用AssetManager
意味着我无法像其他所有操作系统(包括 iOS)上的所有其他文件一样访问文件。
如果没有,C++ 中是否有一种方法可以将 fopen/fread 映射到 AssetManager API?
我只能找到 2010 年或更早的解决方案。所以我想看看在这方面是否有更新的立场。
我想避免使用 Java 并纯粹使用 C++ 来访问存储在 APK 中的文件(一些小于或大于 1MB)。使用AssetManager
意味着我无法像其他所有操作系统(包括 iOS)上的所有其他文件一样访问文件。
如果没有,C++ 中是否有一种方法可以将 fopen/fread 映射到 AssetManager API?
实际上,我找到了这个问题的非常优雅的答案,并在这里写了博客。
总结是:
我的博客有完整的文章和你需要用纯 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::string 并且您在 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/fread,但它完成了工作。将其包装到您自己的文件读取函数中以抽象 zip 层应该很容易。