zoukankan      html  css  js  c++  java
  • [原] Android上使用native IO

    首先, 官方google play对APK大小有限制: 50M.( https://support.google.com/googleplay/android-developer/answer/113469?hl=en )

    所以想通过google play发布大数据的应用的话, 得通过扩展包, 一个叫做OBB(Opaque Binary Blob)的东西, 最大可以存储4G的数据 (国内的奇葩山寨文化就不要管提了).

    OBB是app使用的数据文件, google play并不关心其内容, 下载到设备以后, 系统也不关心. 如何处理这个文件, 是由app决定的.比如app可以上传一个mp4文件作为obb, 下载以后读取该OBB文件,然后用mp4解码器播放.

    SDK预置的OBB格式, 是一个(压缩的,可加密的)FAT磁盘镜像, 在运行时将OBB挂载到/mnt/XXXX/ 的位置 (XXXX是系统自动生成的字符串路径).

    挂载完成以后, 记录下来挂载的位置, 就可以使用 native API 来读取文件了, 这样就可以完全脱离Java的AssetManager或者ZLib.

    如何生成OBB文件呢? ADT工具下的jobb就可以.

    adt-x86sdk	ools>jobb -d E:indata -o E:inmain.1.com.games.xxx.obb -pv 1 -pn com.games.xxx -k pswd

    可以看出可以对OBB加密, 密码为"pswd"

    不过这里Jobb有几个bug: 指定的文件夹太小, jobb直接崩溃. 当然它是用于大数据包的, 但是小文件测试也不行?

    如果指定的文件夹是10M, 那么可以生成OBB, 但是在android上加载不了, 设备重启也加载不了, 错误代码为无法加载.
    将OBB填到20M, 最后可以了.

    然后就是code了, AStorageManager就是来管理obb的.

    挂载OBB是异步的, 而且需要提供callback function和callback data(可选).callback data是用户定义的,可以是任何数据, 比如我这里是一个app结构指针:

    static void Android_ObbCallbackFunc(const char* filename, const int32_t state, void* data)
    {
        Android_App* app = (Android_App*)data;
    
        if( state == AOBB_STATE_MOUNTED )
        {
            int isMounted = ::AStorageManager_isObbMounted(app->storage, filename);
            assert( isMounted != 0 );
    
            const char* mntPath = ::AStorageManager_getMountedObbPath(app->storage, filename);
            
            //save persistent path data - current NDK returns tmp string that may even corrupted right after AStorageManager_getMountedObbPath() return
            //https://code.google.com/p/android/issues/detail?id=41983
            static char mountPath[PATH_MAX];
            app->storageRoot = strcpy(mountPath, mntPath);
    
            LOGI("OBB mounted: %s", filename);
        }
        else if( state == AOBB_STATE_UNMOUNTED )
            LOGI("OBB unmounted: %s", filename);
        else if( state != AOBB_STATE_ERROR_NOT_MOUNTED )
            LOGI("Android_ObbCallbackFunc: %d", state);
    }

    从上面的回调函数可以看到, 如果挂载成功, 就将挂载后的路径保存到app->storageRoot里, 后面的文件读取就可以使用这个路径了.

    不过AStorageManager_getMountedObbPath有bug, 好像是r8的bug了, 现在已经r9了, 但我这儿有时候偶尔还是会返回乱码或者空字符串.

    下面是OBB初始化的代码, 指定密码和回调函数, 以及回调数据:

    static void Android_InitStorage(Android_App* app)
    {
        ANativeActivity* activity = app->activity;
        assert(activity != NULL && activity->obbPath != NULL);
        assert(app->storage == NULL);
        app->storage = AStorageManager_new();
    
        const char* obbPath = activity->obbPath;
    
        ::AStorageManager_unmountObb(app->storage, obbPath, 1, Android_ObbCallbackFunc, NULL);
        
        //it's a async call: handle final mount path in callbacks
        ::AStorageManager_mountObb(app->storage, obbPath, "pswd", Android_ObbCallbackFunc, app);
    }

    记得好像看过断点时的栈,  回调是在线程里调用的, 所以需要注意线程安全.

    另外, 如果挂载速度不可控, 那么主线程可能需要挂起等待, 否则如果主线程跑的足够快已经开始读取, 而mount还没有完成的话, 可能会导致IO失败. 目前没有等待,也暂时没有遇到问题, 后面会继续完善.

    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------

    更新:

    理论上OBB只是APK expansion, 它可以是任何格式, app上传和下载系统并不关心. ndk提供的mount obb(Fat32镜像)在调试的时候问题比较多, 经常mount失败(AOBB_STATE_ERROR_INTERNAL和AOBB_STATE_ERROR_COULD_NOT_MOUNT)

    据说(google group上有人说)是版本不匹配的原因, 但是尝试更新AndroidManifest.xml的包version和jobb -pv的版本, 比如both +1并使两者匹配, 还是经常mount不上, 对于频繁更新包文件用于测试的情况极为不利.

    所以可以使用的另外一种方法是使用自定义的包格式(比如最简单的-常用的zip格式, 貌似Android SDK在java层提供了这种格式)等, 这一点跟一般PC游戏的自定义文件包格式类似.比如暴雪的MPQ格式等等.

    这样就可以跳过mount,直接使用native IO来读写包文件, 因为这种方法是游戏开发中常用的方式, 所以移植起来问题不大. 只移植package系统的runtime就够用了, 工具还是在host platform上运行打包.
    目前zip压缩格式已经经过测试可用.

  • 相关阅读:
    Office EXCEL 如何设置最大行高
    网站SEO优化的方法
    ajax序列化表单,再也不用通过data去一个个的传值了
    java实现网站paypal支付功能并且异步修改订单的状态
    jquery报.live() is not a function的解决方法
    如何判断服务器是否挂掉
    mysql实现分页的几种方式
    sqlserver实现分页的几种方式
    十年前,女:“对不起,我不会喜欢你的,你不要再坚持了,就好比让 Linux 和 Windows 同时运行在一台PC机上,可能吗?
    实际项目开发中为什么引用的外部样式没有什么效果
  • 原文地址:https://www.cnblogs.com/crazii/p/3512657.html
Copyright © 2011-2022 走看看