fopen/fread APK Assets from NativeActivity on Android

前端 未结 2 1098
悲哀的现实
悲哀的现实 2021-02-03 14:43

I have only been able to find solutions dated 2010 and earlier. So I wanted to see if there was a more up-to-date stance on this.

I\'d like to avoid using Java and pure

2条回答
  •  情歌与酒
    2021-02-03 15:21

    Short answer

    No. AFAIK mapping fread/fopen in C++ to AAssetManager is not possible. And if were it would probably limit you to files in the assets folder. There is however a workaround, but it's not straightforward.

    Long Answer

    It IS possible to access any file anywhere in the APK using zlib and libzip in C++. Requirements : some java, zlib and/or libzip (for ease of use, so that's what I settled for). You can get libzip here: http://www.nih.at/libzip/

    libzip may need some tinkering to get it to work on android, but nothing serious.

    Step 1 : retrieve APK location in Java and pass to 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;
    

    Passing PathToAPK to 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;
    }
    

    Assuming that you now have a std::string with your APK location and you have zlib on libzip working you can do something like this:

    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;
        }
    }
    

    And to read a file from the 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;
    

    Not exactly fopen/fread but it gets the job done. It should be pretty easy to wrap this to your own file reading function to abstract the zip layer.

提交回复
热议问题