[原] 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-x86\sdk\tools>jobb -d E:\bin\data -o E:\bin\main.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 != ); 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, , 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压缩格式已经经过测试可用.
[原] Android上使用native IO的更多相关文章
- [原] GLES在iOS和Android上的不同
本来GLES提供了与native platform的接口 EGL, 然而iOS没有使用EGL接口, 而是自己搞了一套,叫做EAGL的类似东西, 虽然说大同小异,但是在做跨平台的时候还是很恶心. elg ...
- react native-调用react-native-fs插件时,如果数据的接口是需要验证信息的,在android上运行报错
调用react-native-fs插件时,如果数据的接口是需要验证信息的,在android上运行报错,而在iOS上运行没问题.原因是因为接口是有验证信息的,而调用这个插件时没有传入,在iOS上会自动加 ...
- 系列篇|编译可在Android上运行的依赖库(一):glib库
前言 这是系列文章,它们由<编译可在Android上运行的glib库>及其他4篇文章组成,这4篇文章在“编译依赖库”一节中列出.由于glib库依赖于其他第三方库,所以需要先将依赖的第三方库 ...
- 最牛逼android上的图表库MpChart(三) 条形图
最牛逼android上的图表库MpChart三 条形图 BarChart条形图介绍 BarChart条形图实例 BarChart效果 最牛逼android上的图表库MpChart(三) 条形图 最近工 ...
- 最牛逼android上的图表库MpChart(二) 折线图
最牛逼android上的图表库MpChart二 折线图 MpChart折线图介绍 MpChart折线图实例 MpChart效果 最牛逼android上的图表库MpChart(二) 折线图 最近工作中, ...
- 最牛逼android上的图表库MpChart(一) 介绍篇
最牛逼android上的图表库MpChart一 介绍篇 MpChart优点 MpChart是什么 MpChart支持哪些图表 MpChart效果如何 最牛逼android上的图表库MpChart(一) ...
- 在Android上使用fontAwesome
再也不用做那些讨厌的小图标了! 从网上找了些资料,总结下在android上使用fontAwesome的方法. 1.到官网上下载资源包,找到其中的字体文件fontawesome-webfont.ttf, ...
- android上传文件到服务器
package com.spring.sky.image.upload.network; import java.io.DataOutputStream; import java.io.File; i ...
- 二十一、Android上常见度量单位【xdpi、hdpi、mdpi、ldpi】解读
术语和概念 屏幕尺寸 屏幕的物理尺寸,以屏幕的对角线长度作为依据(比如 2.8寸, 3.5寸). 简而言之, Android把所有的屏幕尺寸简化为三大类:大,正常,和小. 程序可以针对这三种尺寸的屏幕 ...
随机推荐
- File 和 导出jar包
1.File import java.io.File; import java.io.IOException; public class FileTest { public static void m ...
- awk计算最大值,最小值,平均值的脚本
传入至少三个数字参数到脚本awk_file,并计算出最大,最小,平均值.需要判断传入的数字是否足够,否则输出警告信息.平均值保留两位小数. 如执行bash awk_file 3 4 6 5,脚本输出结 ...
- Delphi I/O error 103 错误
http://stackoverflow.com/questions/634587/delphi-why-do-i-sometimes-get-an-i-o-error-103-with-this-c ...
- react全家桶-路由
/src目录下新增一个pages目录,用于存放渲染页面的组件 在/src/pages中新增一个Add.js文件 /src 下的index.js 路由:import React from 'react' ...
- BCM5396的SPI理解
参考文档链接:https://pan.baidu.com/s/1kuXJmULwtjOW1TeOuTRPQQ *时钟极性和相位 BCM538X / BCM5396用于根据以下标准发送/接收SPI数据: ...
- fastjson 在 springboot中的运用
题记: 项目中开始用是Gson,但是压力测试的时候会出现性能下降明显,不得已换成了fastjson 1.首先引用包 <dependency> <groupId>com.alib ...
- fk的使用细节
在seiman的博客fk2.3的用法笔记一文中,介绍了当震中距很大时,fk在使用时需要加上-f,这一展平变换的选项. 另外,nt*dt为最终数据的总长度,当震中距为远震范围时,such as:40°, ...
- Aimbat安装
1:Pysmo下的sac和aimbat需要放在和前面的toolkits 相同的地方,Python就能找到: 在安装obspy时,需要装yum-plugin-copr; 方法在网址: https://c ...
- AntPathMatcher做路径匹配
转发自: http://www.cnblogs.com/leftthen/p/5212221.html 需要看详细的请看上面的链接 这里以我这里的一个Filter 中需要对路径做例外处理,filter ...
- powerdesigner远程连接数据库
1. dabatase-->configure connections 2.新建连接 3.配置TNS连接测试 4.出现异常及处理 Could not Initialize JavaVM! 出现这 ...