U8SDK——当Flash游戏遇到应用宝YSDK
前一段时间,一个U8SDK的客户需要在应用宝上架一款用Flash开发的游戏,遇到了一个Flash游戏和应用宝YSDK不可磨合的冲突......
起源:
应用宝SDK:要求游戏Activity的生命周期中,需要调用应用宝SDK对应的onCreate, onResume, onPause,onActivityResult, onNewIntent等函数。
Adobe的Air引擎:根本没有对外暴露onCreate和onNewIntent生命周期函数。
问题:
如果不在这些生命周期函数中调用应用宝YSDK的对应函数,那么应用宝YSDK的微信登陆收不到回调。
同时,我们又发现另一个棘手的问题。 应用宝SDK登陆过一次之后, 再次进入的时候, 它默认会触发一次自动登录。 现在这个自动登录收不到回调了。
后来尝试了很多种方式,才发现: 应用宝的初始化接口和onCreate调用,必须在游戏启动Activity的onCreate生命周期函数中,自动登录才能收到回调。
这个就真的没法直接处理了。
对于微信收不到回调,我们试着重写了应用宝SDK的WXEntryActivity类,让他触发onNewIntent()。 这样处理之后,微信登陆终于可以收到回调了。
但是自动登录这个,因为Flash游戏和Android层的交互,需要通过ANE Extention来处理。 Adobe Air并没有对底层暴露引擎Activity的onCreate函数或者可以注入触发的监听器等。所以, SDK的初始化,只能在Flash层调用。
无论如何,甲方客户的游戏要上架应用宝。 作为乙方的我们绝对不能跟他说, 应用宝这个渠道上不了。
解决
后来,我们就想能否通过在U8SDK打包工具打包的过程中,来完成“移花接木”, 将SDK的初始化接口注入到最终游戏Activity的onCreate中去调用。
经过调研发现, Flash在导出apk的时候, 会在【air.包名】(这个包名是Flash游戏层设置的包名,不同游戏是不同的)下面生成一个AppEntry.class文件, 这个类就是最终启动Activity。
那我们就需要想办法,在打包的时候, 将U8SDK的初始化,注入到AppEntry的onCreate中。
看过U8SDK一键打包工具原理的同学应该知道, U8SDK打包的时候, 是先将母包apk反编译,再将渠道SDK的代码、资源等合并进去,最终再回编译成最终的渠道apk。
回编译之后, 母包的代码会被回编译成smali格式。那么我们参考之前对Application做的移花接木的方案, 我们也一样可以通过修改smali文件,将我们的SDK初始化逻辑插入到AppEntry中onCreate函数的对应位置。
如果我们直接在AppEntry的onCreate函数中某个位置插入SDK的初始化(smali)代码的话,对于不熟悉smali语法的同学可能有难度。 那我们换一种更简单的方式,将主要的工作在java中完成,这样我们就可以尽可能少地去修改smali。
最终,我们整理后的实现方式如下:
1、我们在Flash ANE库的Android层部分, 自定义一个Activity类(U8ANEActivity.java), 在这个Activity类中, 实现生命周期函数的调用,并在onCreate函数中完成SDK的初始化。
2、打包客户端中,通过自定义脚本(post_script.py), 将上面U8ANEActivity类的继承类改为AppEntry类(也是Activity的子类)
核心处理代码也很简单:
def modifyClassExtends(smaliPath, targetClassName):
targetClassName = targetClassName.replace(".", "/")
f = open(smaliPath, 'r')
lines = f.readlines()
f.close()
result = ""
for line in lines:
if line.strip().startswith('.super'):
result = result + '\n' + '.super L'+targetClassName+';\n'
else:
result = result + line
f = open(smaliPath, 'w')
f.write(result)
f.close()
return 0
3、然后在post_script.py中, 将AndroidManifest.xml中配置的启动类(AppEntry)改为我们的U8ANEActivity。
filePath = os.path.join(decompileDir, 'AndroidManifest.xml')
file_utils.modifyFileContent(filePath, baseStartActivity, 'com.u8.sdk.ane.U8ANEActivity')
4、这样最终的渠道apk包, 启动的时候, 启动类就是我们的U8ANEActivity类(通过修改smali将其改为继承了AppEntry)。然后启动的时候, 执行U8ANEActivity中的onCreate函数的时候,里面就有U8SDK的初始化逻辑。 其他生命周期函数中调用了U8SDK的对应生命周期函数。
通过这样操作之后,也不需要上面重写WXEntryActivity类的逻辑了,也不需要其他针对ANE做的生命周期逻辑的曲折实现了。 也算一个比较完美的解决方案了。