从神之刃开始,对这个游戏的引擎就充满了好奇,要什么样的手法把一个游戏包减少到40M。虽然有些童鞋总喜欢说无非就是压缩资源减少图片大小毫无技术含量这等话,但我们公司是做不到的。十万个为什么手游版的出现,让我想尽自己能力去分析看看。
文章出自 http://blog.csdn.net/huutu
从网上下载十万个为什么的 APK 安装包后,直接改成ZIP进行解压。因为网上文章说神之刃 是 妙趣横生 的自研引擎,所以直接来看Libs文件夹吧。
Libs文件夹里面有4个不同CPU类型的子文件夹,只有 armeabi-v7a 中存在引擎相关的SO动态链接库文件。
看到这五个SO文件,给我这个半吊子游戏开发者造成的迷惑来说不亚于太阳从西边出来。
为什么这么说?
libcheck.so libentryex.so 这两个应该是腾讯的三方SDK所有。
libgnustl_shared.so 这个文件应该是使用了C++所以会有。
那么游戏所有的就只有 libmqcj.so libcompress.so 这两个动态链接库了。
直觉告诉我,这两个动态链接库不可能是游戏主要的动态链接库文件。
至于SO文件的大小,Unity的 libunity.so + libmono.so 是14M,就连NDK的Sample都有47KB。难道十万个为什么整个游戏框架只有58+6KB?这明显不可能的。
文章出自 http://blog.csdn.net/huutu
进一步,反编译APK,查看Manifest文件和Java源代码。
上面是十万个为什么的Manifest文件,从中可以看出:
com.mqgame.lib.SLaunchActivity 这个是游戏的启动Activity 。
com.mqgame.lib.SNativeActivity 这个是NativiActivity ,并且指定动态链接库 mqcj ,就是上面6KB的那个文件。
来分析反编译出来的Java源代码。
首先来看 com.mqgame.lib.SLaunchActivity ,这个Activity 在游戏中就是 资源准备的界面。女王大人。
if (localIterator.hasNext()) { localRunningTaskInfo = (ActivityManager.RunningTaskInfo)localIterator.next(); if ((localRunningTaskInfo.topActivity.getPackageName().equals(getPackageName())) || (localRunningTaskInfo.baseActivity.getPackageName().equals(getPackageName()))) if ((localRunningTaskInfo.topActivity.getClassName().equals("com.mqgame.lib.SNativeActivity")) || (localRunningTaskInfo.baseActivity.getClassName().equals("com.mqgame.lib.SNativeActivity"))) if (localRunningTaskInfo.numRunning >= 1) { Log.d("sog_debug", "SOGActivity:Relaunch native"); localIntent2 = getIntent(); if (localIntent2 != null) { localIntent2.setClass(this, SNativeActivity.class); label194: localIntent2.setFlags(131072); startActivity(localIntent2); finish(); } } }
在SNativeActivity中看到有一个 preRun函数
文章出自 http://blog.csdn.net/huutu
public boolean preRun() { int i = 1; label323: int j; do { try { LinkedList localLinkedList = new LinkedList(); localLinkedList.add(new String("gnustl_shared")); localLinkedList.add(new String("openal")); localLinkedList.add(new String("compress")); localLinkedList.add(new String("script")); localLinkedList.add(new String("iconv")); localLinkedList.add(new String("ogg")); localLinkedList.add(new String("vorbis")); localLinkedList.add(new String("vorbisfile")); localLinkedList.add(new String("curl")); localLinkedList.add(new String("autoupdater")); localLinkedList.add(new String("speex")); localLinkedList.add(new String("mqcj")); Iterator localIterator = localLinkedList.iterator(); while (true) { if (!localIterator.hasNext()) break label323; String str1 = (String)localIterator.next(); str2 = new String(SUtility.getLibPath() + File.separator + "lib" + str1 + ".so"); if (new File(str2).exists()) break; System.loadLibrary(str1); } } catch (Exception localException) { while (true) { String str2; localException.printStackTrace(); SUtility.appendLog(localException.toString()); i = 0; return i; System.load(str2); } } catch (Error localError) { localError.printStackTrace(); SUtility.appendLog(localError.toString()); return i; } VoiceManager.init(this); SUtility.bNativeEntered = true; j = Settings.System.getInt(getContentResolver(), "accelerometer_rotation", 0); } while ((Build.VERSION.SDK_INT < 9) || (j != i)); setRequestedOrientation(6); return i; }
从代码上来理解,应该存在两个目录用于存放SO文件。
首先从默认的Libs目录查找,然后从第二个Libs文件夹中寻找是不是有这个SO文件,如果有就使用第二个的SO。于是开始在SDK卡中寻找。却没有搜索到,看样子并没有解压到SDK卡中。那就应该是解压到了APP的默认应用文件夹了。于是去找了一个Root的手机来安装游戏。
。。。。。。。文章出自 http://blog.csdn.net/huutu
在玩游戏的时候正好电脑上开着Eclipse,看到了以下Log:
03-29 16:14:07.582: D/SOG(8950): Ready to show Game 03-29 16:14:07.587: D/dalvikvm(8950): Trying to load lib /data/app-lib/com.linekong.cjad.lk-1/libgnustl_shared.so 0x421565f0 03-29 16:14:07.597: D/dalvikvm(8950): Added shared lib /data/app-lib/com.linekong.cjad.lk-1/libgnustl_shared.so 0x421565f0 03-29 16:14:07.597: D/dalvikvm(8950): No JNI_OnLoad found in /data/app-lib/com.linekong.cjad.lk-1/libgnustl_shared.so 0x421565f0, skipping init 03-29 16:14:07.597: D/SOG_DEBUG(8950): Loading liberary from inner gnustl_shared 03-29 16:14:07.597: D/dalvikvm(8950): Trying to load lib /data/app-lib/com.linekong.cjad.lk-1/libcompress.so 0x421565f0 03-29 16:14:07.602: D/dalvikvm(2087): GC_CONCURRENT freed 24K, 28% free 17104K/23584K, paused 2ms+2ms, total 22ms 03-29 16:14:07.602: D/dalvikvm(2087): WAIT_FOR_CONCURRENT_GC blocked 19ms 03-29 16:14:07.607: D/dalvikvm(8950): Added shared lib /data/app-lib/com.linekong.cjad.lk-1/libcompress.so 0x421565f0 03-29 16:14:07.607: D/dalvikvm(8950): No JNI_OnLoad found in /data/app-lib/com.linekong.cjad.lk-1/libcompress.so 0x421565f0, skipping init 03-29 16:14:07.607: D/SOG_DEBUG(8950): Loading liberary from inner compress 03-29 16:14:07.607: D/dalvikvm(8950): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libcurl.so 0x421565f0 03-29 16:14:07.607: D/dalvikvm(8950): GC_CONCURRENT freed 253K, 6% free 5156K/5480K, paused 6ms+2ms, total 17ms 03-29 16:14:07.612: D/dalvikvm(8950): Added shared lib /data/data/com.linekong.cjad.lk/files/libs/libcurl.so 0x421565f0 03-29 16:14:07.612: D/dalvikvm(8950): No JNI_OnLoad found in /data/data/com.linekong.cjad.lk/files/libs/libcurl.so 0x421565f0, skipping init 03-29 16:14:07.612: D/SOG_DEBUG(8950): Loading liberary from path:/data/data/com.linekong.cjad.lk/files/libs/libcurl.so 03-29 16:14:07.612: D/dalvikvm(8950): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libautoupdater.so 0x421565f0 03-29 16:14:07.642: D/dalvikvm(8950): Added shared lib /data/data/com.linekong.cjad.lk/files/libs/libautoupdater.so 0x421565f0 03-29 16:14:07.642: D/dalvikvm(8950): No JNI_OnLoad found in /data/data/com.linekong.cjad.lk/files/libs/libautoupdater.so 0x421565f0, skipping init 03-29 16:14:07.642: D/SOG_DEBUG(8950): Loading liberary from path:/data/data/com.linekong.cjad.lk/files/libs/libautoupdater.so 03-29 16:14:07.677: D/libEGL(8950): loaded /system/lib/egl/libEGL_mali.so 03-29 16:14:07.677: D/libEGL(8950): loaded /system/lib/egl/libGLESv1_CM_mali.so 03-29 16:14:07.682: D/libEGL(8950): loaded /system/lib/egl/libGLESv2_mali.so 03-29 16:14:07.687: E/(8950): Device driver API match 03-29 16:14:07.687: E/(8950): Device driver API version: 401 03-29 16:14:07.687: E/(8950): User space API version: 401 03-29 16:14:07.687: E/(8950): mali: REVISION=Linux-r4p0-00rel0 BUILD_DATE=Tue Jul 8 00:03:51 CST 2014 03-29 16:14:07.687: W/linker(8950): libion.so has text relocations. This is wasting memory and is a security risk. Please fix. 03-29 16:14:07.687: V/WindowAnimator(1979): No window is displayed, unset the SET_ORIENTATION_CHANGE_COMPLETE flag 03-29 16:14:07.742: D/OpenGLRenderer(8950): Enabling debug mode 0 03-29 16:14:07.757: D/SOG(8950): Total:1090 Sub:1080 SceenX:1280 SceenY:800 dX:76 dy:43 nProcess X:160 nProcess Width:770 LocaltionShow:0 03-29 16:14:07.782: D/dalvikvm(8950): GC_FOR_ALLOC freed 64K, 7% free 5140K/5480K, paused 9ms, total 9ms 03-29 16:14:07.787: I/dalvikvm-heap(8950): Grow heap (frag case) to 6.647MB for 1638544-byte allocation 03-29 16:14:07.797: D/dalvikvm(8950): GC_FOR_ALLOC freed <1K, 5% free 6740K/7084K, paused 13ms, total 13ms 03-29 16:14:07.812: D/dalvikvm(8950): GC_CONCURRENT freed 2K, 5% free 6771K/7084K, paused 1ms+2ms, total 16ms 03-29 16:14:07.817: D/sog_debug(8950): launch service 03-29 16:14:07.817: D/SOG(8661): sog service shutdown 03-29 16:14:07.817: D/SOG(8661): sog service startuping 03-29 16:14:07.817: D/Service Loading(8661): /data/data/com.linekong.cjad.lk/files/libs/libgnustl_shared.so 03-29 16:14:07.817: D/dalvikvm(8661): Trying to load lib /data/app-lib/com.linekong.cjad.lk-1/libgnustl_shared.so 0x421512b0 03-29 16:14:07.817: D/dalvikvm(8661): Shared lib '/data/app-lib/com.linekong.cjad.lk-1/libgnustl_shared.so' already loaded in same CL 0x421512b0 03-29 16:14:07.817: D/Service Loading(8661): /data/data/com.linekong.cjad.lk/files/libs/libcompress.so 03-29 16:14:07.817: D/dalvikvm(8661): Trying to load lib /data/app-lib/com.linekong.cjad.lk-1/libcompress.so 0x421512b0 03-29 16:14:07.817: D/dalvikvm(8661): Shared lib '/data/app-lib/com.linekong.cjad.lk-1/libcompress.so' already loaded in same CL 0x421512b0 03-29 16:14:07.817: D/Service Loading(8661): /data/data/com.linekong.cjad.lk/files/libs/libscript.so 03-29 16:14:07.822: D/dalvikvm(8661): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libscript.so 0x421512b0 03-29 16:14:07.822: D/sog_debug(8950): launch game 03-29 16:14:07.822: D/dalvikvm(8661): Shared lib '/data/data/com.linekong.cjad.lk/files/libs/libscript.so' already loaded in same CL 0x421512b0 03-29 16:14:07.822: D/Service Loading(8661): /data/data/com.linekong.cjad.lk/files/libs/libiconv.so 03-29 16:14:07.822: D/dalvikvm(8661): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libiconv.so 0x421512b0 03-29 16:14:07.822: D/dalvikvm(8661): Shared lib '/data/data/com.linekong.cjad.lk/files/libs/libiconv.so' already loaded in same CL 0x421512b0 03-29 16:14:07.822: D/Service Loading(8661): /data/data/com.linekong.cjad.lk/files/libs/libcurl.so 03-29 16:14:07.822: D/dalvikvm(8661): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libcurl.so 0x421512b0 03-29 16:14:07.822: D/dalvikvm(8661): Shared lib '/data/data/com.linekong.cjad.lk/files/libs/libcurl.so' already loaded in same CL 0x421512b0 03-29 16:14:07.822: D/Service Loading(8661): /data/data/com.linekong.cjad.lk/files/libs/libpush.so 03-29 16:14:07.822: D/dalvikvm(8661): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libpush.so 0x421512b0 03-29 16:14:07.822: D/dalvikvm(8661): Shared lib '/data/data/com.linekong.cjad.lk/files/libs/libpush.so' already loaded in same CL 0x421512b0 03-29 16:14:08.417: D/dalvikvm(8950): Trying to load lib /data/app-lib/com.linekong.cjad.lk-1/libgnustl_shared.so 0x421565f0 03-29 16:14:08.417: D/dalvikvm(8950): Shared lib '/data/app-lib/com.linekong.cjad.lk-1/libgnustl_shared.so' already loaded in same CL 0x421565f0 03-29 16:14:08.417: D/dalvikvm(8950): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libopenal.so 0x421565f0 03-29 16:14:08.422: D/dalvikvm(8950): Added shared lib /data/data/com.linekong.cjad.lk/files/libs/libopenal.so 0x421565f0 03-29 16:14:08.422: D/dalvikvm(8950): Trying to load lib /data/app-lib/com.linekong.cjad.lk-1/libcompress.so 0x421565f0 03-29 16:14:08.422: D/dalvikvm(8950): Shared lib '/data/app-lib/com.linekong.cjad.lk-1/libcompress.so' already loaded in same CL 0x421565f0 03-29 16:14:08.422: D/dalvikvm(8950): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libscript.so 0x421565f0 03-29 16:14:08.422: D/dalvikvm(8950): Added shared lib /data/data/com.linekong.cjad.lk/files/libs/libscript.so 0x421565f0 03-29 16:14:08.422: D/dalvikvm(8950): No JNI_OnLoad found in /data/data/com.linekong.cjad.lk/files/libs/libscript.so 0x421565f0, skipping init 03-29 16:14:08.422: D/dalvikvm(8950): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libiconv.so 0x421565f0 03-29 16:14:08.422: D/dalvikvm(8950): Added shared lib /data/data/com.linekong.cjad.lk/files/libs/libiconv.so 0x421565f0 03-29 16:14:08.422: D/dalvikvm(8950): No JNI_OnLoad found in /data/data/com.linekong.cjad.lk/files/libs/libiconv.so 0x421565f0, skipping init 03-29 16:14:08.422: D/dalvikvm(8950): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libogg.so 0x421565f0 03-29 16:14:08.427: D/dalvikvm(8950): Added shared lib /data/data/com.linekong.cjad.lk/files/libs/libogg.so 0x421565f0 03-29 16:14:08.427: D/dalvikvm(8950): No JNI_OnLoad found in /data/data/com.linekong.cjad.lk/files/libs/libogg.so 0x421565f0, skipping init 03-29 16:14:08.427: D/dalvikvm(8950): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libvorbis.so 0x421565f0 03-29 16:14:08.427: D/dalvikvm(8950): Added shared lib /data/data/com.linekong.cjad.lk/files/libs/libvorbis.so 0x421565f0 03-29 16:14:08.427: D/dalvikvm(8950): No JNI_OnLoad found in /data/data/com.linekong.cjad.lk/files/libs/libvorbis.so 0x421565f0, skipping init 03-29 16:14:08.427: D/dalvikvm(8950): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libvorbisfile.so 0x421565f0 03-29 16:14:08.427: D/dalvikvm(8950): Added shared lib /data/data/com.linekong.cjad.lk/files/libs/libvorbisfile.so 0x421565f0 03-29 16:14:08.427: D/dalvikvm(8950): No JNI_OnLoad found in /data/data/com.linekong.cjad.lk/files/libs/libvorbisfile.so 0x421565f0, skipping init 03-29 16:14:08.427: D/dalvikvm(8950): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libcurl.so 0x421565f0 03-29 16:14:08.427: D/dalvikvm(8950): Shared lib '/data/data/com.linekong.cjad.lk/files/libs/libcurl.so' already loaded in same CL 0x421565f0 03-29 16:14:08.427: D/dalvikvm(8950): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libautoupdater.so 0x421565f0 03-29 16:14:08.427: D/dalvikvm(8950): Shared lib '/data/data/com.linekong.cjad.lk/files/libs/libautoupdater.so' already loaded in same CL 0x421565f0 03-29 16:14:08.427: D/dalvikvm(8950): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libspeex.so 0x421565f0 03-29 16:14:08.432: D/dalvikvm(8950): Added shared lib /data/data/com.linekong.cjad.lk/files/libs/libspeex.so 0x421565f0 03-29 16:14:08.432: D/dalvikvm(8950): No JNI_OnLoad found in /data/data/com.linekong.cjad.lk/files/libs/libspeex.so 0x421565f0, skipping init 03-29 16:14:08.432: D/dalvikvm(8950): Trying to load lib /data/data/com.linekong.cjad.lk/files/libs/libmqcj.so 0x421565f0 03-29 16:14:08.502: D/dalvikvm(8950): Added shared lib /data/data/com.linekong.cjad.lk/files/libs/libmqcj.so 0x421565f0 03-29 16:14:08.502: W/Looper(8950): Looper already prepared for this thread with a different value for the ALOOPER_PREPARE_ALLOW_NON_CALLBACKS option. 03-29 16:14:08.507: V/VoiceManager(8950): VoiceManager Init Finished! 03-29 16:14:08.712: I/MemTotal: 1723840 kB MemFree: 357384 kB(8950): 03-29 16:14:08.712: I/MemTotal: 1723840 kB MemFree: 357384 kB(8950): MemTotal: 03-29 16:14:08.712: I/MemTotal: 1723840 kB MemFree: 357384 kB(8950): 1723840 03-29 16:14:08.712: I/MemTotal: 1723840 kB MemFree: 357384 kB(8950): kB 03-29 16:14:08.712: I/MemTotal: 1723840 kB MemFree: 357384 kB(8950): MemFree: 03-29 16:14:08.712: I/MemTotal: 1723840 kB MemFree: 357384 kB(8950): 357384 03-29 16:14:08.712: I/MemTotal: 1723840 kB MemFree: 357384 kB(8950): kB文章出自 http://blog.csdn.net/huutu
游戏分别从以下两个目录加载了SO文件
1、工程中的Libs文件夹,就是 /data/app-lib/,使用system.loadLibrary()加载
2、默认应用文件夹 /data/data/com.linekong.cjad.lk/files 中的 libs/* ,使用system.load() 加载
文章出自 http://blog.csdn.net/huutu
在Root过的手机上安装ES文件管理器后,在/data/data/com.linekong.cjad.lk/files/libs中找到了游戏所使用的SO,如下
文章出自 http://blog.csdn.net/huutu文章出自 http://blog.csdn.net/huutu
那么为什么要把Libs先压缩然后又解压出来呢,直接放到项目工程的Libs目录中不就好了?我想到的有以下两条原因:
1、其实这正也正式Cocos2d-x这么火的原因之一 --- 热更新。出了Bug?那就更新一下换一个SO吧……
2、江湖传言,有一种黑科技能将SO文件的压缩比率比APK默认压缩方法再提高50%。。。好吧其实就是7ZIP采用的LZMA压缩算法。
我们使用十万个为什么的几个SO来测试一下,看看默认放在项目Libs里面 和 使用7ZIP压缩之后放到Assets里面的文件大小差距吧。
这是游戏的SO文件,总共11M。
文章出自 http://blog.csdn.net/huutu
这是三种出包方式,把上面的SO文件直接放到Libs、使用ZIP压缩后放到Assets 、使用7ZIP压缩后放到Assets。
从中可以看出,7ZIP 当之无愧的压缩界黑科技。之前也有同行辟谣,蓝港所谓的内部高压缩算法其实就是LZMA,这下我也有理由相信了。
十万个为什么的资源后缀名是SPK,比如这个music.spk ,应该就是音乐了。我们把它改成 7Z后缀,然后解压。
居然直接就解压了……截图为证……这下子确认蓝港使用的就是LZMA压缩算法了……
最后呼吁一下,使用自研引擎的CP厂商么,赶紧把资源和SO用LZMA压缩一下!!
对于使用Unity的开发商,因为Unity用的就是LZMA,所以赶紧把Unity的那几个SO用LZMA压缩一下!!
文章出自 http://blog.csdn.net/huutu