4. qq和qq空间 (独立app)
分析时用的是:
1. 夜神android模拟器(因为用android studio自带的模拟器运行x86架构的镜像提示不能安装qq空间,安装arm架构的镜像运行又极度慢)
使用过程中遇到adb找不到夜神模拟器的问题, 移步这里 adb devices检测不到模拟器 解决。
2. QQ空间版本7.4.1
3. QQ版本 7.1.8
QQ空间版本7.4.1 和 QQ版本 7.1.8 都是反编译分析时也就是写这篇文章时的最新版本。
qq空间的主题换肤在:我的空间 -> 个性化 -> 原创主题
qq的主题换肤在:左边侧滑栏 -> 个性装扮 -> 主题
下面开始分析。
用smali2java反编译qq空间.apk,有很大一部分代码反编译不出来。
用apktool反编译qq空间.apk, 会报错:
>java -jar apktool_2.2.4.jar d qq_zone.apk -o qq_zone
I: Using Apktool 2.2.4 on qq_zone.apk
I: Loading resource table...
Exception in thread "main" brut.androlib.AndrolibException: Could not decode arsc file
at brut.androlib.res.decoder.ARSCDecoder.decode(ARSCDecoder.java:52)
at brut.androlib.res.AndrolibResources.getResPackagesFromApk(AndrolibResources.java:562)
at brut.androlib.res.AndrolibResources.loadMainPkg(AndrolibResources.java:72)
at brut.androlib.res.AndrolibResources.getResTable(AndrolibResources.java:64)
at brut.androlib.Androlib.getResTable(Androlib.java:68)
at brut.androlib.ApkDecoder.setTargetSdkVersion(ApkDecoder.java:207)
at brut.androlib.ApkDecoder.decode(ApkDecoder.java:109)
at brut.apktool.Main.cmdDecode(Main.java:166)
at brut.apktool.Main.main(Main.java:80)
Caused by: java.io.IOException: Expected: 0x00000008, got: 0x00000003
at brut.util.ExtDataInput.skipCheckShort(ExtDataInput.java:56)
at brut.androlib.res.decoder.ARSCDecoder.readValue(ARSCDecoder.java:315)
at brut.androlib.res.decoder.ARSCDecoder.readEntry(ARSCDecoder.java:247)
at brut.androlib.res.decoder.ARSCDecoder.readTableType(ARSCDecoder.java:226)
at brut.androlib.res.decoder.ARSCDecoder.readTableTypeSpec(ARSCDecoder.java:156)
at brut.androlib.res.decoder.ARSCDecoder.readTablePackage(ARSCDecoder.java:118)
at brut.androlib.res.decoder.ARSCDecoder.readTableHeader(ARSCDecoder.java:80)
at brut.androlib.res.decoder.ARSCDecoder.decode(ARSCDecoder.java:47)
... 8 more
因此就看不了qq空间的资源文件了,目前还没有解决这个问题。
然后来看下qq的。
用smali2java反编译查看qq源码,发现也是有很大一部分代码反编译不出来。
只好去看看能不能从资源文件入手吗,用apktool反编译qq.apk文件,查看资源文件:
res\layout下的布局文件:
res\values\colors.xml文件:
#00ffffff
#ff000000
#ffa6a6a6
#ffc8c7cc
#ff808080
#ffb2b2b2
#ff333333
#ffc8c8c8
#ffffffff
#ffff6600
#ffff3b30
#ff43c959
#ff00a5e0
#ff0079ff
#8000a5e0
#90000000
#ffe6e6e6
#ffffffff
#ff333333
res\values\dimens.xml文件:
1.0px
45.0sp
19.0sp
18.0sp
15.0sp
12.0sp
13.0sp
14.0sp
11.0sp
52.0dip
34.0dip
15.0sp
50.0dip
BitApp消息
http://combo.b.qq.com/crm3mobile/src/zip/
消息显示失败
[动态消息]
请选择邮件客户端:
你的手机尚未安装邮件应用,请安装邮件应用后再试
添加失败
已更新
保存到电话簿
QQ公众号
微信公众号
重绑
使用微信扫二维码关注微信公众号
免费电话
企业免费电话
企业接待信息有误
网络超时
发现这些资源文件的名称都反编译不出来, 看来QQ的混淆程度做的很深。
于是看看能不能从其他方面入手。
我们使用qq空间或者qq的时候注意到,使用主题前必须要先下载皮肤包,下载下来的皮肤包肯定要存储,那么存储在哪?
只可能在两个地方:
1. SD卡
2. 应用程序的目录
下面我们先来看下应用程序的目录,试试看能不能找到有用的信息。
第一步:得到qq空间包名
打开qq空间app,执行命令:adb shell dumpsys activity top 或者执行: adb shell dumpsys activity activities 也可以
这里执行的是:adb shell dumpsys activity activities
得到qq空间包名是:com.qzone
第二步:进入qq空间的应用程序目录,查看资源
进入/data/data目录,执行ls -l 命令列出当前系统所有已安装的包名,
可以看到的确有qq空间:
倒数第四个就是。 进入com.qzone目录。
再次执行ls -l,
进入shared_prefs目录:
现在还没看到什么关键信息,别急,现在进入我的空间 -> 个性化 -> 原创主题, 到主题下载页面,下载并应用一个主题,然后再执行ls -l
找到了theme.xml, 就在倒数第三个。
查看theme.xml文件内容:
找到了皮肤文件存放的目录:
/storage/emulated/0/Android/data/com.qzone/files/cache/qz_external_resource/theme_res/1/res/
从路径中也可以看出qq空间下载的皮肤包是存储在sd卡里的。
然后我又下载并应用另外一个新的皮肤,再来查看该文件内容:
看到路径中数字由1变为了103, 其它均没变,说明不同皮肤包存储路径不一样。
本来想着进入/data/data/com.qzone/files/cache/qz_external_resource/theme_res/103目录查看相关资源,可是发现/data/data/com.qzone/files/cache/目录下没有qz_external_resource目录,这也不难理解,因为/data/data/是应用程序的目录,是在内置存储器上的,而不是sd卡里的目录, 思考了一段时间,执行下列操作:
1. 把当前路径回退到根目录,
2. 执行: find . -name qz_external_resource 即在在根目录下搜索qz_external_resource
终于找到qz_external_resource在哪了:
执行:cd /mnt/shell/emulated/0/Android/data/com.qzone/files/cache/qz_external_resource/theme_res 进入到theme_res目录
再执行:ls -l
看到了 1 目录和103目录,分别是两个皮肤包的存储目录,进入1目录:
终于找到了皮肤包文件! 做过apk解压的一看就知道这是.apk文件解压缩之后得到的文件
到了这里就可以知道qq空间的换肤方案采用的就是动态加载,下载的皮肤包就是一个apk文件,然后动态加载apk,替换资源文件。
再来看看qq的,分析方法同qq空间一样,
打开qq,
执行: adb shell dumpsys activity activities
可以看到qq的包名是:com.tencent.mobileqq
果然在qq的程序目录data/data/com.tencent.mobileqq下找到了theme.xml文件 ,里面的内容和qq空间的几乎一样:
根据路径知道,和qq空间不同的是,qq的皮肤包是放在应用程序目录下,而不是放在SD卡中。
到现在已经可以确定qq和qq空间实现换肤的大体方案:采用动态加载皮肤包apk的方式来实现换肤。
那么具体是采用哪种动态加载的策略呢,接下来就要探讨这个问题。
下面是用 jadx 来反编译:
来看qq的:
展开com.tencent.theme目录,看到有SkinEngine类:
再来看下qq空间反编译后的:
展开com.tencent.theme目录,看到有SkinEngine类:
由以上分析,QQ和QQ空间的换肤用的都是SkinEngine这个关键的类来实现的。
查看QQ和QQ空间的SkinEngine的源码,发现是差不多的,选一个来分析即可,下面就来分析QQ这个关键的SkinEngine类。
虽然很多代码反编译不出来,但是关键类SkinEngine的很多代码还是可以反编译出来的,来看一些关键的代码:
public static void init(Context context, int[] iArr, Class cls, int i, File file) throws UnSupportPlatformException {
SkinEngine instances = getInstances();
Resources resources = context.getResources();
instances.mResources = resources;
isSupportPlatform(context, resources);
instances.u = a(instances.mResources);
context.getApplicationContext().registerReceiver(instances.l, new IntentFilter(ACTION_THEME_UPDATE), "com.tencent.msg.permission.pushnotify", null);
instances.a(resources, null, iArr, 0, cls, i, file);
SharedPreferences sharedPreferences = context.getSharedPreferences(PREFERENCE_NAME, 4);
instances.s = sharedPreferences.getString(KEY_THEME, null);
instances.o = sharedPreferences.getBoolean(KEY_RESOURCES_IS_COMPLIED, true);
}
/* JADX WARNING: inconsistent code. */
/* Code decompiled incorrectly, please refer to instructions dump. */
private void a(android.content.res.Resources r16, java.lang.Class r17, int[] r18, int r19, java.lang.Class r20, int r21, java.io.File r22) throws com.tencent.theme.UnSupportPlatformException {
/*
r15 = this;
r2 = 0;
if (r18 != 0) goto L_0x0007;
L_0x0003:
if (r17 == 0) goto L_0x0060;
L_0x0005:
if (r19 == 0) goto L_0x0060;
L_0x0007:
r1 = b; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
if (r1 == 0) goto L_0x018b;
L_0x000b:
r1 = android.content.res.Resources.class;
r2 = "mResourcesImpl";
r1 = r1.getDeclaredField(r2); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = 1;
r1.setAccessible(r2); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r0 = r16;
r14 = r1.get(r0); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r1 = r14.getClass(); Catch:{ NoSuchFieldException -> 0x0179, IllegalArgumentException -> 0x01bd, IllegalAccessException -> 0x0242 }
r2 = "sPreloadedDrawables";
r1 = r1.getDeclaredField(r2); Catch:{ NoSuchFieldException -> 0x0179, IllegalArgumentException -> 0x01bd, IllegalAccessException -> 0x0242 }
L_0x0029:
r2 = 1;
r1.setAccessible(r2); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = r1.get(r14); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r8 = r1;
L_0x0032:
r1 = r2 instanceof android.util.LongSparseArray; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
if (r1 == 0) goto L_0x01d4;
L_0x0036:
if (r18 == 0) goto L_0x01a3;
L_0x0038:
r1 = new com.tencent.theme.g; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r3 = 1;
r6 = new android.util.LongSparseArray[r3]; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r3 = 0;
r2 = (android.util.LongSparseArray) r2; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r6[r3] = r2; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = r15;
r3 = r16;
r4 = r18;
r5 = r22;
r1.(r2, r3, r4, r5, r6); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r15.v = r1; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
L_0x004e:
r1 = b; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
if (r1 == 0) goto L_0x01c4;
L_0x0052:
if (r14 == 0) goto L_0x01c4;
L_0x0054:
r1 = new com.tencent.theme.h; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = 0;
r3 = r15.v; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r1.(r2, r3); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r8.set(r14, r1); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = r14;
L_0x0060:
r1 = android.os.Build.VERSION.SDK_INT; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r3 = 23;
if (r1 < r3) goto L_0x009c;
L_0x0066:
r1 = "samsung";
r3 = android.os.Build.BRAND; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r1 = r1.equalsIgnoreCase(r3); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
if (r1 == 0) goto L_0x009c;
L_0x0071:
r1 = android.content.res.Resources.class;
r3 = "mALDC";
r1 = r1.getDeclaredField(r3); Catch:{ Throwable -> 0x0235 }
if (r1 == 0) goto L_0x0249;
L_0x007c:
r3 = 1;
r1.setAccessible(r3); Catch:{ Throwable -> 0x0235 }
r3 = r15.mResources; Catch:{ Throwable -> 0x0235 }
r1 = r1.get(r3); Catch:{ Throwable -> 0x0235 }
if (r1 == 0) goto L_0x0217;
L_0x0088:
r3 = r1 instanceof java.util.Map; Catch:{ Throwable -> 0x0235 }
if (r3 == 0) goto L_0x0217;
L_0x008c:
r1 = (java.util.Map) r1; Catch:{ Throwable -> 0x0235 }
r1.clear(); Catch:{ Throwable -> 0x0235 }
r1 = "SkinEngine";
r3 = 2;
r4 = "clear mALDC suss";
r5 = 0;
com.tencent.theme.j.c(r1, r3, r4, r5); Catch:{ Throwable -> 0x0235 }
L_0x009c:
r1 = "SkinEngine";
r3 = 2;
r4 = "initIntercepter DrawablePreloadIntercepter ok";
r5 = 0;
com.tencent.theme.j.c(r1, r3, r4, r5); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
if (r20 == 0) goto L_0x00f7;
L_0x00a9:
if (r21 == 0) goto L_0x00f7;
L_0x00ab:
r1 = b; Catch:{ Exception -> 0x0292 }
if (r1 == 0) goto L_0x0268;
L_0x00af:
r1 = android.content.res.Resources.class;
r2 = "mResourcesImpl";
r1 = r1.getDeclaredField(r2); Catch:{ Exception -> 0x0292 }
r2 = 1;
r1.setAccessible(r2); Catch:{ Exception -> 0x0292 }
r0 = r16;
r2 = r1.get(r0); Catch:{ Exception -> 0x0292 }
r1 = r2.getClass(); Catch:{ NoSuchFieldException -> 0x0256, IllegalArgumentException -> 0x01bd, IllegalAccessException -> 0x0242 }
r3 = "sPreloadedComplexColors";
r3 = r1.getDeclaredField(r3); Catch:{ NoSuchFieldException -> 0x0256, IllegalArgumentException -> 0x01bd, IllegalAccessException -> 0x0242 }
L_0x00cd:
r1 = 1;
r3.setAccessible(r1); Catch:{ Exception -> 0x0292 }
r1 = r3.get(r2); Catch:{ Exception -> 0x0292 }
r1 = (android.util.LongSparseArray) r1; Catch:{ Exception -> 0x0292 }
r4 = r1;
r7 = r2;
r8 = r3;
L_0x00da:
r1 = a; Catch:{ Exception -> 0x0292 }
if (r1 == 0) goto L_0x0282;
L_0x00de:
r1 = new com.tencent.theme.f; Catch:{ Exception -> 0x0292 }
r2 = r15;
r3 = r16;
r5 = r20;
r6 = r21;
r1.(r2, r3, r4, r5, r6); Catch:{ Exception -> 0x0292 }
r15.w = r1; Catch:{ Exception -> 0x0292 }
L_0x00ec:
r1 = b; Catch:{ Exception -> 0x0292 }
if (r1 == 0) goto L_0x02c3;
L_0x00f0:
if (r7 == 0) goto L_0x02c3;
L_0x00f2:
r1 = r15.w; Catch:{ Exception -> 0x0292 }
r8.set(r7, r1); Catch:{ Exception -> 0x0292 }
L_0x00f7:
r1 = "SkinEngine";
r2 = 2;
r3 = "initIntercepter colorStateListPreloadIntercepter ok";
r4 = 0;
com.tencent.theme.j.c(r1, r2, r3, r4); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r1 = r16.getClass(); Catch:{ Exception -> 0x02ef }
r2 = r1.getName(); Catch:{ Exception -> 0x02ef }
r3 = "android.content.res.MiuiResources";
r2 = r2.equals(r3); Catch:{ Exception -> 0x02ef }
if (r2 == 0) goto L_0x0133;
L_0x0113:
r2 = "sPreloadDrawableSources";
r1 = r1.getDeclaredField(r2); Catch:{ Exception -> 0x02ef }
r2 = 1;
r1.setAccessible(r2); Catch:{ Exception -> 0x02ef }
r0 = r16;
r2 = r1.get(r0); Catch:{ Exception -> 0x02ef }
if (r2 != 0) goto L_0x0133;
L_0x0126:
r2 = new android.util.SparseArray; Catch:{ Exception -> 0x02ef }
r2.(); Catch:{ Exception -> 0x02ef }
r0 = r16;
r1.set(r0, r2); Catch:{ Exception -> 0x02ef }
r1 = 1;
IS_PROBLEM_MIUI = r1; Catch:{ Exception -> 0x02ef }
L_0x0133:
r1 = r16.getClass(); Catch:{ Exception -> 0x0302 }
r2 = "mIcons";
r1 = r1.getDeclaredField(r2); Catch:{ Exception -> 0x0302 }
mIconsOfCM = r1; Catch:{ Exception -> 0x0302 }
r1 = mIconsOfCM; Catch:{ Exception -> 0x0302 }
r2 = 1;
r1.setAccessible(r2); Catch:{ Exception -> 0x0302 }
r1 = mIconsOfCM; Catch:{ Exception -> 0x0302 }
r2 = 0;
r0 = r16;
r1.set(r0, r2); Catch:{ Exception -> 0x0302 }
r1 = mIconsOfCM; Catch:{ Exception -> 0x0302 }
r2 = 0;
r1.setAccessible(r2); Catch:{ Exception -> 0x0302 }
r1 = r16.getClass(); Catch:{ Exception -> 0x0302 }
r2 = "mComposedIconInfo";
r1 = r1.getDeclaredField(r2); Catch:{ Exception -> 0x0302 }
mComposedIconInfoOfCM = r1; Catch:{ Exception -> 0x0302 }
r1 = mComposedIconInfoOfCM; Catch:{ Exception -> 0x0302 }
r2 = 1;
r1.setAccessible(r2); Catch:{ Exception -> 0x0302 }
r1 = mComposedIconInfoOfCM; Catch:{ Exception -> 0x0302 }
r2 = 0;
r0 = r16;
r1.set(r0, r2); Catch:{ Exception -> 0x0302 }
r1 = mComposedIconInfoOfCM; Catch:{ Exception -> 0x0302 }
r2 = 0;
r1.setAccessible(r2); Catch:{ Exception -> 0x0302 }
r1 = 1;
IS_PROBLEM_CM11 = r1; Catch:{ Exception -> 0x0302 }
L_0x0178:
return;
L_0x0179:
r1 = move-exception;
r1 = r14.getClass(); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r1 = r1.getSuperclass(); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = "sPreloadedDrawables";
r1 = r1.getDeclaredField(r2); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
goto L_0x0029;
L_0x018b:
r1 = android.content.res.Resources.class;
r3 = "sPreloadedDrawables";
r3 = r1.getDeclaredField(r3); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r1 = 1;
r3.setAccessible(r1); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r0 = r16;
r1 = r3.get(r0); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r14 = r2;
r8 = r3;
r2 = r1;
goto L_0x0032;
L_0x01a3:
r1 = new com.tencent.theme.g; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r3 = 1;
r7 = new android.util.LongSparseArray[r3]; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r3 = 0;
r2 = (android.util.LongSparseArray) r2; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r7[r3] = r2; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = r15;
r3 = r16;
r4 = r17;
r5 = r19;
r6 = r22;
r1.(r2, r3, r4, r5, r6, r7); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r15.v = r1; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
goto L_0x004e;
L_0x01bd:
r1 = move-exception;
r2 = new com.tencent.theme.UnSupportPlatformException;
r2.(r1);
throw r2;
L_0x01c4:
r1 = new com.tencent.theme.h; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = 0;
r3 = r15.v; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r1.(r2, r3); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r0 = r16;
r8.set(r0, r1); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = r14;
goto L_0x0060;
L_0x01d4:
r1 = r2 instanceof android.util.LongSparseArray[]; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
if (r1 == 0) goto L_0x030b;
L_0x01d8:
r2 = (android.util.LongSparseArray[]) r2; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r0 = r2;
r0 = (android.util.LongSparseArray[]) r0; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r6 = r0;
if (r18 == 0) goto L_0x01fe;
L_0x01e0:
r1 = new com.tencent.theme.g; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = r15;
r3 = r16;
r4 = r18;
r5 = r22;
r1.(r2, r3, r4, r5, r6); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r15.v = r1; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
L_0x01ee:
r1 = 0;
L_0x01ef:
r2 = r6.length; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
if (r1 >= r2) goto L_0x030b;
L_0x01f2:
r2 = new com.tencent.theme.h; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r3 = r15.v; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2.(r1, r3); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r6[r1] = r2; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r1 = r1 + 1;
goto L_0x01ef;
L_0x01fe:
r7 = new com.tencent.theme.g; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r8 = r15;
r9 = r16;
r10 = r17;
r11 = r19;
r12 = r22;
r13 = r6;
r7.(r8, r9, r10, r11, r12, r13); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r15.v = r7; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
goto L_0x01ee;
L_0x0210:
r1 = move-exception;
r2 = new com.tencent.theme.UnSupportPlatformException;
r2.(r1);
throw r2;
L_0x0217:
r3 = "SkinEngine";
r4 = 1;
r5 = new java.lang.StringBuilder; Catch:{ Throwable -> 0x0235 }
r5.(); Catch:{ Throwable -> 0x0235 }
r6 = "clear fail, mALDC type:";
r5 = r5.append(r6); Catch:{ Throwable -> 0x0235 }
r1 = r5.append(r1); Catch:{ Throwable -> 0x0235 }
r1 = r1.toString(); Catch:{ Throwable -> 0x0235 }
r5 = 0;
com.tencent.theme.j.c(r3, r4, r1, r5); Catch:{ Throwable -> 0x0235 }
goto L_0x009c;
L_0x0235:
r1 = move-exception;
r3 = "SkinEngine";
r4 = 1;
r5 = "clear mALDC Error";
com.tencent.theme.j.a(r3, r4, r5, r1); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
goto L_0x009c;
L_0x0242:
r1 = move-exception;
r2 = new com.tencent.theme.UnSupportPlatformException;
r2.(r1);
throw r2;
L_0x0249:
r1 = "SkinEngine";
r3 = 1;
r4 = "clear fail, null == f";
r5 = 0;
com.tencent.theme.j.c(r1, r3, r4, r5); Catch:{ Throwable -> 0x0235 }
goto L_0x009c;
L_0x0256:
r1 = move-exception;
r1 = r2.getClass(); Catch:{ Exception -> 0x0292 }
r1 = r1.getSuperclass(); Catch:{ Exception -> 0x0292 }
r3 = "sPreloadedComplexColors";
r3 = r1.getDeclaredField(r3); Catch:{ Exception -> 0x0292 }
goto L_0x00cd;
L_0x0268:
r1 = android.content.res.Resources.class;
r3 = "sPreloadedColorStateLists";
r3 = r1.getDeclaredField(r3); Catch:{ Exception -> 0x0292 }
r1 = 1;
r3.setAccessible(r1); Catch:{ Exception -> 0x0292 }
r0 = r16;
r1 = r3.get(r0); Catch:{ Exception -> 0x0292 }
r1 = (android.util.LongSparseArray) r1; Catch:{ Exception -> 0x0292 }
r4 = r1;
r7 = r2;
r8 = r3;
goto L_0x00da;
L_0x0282:
r1 = new com.tencent.theme.d; Catch:{ Exception -> 0x0292 }
r2 = r15;
r3 = r16;
r5 = r20;
r6 = r21;
r1.(r2, r3, r4, r5, r6); Catch:{ Exception -> 0x0292 }
r15.w = r1; Catch:{ Exception -> 0x0292 }
goto L_0x00ec;
L_0x0292:
r1 = move-exception;
r2 = android.content.res.Resources.class;
r3 = "mPreloadedColorStateLists";
r7 = r2.getDeclaredField(r3); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = 1;
r7.setAccessible(r2); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r0 = r16;
r4 = r7.get(r0); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = r4 instanceof android.util.SparseArray; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
if (r2 == 0) goto L_0x02cc;
L_0x02aa:
r1 = new com.tencent.theme.e; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r4 = (android.util.SparseArray) r4; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = r15;
r3 = r16;
r5 = r20;
r6 = r21;
r1.(r2, r3, r4, r5, r6); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r15.x = r1; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r1 = r15.x; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r0 = r16;
r7.set(r0, r1); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
goto L_0x00f7;
L_0x02c3:
r1 = r15.w; Catch:{ Exception -> 0x0292 }
r0 = r16;
r8.set(r0, r1); Catch:{ Exception -> 0x0292 }
goto L_0x00f7;
L_0x02cc:
r2 = r4 instanceof android.util.LongSparseArray; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
if (r2 == 0) goto L_0x02e9;
L_0x02d0:
r1 = new com.tencent.theme.d; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r4 = (android.util.LongSparseArray) r4; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2 = r15;
r3 = r16;
r5 = r20;
r6 = r21;
r1.(r2, r3, r4, r5, r6); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r15.w = r1; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r1 = r15.w; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r0 = r16;
r7.set(r0, r1); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
goto L_0x00f7;
L_0x02e9:
r2 = new com.tencent.theme.UnSupportPlatformException; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
r2.(r1); Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
throw r2; Catch:{ IllegalArgumentException -> 0x01bd, NoSuchFieldException -> 0x0210, IllegalAccessException -> 0x0242 }
L_0x02ef:
r1 = move-exception;
r2 = DEBUG;
if (r2 == 0) goto L_0x02fd;
L_0x02f4:
r2 = "SkinEngine";
r3 = "";
android.util.Log.e(r2, r3, r1);
L_0x02fd:
r1 = 0;
IS_PROBLEM_MIUI = r1;
goto L_0x0133;
L_0x0302:
r1 = move-exception;
r1 = 0;
mIconsOfCM = r1;
r1 = 0;
mComposedIconInfoOfCM = r1;
goto L_0x0178;
L_0x030b:
r2 = r14;
goto L_0x0060;
*/
throw new UnsupportedOperationException("Method not decompiled: com.tencent.theme.SkinEngine.a(android.content.res.Resources, java.lang.Class, int[], int, java.lang.Class, int, java.io.File):void");
}
再来看unInit()方法,这个方法代码比较清楚:
public void unInit() {
Field declaredField;
try {
if (this.v != null) {
declaredField = Resources.class.getDeclaredField("sPreloadedDrawables");
declaredField.setAccessible(true);
if (declaredField.getDeclaringClass().isArray()) {
declaredField.set(null, this.v.b);
} else {
declaredField.set(null, this.v.b[0]);
}
}
try {
Field declaredField2 = Resources.class.getDeclaredField("sPreloadedColorStateLists");
declaredField2.setAccessible(true);
LongSparseArray longSparseArray = (LongSparseArray) declaredField2.get(this.mResources);
declaredField2.set(null, this.w.b);
} catch (Exception e) {
declaredField = Resources.class.getDeclaredField("mPreloadedColorStateLists");
declaredField.setAccessible(true);
Object obj = declaredField.get(this.mResources);
if (obj instanceof SparseArray) {
declaredField.set(null, this.x.b);
} else if (obj instanceof LongSparseArray) {
declaredField.set(null, this.w.b);
}
}
} catch (Throwable e2) {
if (DEBUG) {
Log.e(TAG, "resotre SkinEngine failed", e2);
}
}
}
根据上述代码再结合Resources获取资源的getDrawable()方法的实现原理: getDrawable()方法会从 sPreloadedDrawables中获取图片,具体可在Resources类源码中查看。
综合两者可以推出SkinEngine的大致实现原理:通过反射获取Resources类的sPreloadedDrawables成员变量,使其指向自定义实现的DrawablePreloadIntercepter对象,在DrawablePreloadIntercepter中重写get()方法,当系统调用get()方法获取图片时即获取到换肤后的图片,从而实现换肤。