【问题标题】:Access Android APK Asset data directly in c++ without Asset Manager and copying直接在 C++ 中访问 Android APK 资产数据,无需资产管理器和复制
【发布时间】:2012-04-27 08:11:02
【问题描述】:

我在我的引擎中使用纯 C++ 在 android 中创建游戏引擎。没有单个 java 文件。基本上它是一个只能存储到外部存储器的游戏。当我通过 adb 手动将资产数据移动到我的外部 sd 卡时,游戏已经运行良好且稳定。

adb push ..\..\Bin\Data /sdcard/Android/data/com.fantasyhaze.%SMALL_PACKAGE_NAME%/files/Data/

这不是一个好的解决方案,因为它无法交付。因此我在 Assets 文件夹中有我的资产数据 它在构建过程中被移动到 apk 文件中,结构如下:

资产/数据/MoreFolders/Withsubfolders 资产/数据/EngineData.zip 资产/数据/ScriptData.zip

但我不知道这些文件在文件系统上的什么位置以便在 c++ 代码中访问它们。

所以我试图获取文件目录的路径。并且由于本机活动状态中的错误 我必须用普通代码检索信息。

// bug in 2.3 internalDataPath / externalDataPath = null using jni code instead
//FHZ_PRINTF("INTERNAL inter PATH = %s\n", state->activity->internalDataPath);  
//FHZ_PRINTF("EXTERNAL inter PATH = %s\n", state->activity->externalDataPath);

c++ 代码相当于 android.os.Environment.getFilesDir() 和 android.os.Environment.getExternalStorageState() 等

            // getPath() - java
        JNIEnv *jni_env = Core::HAZEOS::GetJNIEnv();
        jclass cls_Env = jni_env->FindClass("android/app/NativeActivity");
        jmethodID mid_getExtStorage = jni_env->GetMethodID(cls_Env, "getFilesDir","()Ljava/io/File;");
        jobject obj_File = jni_env->CallObjectMethod( gstate->activity->clazz, mid_getExtStorage);
        jclass cls_File = jni_env->FindClass("java/io/File");
        jmethodID mid_getPath = jni_env->GetMethodID(cls_File, "getPath","()Ljava/lang/String;");
        jstring obj_Path = (jstring) jni_env->CallObjectMethod(obj_File, mid_getPath);
        const char* path = jni_env->GetStringUTFChars(obj_Path, NULL);
        FHZ_PRINTF("INTERNAL PATH = %s\n", path);
        jni_env->ReleaseStringUTFChars(obj_Path, path);

        // getCacheDir() - java
        mid_getExtStorage = jni_env->GetMethodID( cls_Env,"getCacheDir", "()Ljava/io/File;");
        obj_File = jni_env->CallObjectMethod(gstate->activity->clazz, mid_getExtStorage, NULL);
        cls_File = jni_env->FindClass("java/io/File");
        mid_getPath = jni_env->GetMethodID(cls_File, "getAbsolutePath", "()Ljava/lang/String;");
        obj_Path = (jstring) jni_env->CallObjectMethod(obj_File, mid_getPath);
        path = jni_env->GetStringUTFChars(obj_Path, NULL);
        FHZ_PRINTF("CACHE DIR = %s\n", path); 
        jni_env->ReleaseStringUTFChars(obj_Path, path);

        // getExternalFilesDir() - java
        mid_getExtStorage = jni_env->GetMethodID( cls_Env,"getExternalFilesDir", "(Ljava/lang/String;)Ljava/io/File;");
        obj_File = jni_env->CallObjectMethod(gstate->activity->clazz, mid_getExtStorage, NULL);
        cls_File = jni_env->FindClass("java/io/File");
        mid_getPath = jni_env->GetMethodID(cls_File, "getPath", "()Ljava/lang/String;");
        obj_Path = (jstring) jni_env->CallObjectMethod(obj_File, mid_getPath);
        path = jni_env->GetStringUTFChars(obj_Path, NULL);
        FHZ_PRINTF("EXTERNAL PATH = %s\n", path);
        jni_env->ReleaseStringUTFChars(obj_Path, path);

        //getPackageCodePath() - java
        mid_getPath = jni_env->GetMethodID(cls_Env, "getPackageCodePath", "()Ljava/lang/String;"); 
        obj_File = jni_env->CallObjectMethod(gstate->activity->clazz, mid_getPath); 
        obj_Path = (jstring) jni_env->CallObjectMethod(obj_File, mid_getPath);
        path = jni_env->GetStringUTFChars(obj_Path, NULL);
        FHZ_PRINTF("Looked up package code path = %s\n", path);

效果很好,结果

内部路径 = /data/data/com.fantasyhaze.rememory/files

CACHE DIR = /data/data/com.fantasyhaze.rememory/cache

外部路径 = /mnt/sdcard/Android/data/com.fantasyhaze.rememory/files

查找包代码路径=/mnt/asec/com.fantasyhaze.rememory-2/pkg.apk

但是资产文件夹中没有文件...

我需要访问一个文件夹作为正常工作目录来读取文件。这在

中是可能的

/mnt/sdcard/Android/data/com.fantasyhaze.rememory/files/Data

但是通过资产管理器将所有数据从资产文件夹(无论它在哪里)移动到这个文件夹,会导致内存消耗加倍。

assets >1GB 意味着资产 >2GB,这是没有意义的。不仅如此,assert 文件夹似乎不能反复工作,而且只适用于小数据文件 这在使用更大的 pak 文件时是不可能的。也许文件可以在使用时直接从 apk 访问 解压缩系统,然后解压缩我的资源文件,但无论如何我都必须选择 apk 路径。

所以我的问题:

  1. 文件系统上的 apk 中的 Assets 文件夹在哪里?
  2. 检索 apk 位置或可执行文件位置的代码 (c++) 是什么
  3. 我可以通过普通文件打开方法直接访问它还是仅在我解压缩它的情况下访问它。如果我可以在不打开包装的情况下使用它,如何使用?
  4. 如果安装了 sd 卡,检索信息的代码 (c++) 是什么?

我希望有人可以帮助我:)

编辑:添加缓存目录和包目录代码(以及它的输出路径),为其他需要它的人提供源代码。

【问题讨论】:

  • 从 NDK 端获取资产是棘手且不可靠的,因为某些版本的 Android 原生实现存在错误。让我找到那个 nfo 并回复你。
  • 如果您不打算使用 NativeActivity,您可以使用此方法(仅供参考)查找 APK 并加载资源。 androgeek.info/?p=275
  • 嗨,我想在这个问题中使用这个代码。我需要获取 .apk 文件和内部目录路径的“getPackageCodePath”路径。但它不断向我抛出无法调用的错误。任何人都可以帮助我??提前致谢。在 MainActivity 我有: public native int test();并加载库。在 C 代码中,我正在调用 JNI 方法,并且为 .apk 提供了相同的“包代码路径”:
  • 我得到的错误是:JNI DETECTED ERROR IN APPLICATION: can't call java.lang.String android.content.ContextWrapper.getPackageCodePath() on instance of java.lang.Class 在调用 CallObjectMethod

标签: android c++ native apk native-activity


【解决方案1】:

我发布答案而不是将其标记为重复,因为从技术上讲,您要求的详细信息比我将在此处链接的问题/答案中提供的更多。因此,要回答 4 点中的第一个,请参阅 Obtaining the name of an Android APK using C++ and the NativeActivity class

至于检查SD卡是否挂载,应该比较简单。只需尝试打开 SD 卡上的目录或文件(您知道应该在那里),如果失败,您就知道 SD 卡不可用。见What's the best way to check if a file exists in C? (cross platform)

【讨论】:

  • 感谢信息,搜索了很久,但在链接 2 中找不到这篇文章!有了那里的信息,我终于可以检索到 apk 的位置 :) 在第一篇文章中添加了代码,以不同于链接中的形式提供它。文件检查没问题,但我认为可能有一些方法可以检查 sd 卡是否安装在 c 代码中,类似于:android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);,如 link 中所见
【解决方案2】:

您可能想查看“扩展文件”,请参阅APK Expansion Files

据我了解,这为您提供了一个自动将资源文件(您的扩展文件)放在“共享存储位置”的系统。

所以我认为这将解决您的重复数据问题。

还有一个简短的介绍post on the android-developers blog

【讨论】:

  • 不知道有50MB的限制!!!关于apk文件大小?这太可怕了,那些扩展文件可以解决问题,但是在 C/C++ 中使用 AStorageManager 来访问 odb 文件是否有任何来源?在原生 c 中重新实现下载器的东西似乎有很多工作:/
猜你喜欢
  • 1970-01-01
  • 2011-12-26
  • 1970-01-01
  • 2017-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-11
  • 1970-01-01
相关资源
最近更新 更多