由于成本原因,负责自研了混合推送SDK给公司安卓端使用,之前都是好好的。
突然在某一天,测试同学把oppo K3手机升级到了安卓10系统,发现推送无法使用。同事负责新app推送的接入,发现了问题,并且发现必须把oppo推送sdk升级到2.1.0才能使用。
升级完后,功能倒是可以用了,但因为oppo只提供aar包,所以app同学使用时还要再依赖oppo_push.aar。
这对于app的同学简直忍不了啊,引入一个sdk,还得引入一个aar,what the fuck?
公司有自己的maven仓库,必须要把oppo库组件化才能简化依赖关系。
有两种方式:一种是把aar打入工程,另一种是直接把aar放到公司maven并自己维护pom等依赖关系。
感觉第二种方式遇到版本时更不友好,所以采用第一种方式。下面开始了aar转本地代码的过程。
先看了aar的资源引用,几乎没有任何资源文件引入,除了一个地方:
public void a(final Context context) {
if (Build.VERSION.SDK_INT >= 26) {
f.a(new Runnable() {
/* class com.heytap.mcssdk.b.a.AnonymousClass1 */
public void run() {
if (!d.a(context)) {
String string = context.getString(R.string.system_default_channel);
if (TextUtils.isEmpty(string)) {
string = a.b;
}
d.a(context, a.this.a(context, a.a, string, a.c));
}
}
});
}
}
先不管,先把aar中的jar弄到混合推送的工程,编译运行demo。
果不其然,闪退了,报找不到R.string.system_default_channel。
没有R,我们造一个R文件就得了,我搞了一个包名变量名一模一样的R文件。
重新运行,依旧报错,这是何等的卧槽。反编译apk发现根本没有R这个类。
把R改名为RA,再次编译,检查apk,RA文件竟然神奇地出现了。
结论:安卓开发,不能以R作为文件名,android studio编译时会根据资源配置文件自动生成R文件,并去除已有的R文件。
找不到这个String,那能不能给oppo的sdk传一个ContextWrapper,把getString的行为改变?
应该是可以的。
sdk直接保存传入sdk的applicationContext,所以新建一个ContextWrapper,覆写getApplicationContext方法,使其返回另一个ContextWrapper,然后这个ContextWrapper覆写getResource方法(因为context.getString先调用getResource,然后再调用Resource#getString)。
重新运行,还是报错。
哪里不对呢?发现原来是自己脑子瓦特了,这个报错是找不到R.string.system_default_channel,而不是获取不到值。。。
最后只能寄希望于反编译上了。
平时用的反编译工具是jd-gui,对于一般任务都得心应手,对于反编译出来的代码,是这样的:
可是把它导出放到工程的时候,发现巨量的错误,主要是mcssdk下的a包名和a类名字重复,导致很多引用搞混了。
这种错误太多了,如果一个个搞,要费大量时间,而且后续oppo升级版本,也不好维护它的代码。
有没有什么更好的方法?jd-gui可以做到这一步,其实把重名的包和类重命名一下,这个问题不就解决了?当然这个活我是没时间做了。
接下来受这篇文章指点,发现原来有jadx-gui这种更牛逼的反编译工具,竟然可以反混淆,我是惊呆了的。
https://cloud.tencent.com/developer/article/1548700
太强大了,使用效果:
这根本就不用改了呀,直接就能用了好吗。
直接把代码放入推送工程,组件化完成。