公司最近的游戏上了AppleStore,打开游戏的详细页面。策划突然发现游戏好大啊。怎么显示的是347M,之前上的另外一款游戏,我们没有注意这块,只是光顾着玩了。而实际我们做出来的IPA只有140多M,咨询几个超级资深的IOS开发人员,AppleStore显示的是IPA展开后的大小。但是玩家不这么认为啊。以为下载的游戏这么大。为了减小大小,看来只要压缩原始文件大小了,经过分析,特做出以下的方法:
- 图片文件,声音文件,不压缩,因为压缩比几乎没有。
- 压缩相关的文本文件,Plist,Json文件。尤其是动画文件,我们用的是ExportJson格式。大的惊人
在这里,做了一下简单的文件格式定义,文件由三部分构成,如下
- 在每个压缩的文件头部加eraygames做压缩标记(9字节长),(用来判断文件是否压缩)
- 然后是四个字节描述压缩前的文件原始长度 (用来解压)
- 然后是文件压缩后的内容
资源的压缩,可以用Python脚本语言,在项目打包之前做运行一下命令即可,下面主要修改Cocos2d-x的引擎部分CCFileUtils,因为所有的文件加载全部在这个类里。而最终的入口在FileUtils::getContents方法里。当然其他平台,在对应的CCFileUtils-Android,CCFileUtils-win32,里。修改如下,在CCFileUtils.h头文件添加方法如下:
protected: enum COMPRESS_CODE { noCompress = 0, unCompressOK, unCompressError, }; COMPRESS_CODE checkIsCompressFile(ResizableBuffer* buffer,int size); private: int m_ITagLen; int m_ISizeLen;CCFileUtils.cpp如下:
FileUtils::COMPRESS_CODE FileUtils::checkIsCompressFile(ResizableBuffer* buffer, int size) { if (size <= m_itaglen="" +="" m_isizelen)="" {="" return="" nocompress;="" }="" unsigned="" char="" *="" sdata="new" char[m_itaglen="" 1];="" memcpy(sdata,="" buffer-="">buffer(), m_ITagLen); sData[m_ITagLen] = '\0'; std::string tag((char*)sData); if (tag.find("eraygames") != std::string::npos) { CC_SAFE_DELETE_ARRAY(sData); sData = new unsigned char[m_ISizeLen]; memcpy(sData, (unsigned char*)buffer->buffer() + m_ITagLen, m_ISizeLen); std::reverse(&sData[0], &sData[m_ISizeLen]); uLong fileLen = 0; memcpy(&fileLen, sData, m_ISizeLen); CC_SAFE_DELETE_ARRAY(sData); int compressSize = size - m_ITagLen - m_ISizeLen; sData = new unsigned char[compressSize]; memcpy(sData, (unsigned char*)buffer->buffer() + m_ITagLen + m_ISizeLen, compressSize); unsigned char* fileData = new unsigned char[fileLen]; bool isCompress = true; do { if (uncompress(fileData, &fileLen, sData, compressSize) != Z_OK) { isCompress = false; break; } buffer->setBuffer(fileData, fileLen); } while (0); CC_SAFE_DELETE_ARRAY(sData); CC_SAFE_DELETE_ARRAY(fileData); if (!isCompress) { CCLOG("UnCompress Error"); return unCompressError; } return unCompressOK; } return noCompress; } =>
然后修改对应的getContents方法。在方法最后一句的前面添加,我修改CCFileUtils-win32.cpp
FileUtils::Status FileUtilsWin32::getContents(const std::string& filename, ResizableBuffer* buffer) { // 此处省略其他代码 if (!successed) { CCLOG("Get data from file(%s) failed, error code is %s", filename.data(), std::to_string(::GetLastError()).data()); buffer->resize(sizeRead); return FileUtils::Status::ReadFailed; } FileUtils::COMPRESS_CODE code = checkIsCompressFile(buffer, size); if (code == FileUtils::COMPRESS_CODE::unCompressError) { return FileUtils::Status::ReadFailed; } return FileUtils::Status::OK; }
最近项目升级引擎到3.13.1,以上所有的研究代码基于此版本