cocos2d-x android 直接加载下载到sd的zip里的资源文件(二)
来源:互联网 发布:数据分析师的工资待遇 编辑:程序博客网 时间:2024/05/01 23:23
上一节 解决了读文件的问题,游戏也跑起来了,可是音效和背景音乐,死活播放不出来。回想一下,的确没有考虑到游戏的音效问题。让我们再折腾一下,播放zip里的音效问题。cocos-x 安卓的背景音乐处理交给了Cocos2dxMusic.java,音效处理交给了Cocos2dxSound.java。别的我们不看,就关注声音资源加载的地方。
先分析一下Cocos2dxMusic.java 的声音资源加载方法
private MediaPlayer createMediaplayer(final String pPath) ;
这个方法就是啦。大概就是判断fullpath路径是否 '/'开头,如果是就加载sd卡声音资源,否则加载apk里的资源。
/** * create mediaplayer for music * * @param pPath * the pPath relative to assets * @return */private MediaPlayer createMediaplayer(final String pPath) {MediaPlayer mediaPlayer = new MediaPlayer();try {//加载sd卡里的声音资源if (pPath.startsWith("/")) {final FileInputStream fis = new FileInputStream(pPath);mediaPlayer.setDataSource(fis.getFD());fis.close();} else {//加载apk里的声音资源final AssetFileDescriptor assetFileDescritor = this.mContext.getAssets().openFd(pPath);mediaPlayer.setDataSource(assetFileDescritor.getFileDescriptor(), assetFileDescritor.getStartOffset(), assetFileDescritor.getLength());}mediaPlayer.prepare();mediaPlayer.setVolume(this.mLeftVolume, this.mRightVolume);} catch (final Exception e) {mediaPlayer = null;Log.e(Cocos2dxMusic.TAG, "error: " + e.getMessage(), e);}return mediaPlayer;}
在分析一下Cocos2dxSound.java的声音资源加载方法
->public int playEffect(final String pPath, final boolean pLoop)
->public int preloadEffect(final String pPath)
->public int createSoundIDFromAsset(final String pPath)
也是是判断fullpath路径是否 '/'开头,如果是就加载sd卡声音资源,否则加载apk里的资源。
public int createSoundIDFromAsset(final String pPath) {int soundID = Cocos2dxSound.INVALID_SOUND_ID;try {if (pPath.startsWith("/")) {//加载sd卡声音资源soundID = this.mSoundPool.load(pPath, 0);} else {//加载apk里的声音资源soundID = this.mSoundPool.load(this.mContext.getAssets().openFd(pPath), 0);}} catch (final Exception e) {soundID = Cocos2dxSound.INVALID_SOUND_ID;Log.e(Cocos2dxSound.TAG, "error: " + e.getMessage(), e);}// mSoundPool.load returns 0 if something goes wrong, for example a file does not existif (soundID == 0) {soundID = Cocos2dxSound.INVALID_SOUND_ID;}return soundID;}
回想起来,我们已经有fullpath ,我们要像读取向下面的资源
fullpath = /storage/emulated/0/DonutABC/unitRes/game_22.zip#/res/pub_element/L1U1/audio/pub_unit1_blue_audio.wav
方法1:直接读取zip里的声音流 让播放器们播放
InputStream 这样的东西java 程序猿们太熟悉不过了,何况是ZipInputStream。我们先将对应的文件用ZipInputStream 读出,然后直接让MediaPlayer 或SoundPool 加载播放流不就可以了吗?可是童话都是骗人的。突然想起邓超演的《美人鱼》,我实在是想不通。好好的白富美在身边不要,偏偏去要一条上半身是人,下半身是鱼的人鱼。没有接口下半辈子能幸福吗!!!实在是想不通。在这个问题上,也是遇到了这样的人鱼。MediaPlayer 和 SoundPool 都没有直接播放流的方法 ,MediaPlayer的setDataSource方法。SoundPool的load方法 都没有播放流的接口。下半辈子不幸福,感觉不会再爱了。好吧换第二个方法
方法2:将zip对应的声音文件临时解压到sd卡里, 然后返回fullpath给 Cocos2dxMusic.java或Cocos2dxSound.java 的加载方法。
新欢没有接口,我们找旧爱。旧爱的接口就是要个声音文件的fullpath吗,太容易满足了。让我们动手改改
Cocos2dxMusic.java 的 createMediaplayer
/** * create mediaplayer for music * * @param pPath * the pPath relative to assets * @return */private MediaPlayer createMediaplayer(final String pPath) {MediaPlayer mediaPlayer = new MediaPlayer();try {if (pPath.startsWith("/")) {//改了这里String ppPath = PathUtils.getZipFilePath(pPath);final FileInputStream fis = new FileInputStream(ppPath);mediaPlayer.setDataSource(fis.getFD());fis.close();} else {final AssetFileDescriptor assetFileDescritor = this.mContext.getAssets().openFd(pPath);mediaPlayer.setDataSource(assetFileDescritor.getFileDescriptor(), assetFileDescritor.getStartOffset(), assetFileDescritor.getLength());}mediaPlayer.prepare();mediaPlayer.setVolume(this.mLeftVolume, this.mRightVolume);} catch (final Exception e) {mediaPlayer = null;Log.e(Cocos2dxMusic.TAG, "error: " + e.getMessage(), e);}return mediaPlayer;}
Cocos2dxSound.java 的createSoundIDFromAsset
public int createSoundIDFromAsset(final String pPath) {int soundID = Cocos2dxSound.INVALID_SOUND_ID;try {if (pPath.startsWith("/")) {//改了下面的String ppPath = PathUtils.getZipFilePath(pPath);soundID = this.mSoundPool.load(ppPath, 0);} else {soundID = this.mSoundPool.load(this.mContext.getAssets().openFd(pPath), 0);}} catch (final Exception e) {soundID = Cocos2dxSound.INVALID_SOUND_ID;Log.e(Cocos2dxSound.TAG, "error: " + e.getMessage(), e);}// mSoundPool.load returns 0 if something goes wrong, for example a file does not existif (soundID == 0) {soundID = Cocos2dxSound.INVALID_SOUND_ID;}return soundID;}
解压的方法 getZipFilePath
/*** * 获得路径 也许是zip里面的的路径 * @param pPath * @return * @throws ZipException * @throws IOException */public static String getZipFilePath(String pPath) throws ZipException, IOException {String zipfilepath = "";String filename = "";int index = pPath.indexOf("#");String ppPath = pPath;//是否在zip里if(index != -1){zipfilepath = pPath.substring(0,index);filename = pPath.substring(index+2);Log.d("RecordManager","zipfilepath:"+ zipfilepath + "--filename:" + filename);String filesavename = filename.replaceAll("/","_");ppPath = PathUtils.getTempPath() +filesavename+".temp";File filetemp = new File(ppPath);//是否有临时解压文件 避免重复解压if(!filetemp.exists()){filetemp.createNewFile();ZipFile file = new ZipFile(zipfilepath);FileHeader fileHeader = file.getFileHeader(filename);net.lingala.zip4j.io.ZipInputStream zipInputStream = file.getInputStream(fileHeader);FileOutputStream fo = new FileOutputStream(ppPath);byte[] b = new byte[4096];int readLine = -1;while ((readLine = zipInputStream.read(b)) != -1) {fo.write(b,0,readLine);}fo.close();zipInputStream.close();}}return ppPath;}
注:我用了开源的zip操作库 zip4j ,我git上有提交 。
好啦。我们这就跑起来。欧啦!声音出来了。这个方案凑合着用,如有更高明的方法,请回复我。
解压方法 c++版
static std::string getZipFilePath(const std::string& fullPath,const std::string& saveDir);static unsigned char* getFileDataFromZip(const char* pszZipFilePath, const char* pszFileName, unsigned long * pSize);
#include "support/zip_support/ZipUtils.h"#include "platform/CCCommon.h"#include "support/zip_support/unzip.h"#include "platform/CCFileUtils.h"
/** * fullpath 音效的绝对路径 * saveDir 解压到的地方 * return 解压后的资源返回的路径 **/std::string JNItools::getZipFilePath(const std::string& fullPath,const std::string& saveDir){ unsigned char * pBuffer = NULL; unsigned long pSize = 0; std::string savepath = fullPath; std::string pszFileNameTemp = ""; std::string pszZipFilePath = "";
size_t pos = fullPath.find_last_of("#"); if (pos != std::string::npos) { // file_path = /storage/emulated/0/DonutABC/unitRes/game_22.zip pszZipFilePath = fullPath.substr(0, pos); // file = res/pub_element/L1U1/audio/pub_unit1_blue_audio.wav pszFileNameTemp = fullPath.substr(pos+2);// CCLOG("pszZipFilePath:%s,pszFileNameTemp:%s",pszZipFilePath.c_str(),pszFileNameTemp.c_str()); //替换‘/' std::string filename = pszFileNameTemp; std::string old_value = "/"; std::string new_value = "_"; for(string::size_type pos(0); pos!=string::npos; pos+=new_value.length()){ if((pos=filename.find(old_value,pos))!=string::npos) filename.replace(pos,old_value.length(),new_value); else break; }// CCLOG("filename:%s",filename.c_str()); savepath = saveDir + filename + ".temp"; const char* output = savepath.c_str(); CCLOG("filename:%s",output); //文件如果存在就不解压了 int i = access(savepath.c_str(), 0); CCLOG("filename:%d",i); if( i == -1){ pBuffer = JNItools::getFileDataFromZip(pszZipFilePath.c_str(),pszFileNameTemp.c_str(),&pSize); FILE *savefile = fopen(output, "wb"); fwrite(pBuffer, 1, (size_t)pSize, savefile); fflush(savefile); fclose(savefile); delete pBuffer; } } return savepath; }/** * 解压zip 获得资源数据 **/unsigned char* JNItools::getFileDataFromZip(const char* pszZipFilePath, const char* pszFileName, unsigned long * pSize){ unsigned char * pBuffer = NULL; unzFile pFile = NULL; *pSize = 0; do {// CCLOG("1"); CC_BREAK_IF(!pszZipFilePath || !pszFileName);// CCLOG("11"); CC_BREAK_IF(strlen(pszZipFilePath) == 0);// CCLOG("1111"); pFile = unzOpen(pszZipFilePath); CC_BREAK_IF(!pFile);// CCLOG("2"); int nRet = unzLocateFile(pFile, pszFileName, 1); CC_BREAK_IF(UNZ_OK != nRet);// CCLOG("3"); char szFilePathA[260]; unz_file_info FileInfo; nRet = unzGetCurrentFileInfo(pFile, &FileInfo, szFilePathA, sizeof(szFilePathA), NULL, 0, NULL, 0); CC_BREAK_IF(UNZ_OK != nRet);// CCLOG("4"); nRet = unzOpenCurrentFile(pFile); CC_BREAK_IF(UNZ_OK != nRet);// CCLOG("5"); pBuffer = new unsigned char[FileInfo.uncompressed_size]; int CC_UNUSED nSize = unzReadCurrentFile(pFile, pBuffer, FileInfo.uncompressed_size); CCAssert(nSize == 0 || nSize == (int)FileInfo.uncompressed_size, "the file size is wrong");// CCLOG("6"); *pSize = FileInfo.uncompressed_size; unzCloseCurrentFile(pFile); } while (0); if (pFile) { unzClose(pFile); } return pBuffer;}
调方法
public static native String getZipFilePath(String pPath,String saveDir);
/** * jni 调用 */ jstring Java_org_cocos2dx_lib_PathUtils_getZipFilePath(JNIEnv* env, jobject thiz,jstring path,jstring savedir) {// CCLOG("filename:%s","Java_org_cocos2dx_lib_PathUtils_getZipFilePath"); std::string char_path = JniHelper::jstring2string(path); std::string char_savedir = JniHelper::jstring2string(savedir); std::string str_path = JNItools::getZipFilePath(char_path,char_savedir);// CCLOG("----getPath:%s",str_path.c_str()); env->DeleteLocalRef(path); env->DeleteLocalRef(savedir); return (env)->NewStringUTF(str_path.c_str()); }
public int createSoundIDFromAsset(final String pPath) {int soundID = Cocos2dxSound.INVALID_SOUND_ID;try {if (pPath.startsWith("/")) {String ppPath = PathUtils.getZipFilePath(pPath,PathUtils.getTempPath());soundID = this.mSoundPool.load(ppPath, 0);} else {soundID = this.mSoundPool.load(this.mContext.getAssets().openFd(pPath), 0);}} catch (final Exception e) {soundID = Cocos2dxSound.INVALID_SOUND_ID;Log.e(Cocos2dxSound.TAG, "error: " + e.getMessage(), e);}// mSoundPool.load returns 0 if something goes wrong, for example a file does not existif (soundID == 0) {soundID = Cocos2dxSound.INVALID_SOUND_ID;}return soundID;}
Cocos2dxMusic.java 修改
/** * create mediaplayer for music * * @param pPath * the pPath relative to assets * @return */private MediaPlayer createMediaplayer(final String pPath) {MediaPlayer mediaPlayer = new MediaPlayer();try {if (pPath.startsWith("/")) {String ppPath = PathUtils.getZipFilePath(pPath,PathUtils.getTempPath());final FileInputStream fis = new FileInputStream(ppPath);mediaPlayer.setDataSource(fis.getFD());fis.close();} else {final AssetFileDescriptor assetFileDescritor = this.mContext.getAssets().openFd(pPath);mediaPlayer.setDataSource(assetFileDescritor.getFileDescriptor(), assetFileDescritor.getStartOffset(), assetFileDescritor.getLength());}mediaPlayer.prepare();mediaPlayer.setVolume(this.mLeftVolume, this.mRightVolume);} catch (final Exception e) {mediaPlayer = null;Log.e(Cocos2dxMusic.TAG, "error: " + e.getMessage(), e);}return mediaPlayer;}
整体来看效率没什么提高,就是不用 zip4j 解压了。
还是老样子。下载完整的改动
{{{{{{{{{github传送门}}}}}}}}
本文出处
http://blog.csdn.net/frabbit_on_fire/article/details/51538300
- cocos2d-x android 直接加载下载到sd的zip里的资源文件(二)
- cocos2d-x android 直接加载下载到sd的zip里的资源文件(一)
- cocos2d-x 读取android手机sd卡中的资源(android http下载zip资源、解压)
- 关于android资源文件图片和SD卡图片加载到内存的占用
- Cocos2d-x 避免手工输入项目需要编译的cpp文件到Android.mk里
- Cocos2d-x 避免手工输入项目需要编译的cpp文件到Android.mk里
- cocos2d-x 把资源文件保存到本地手机上,调用JNI接口,ANdroid的
- Android下载文件到sd card的一些常见问题
- android里的zip文件压缩
- cocos2d-x中CCTextureCache图片资源的异步加载
- 关于cocos2d-x进度条的实现和异步加载资源
- 【Android】Android直接解析zip里文件(.json/.png)
- cocos2d-x plugin集成到Android里时遇到的问题
- android中拷贝assets下的资源文件到SD卡中(可以超过1M)
- android中拷贝assets下的资源文件到SD卡中(可以超过1M)
- android中拷贝assets下的资源文件到SD卡中(可以超过1M)
- 把raw里的文件复制到SD卡中
- 包含到cocos2d-x里的tcpsocket源码
- 自定义输入框可一键清除
- SlideAndDragListView学习笔记
- leetcode 118 Pascal's Triangle C++
- iOS实现长时间后台运行
- Jquery学习笔记一
- cocos2d-x android 直接加载下载到sd的zip里的资源文件(二)
- for语句的运用
- Graphite监控上手指南
- Oracle安装时先决条件物理内存检查失败的解决方案
- sizeof()与strlen()
- 【Tsung学习】2.环境准备、软件安装
- 各种主流浏览器CSS、BUG兼容(附带解决方法~、)
- php数据转换为js
- 反射中属性的用法