6

2010年以前の日付のソリューションしか見つけることができませんでした。ですから、これについてもっと最新のスタンスがあるかどうかを知りたかったのです。

Java の使用を避け、純粋に C++ を使用して、APK に保存されているファイル (1 MB 未満または 1 MB を超えるもの) にアクセスしたいと考えています。使用AssetManagerすると、他のすべてのオペレーティング システム (iOS を含む) の他のすべてのファイルのようにファイルにアクセスできなくなります。

そうでない場合、どうにかして fopen/fread を AssetManager API にマップできる C++ のメソッドはありますか?

4

2 に答える 2

12

私は実際に問題に対する非常にエレガントな答えを見つけ、それについてブログに書きました ここ.

要約は次のとおりです。

  • AAssetManager API には NDK バインディングがあります。これにより、APK からアセットをロードできます。
  • あらゆるものに対して読み取り/書き込み/シークする方法を知っている一連の関数を組み合わせて、それらをファイル ポインター (FILE*) として偽装することができます。
  • アセット名を受け取り、AssetManager を使用してそれを開き、結果を FILE* として偽装する関数を作成すると、fopen に非常に似たものになります。
  • fopen という名前のマクロを定義すると、その関数のすべての使用を代わりに私たちのものに置き換えることができます。

私のブログには完全な記事と、純粋な C で実装する必要があるすべてのコードがあります。これを使用して、Android 用の lua と libogg をビルドしています。

于 2015-02-14T18:46:51.823 に答える
6

簡潔な答え

いいえ。知る限り、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 レイヤーを抽象化するのは非常に簡単です。

于 2013-08-07T15:56:22.160 に答える