Skip to content

Commit 63653ef

Browse files
author
weiqiangliu
committed
Release 3.2.12
1 parent c085c21 commit 63653ef

File tree

4 files changed

+72
-29
lines changed

4 files changed

+72
-29
lines changed

plugin/ext.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
project.ext {
2-
pluginVersion = '3.2.11'
2+
pluginVersion = '3.2.12'
33
Properties properties = new Properties()
44
if (project.file('local.properties').exists()) {
55
properties.load(project.file('local.properties').newDataInputStream())

plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/SensorsAnalyticsClassVisitor.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ class SensorsAnalyticsClassVisitor extends ClassVisitor {
173173

174174
MethodVisitor methodVisitor = cv.visitMethod(access, name, desc, signature, exceptions)
175175
if (transformHelper.extension != null && transformHelper.extension.autoHandleWebView && transformHelper.urlClassLoader != null) {
176-
methodVisitor = new SensorsAnalyticsWebViewMethodVisitor(methodVisitor, transformHelper, mClassName, mSuperName)
176+
methodVisitor = new SensorsAnalyticsWebViewMethodVisitor(methodVisitor, access, name, desc, transformHelper, mClassName, mSuperName)
177177
}
178178
SensorsAnalyticsDefaultMethodVisitor sensorsAnalyticsDefaultMethodVisitor = new SensorsAnalyticsDefaultMethodVisitor(methodVisitor, access, name, desc) {
179179
boolean isSensorsDataTrackViewOnClickAnnotation = false

plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/SensorsAnalyticsTransform.groovy

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import groovy.io.FileType
3333
import org.apache.commons.codec.digest.DigestUtils
3434
import org.apache.commons.io.FileUtils
3535
import org.apache.commons.io.IOUtils
36-
import org.apache.commons.io.output.ByteArrayOutputStream
3736
import org.objectweb.asm.ClassReader
3837
import org.objectweb.asm.ClassVisitor
3938
import org.objectweb.asm.ClassWriter
@@ -46,8 +45,8 @@ import java.util.jar.JarOutputStream
4645

4746
class SensorsAnalyticsTransform extends Transform {
4847
private SensorsAnalyticsTransformHelper transformHelper
49-
public static final String VERSION = "3.2.11"
50-
public static final String MIN_SDK_VERSION = "4.0.7"
48+
public static final String VERSION = "3.2.12"
49+
public static final String MIN_SDK_VERSION = "4.3.2"
5150
private WaitableExecutor waitableExecutor
5251
private URLClassLoader urlClassLoader
5352

@@ -311,6 +310,10 @@ class SensorsAnalyticsTransform extends Transform {
311310
}
312311

313312
private File modifyJar(File jarFile, File tempDir, boolean isNameHex) {
313+
//FIX: ZipException: zip file is empty
314+
if (jarFile == null || jarFile.length() == 0) {
315+
return null
316+
}
314317
//取原 jar, verify 参数传 false, 代表对 jar 包不进行签名校验
315318
def file = new JarFile(jarFile, false)
316319
//设置输出到的 jar

plugin/src/main/groovy/com/sensorsdata/analytics/android/plugin/SensorsAnalyticsWebViewMethodVisitor.groovy

Lines changed: 64 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -19,58 +19,98 @@ package com.sensorsdata.analytics.android.plugin
1919

2020
import org.objectweb.asm.MethodVisitor
2121
import org.objectweb.asm.Opcodes
22+
import org.objectweb.asm.Type
23+
import org.objectweb.asm.commons.AdviceAdapter
2224

23-
class SensorsAnalyticsWebViewMethodVisitor extends MethodVisitor implements Opcodes {
25+
/**
26+
* 判断逻辑:
27+
*
28+
* 如果当前方法所在的类是 WebView 的子类,并且被处理的方法是目标方法中的一个就不处理;
29+
* 否则就判断 owner 是否是 WebView 的子类,如果是就处理,否则不处理。
30+
*/
31+
class SensorsAnalyticsWebViewMethodVisitor extends AdviceAdapter implements Opcodes {
2432

2533
private SensorsAnalyticsTransformHelper transformHelper
2634
private Class webView
2735
private Class x5WebView
2836
private boolean isPreviousX5WebView = false
2937
private static X5WebViewStatus x5WebViewStatus = X5WebViewStatus.NOT_INITIAL
30-
private static final def TARGET_NAME_DESC = ["loadUrl(Ljava/lang/String;)V", "loadUrl(Ljava/lang/String;Ljava/util/Map;)V",
31-
"loadData(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
32-
"loadDataWithBaseURL(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
33-
"postUrl(Ljava/lang/String;[B)V"]
34-
private static final def VIEW_DESC = "Landroid/view/View;"
35-
private static final def OWNER_WHITE_SET = new HashSet(["android/webkit/WebView", "com/tencent/smtt/sdk/WebView"])
38+
//目标方法
39+
private static final List<String> TARGET_NAME_DESC = ["loadUrl(Ljava/lang/String;)V", "loadUrl(Ljava/lang/String;Ljava/util/Map;)V",
40+
"loadData(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
41+
"loadDataWithBaseURL(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
42+
"postUrl(Ljava/lang/String;[B)V"]
43+
private static final String VIEW_DESC = "Landroid/view/View;"
44+
private static final HashSet OWNER_WHITE_SET = new HashSet(["android/webkit/WebView", "com/tencent/smtt/sdk/WebView"])
3645
private String className
3746
private String superName
47+
private String methodNameDesc
48+
private boolean shouldSkip = false
3849

39-
40-
SensorsAnalyticsWebViewMethodVisitor(MethodVisitor mv, SensorsAnalyticsTransformHelper transformHelper, String className, String superName) {
41-
super(SensorsAnalyticsUtil.ASM_VERSION, mv)
50+
SensorsAnalyticsWebViewMethodVisitor(MethodVisitor mv, int access, String name, String desc, SensorsAnalyticsTransformHelper transformHelper, String className, String superName) {
51+
super(SensorsAnalyticsUtil.ASM_VERSION, mv, access, name, desc)
4252
this.transformHelper = transformHelper
4353
this.className = className
4454
this.superName = superName
55+
this.methodNameDesc = name + desc
56+
//如果当前方法符合目标定义,而且此类是 WebView 的子类,那么就跳过 visitMethodInsn 的指令
57+
if (TARGET_NAME_DESC.contains(methodNameDesc) && isAssignableWebView(className)) {
58+
shouldSkip = true
59+
}
4560
}
4661

4762
@Override
4863
void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
49-
if (TARGET_NAME_DESC.contains(name + desc)) {
50-
if (!checkWebViewChild(className)) {
64+
if (shouldSkip) {
65+
super.visitMethodInsn(opcode, owner, name, desc, itf)
66+
return
67+
}
68+
try {
69+
if (opcode != INVOKESTATIC && TARGET_NAME_DESC.contains(name + desc)) {
70+
// 解决 NoClassDefError 问题
71+
if (superName == "com/tencent/smtt/sdk/WebViewClient") {
72+
super.visitMethodInsn(opcode, owner, name, desc, itf)
73+
return
74+
}
5175
if (isAssignableWebView(owner)) {
52-
opcode = INVOKESTATIC
53-
owner = SensorsAnalyticsHookConfig.SENSORS_ANALYTICS_API
76+
Type[] argTypes = Type.getArgumentTypes(desc)
77+
List<Integer> positionList = new ArrayList<>()
78+
//依次复制操作数栈顶的元素到局部变量表中保存
79+
for (int index = 0; index < argTypes.length; index++) {
80+
int position = newLocal(argTypes[index])
81+
storeLocal(position)
82+
positionList.add(position)
83+
}
84+
int ownerPosition = newLocal(Type.getObjectType(owner))
85+
storeLocal(ownerPosition)
86+
positionList.add(ownerPosition)
87+
//将局部变量表中的数据压入操作数栈中触发原有的方法
88+
positionList.reverseEach { tmp ->
89+
loadLocal(tmp)
90+
}
91+
super.visitMethodInsn(opcode, owner, name, desc, itf)
92+
//将局部变量表中的数据压入操作数栈中触发我们需要插入的方法
93+
positionList.reverseEach { tmp ->
94+
loadLocal(tmp)
95+
}
5496
desc = reStructureDesc(desc)
97+
//为保持新 SDK 使用旧版插件问题,会使用新 SDK loadUrl + 2 后缀的方法
98+
mv.visitMethodInsn(INVOKESTATIC, SensorsAnalyticsHookConfig.SENSORS_ANALYTICS_API, name + "2", desc, false)
99+
return
55100
}
56101
}
102+
} catch (Throwable throwable) {
103+
Logger.warn("Can not auto handle webview, if you have any questions, please contact our technical services: classname:${className}, method:${methodNameDesc}, exception: ${throwable}")
57104
}
58105
super.visitMethodInsn(opcode, owner, name, desc, itf)
59106
}
60107

61108
/**
62-
* 判断是否是 WebView 的子类,避免 WebView 子类中调用 load* 方法,导致的递归调用
109+
* 判断方法的 owner 是否是 WebView 的子类
63110
*
64-
* @param className 当前被处理的类
65-
* @return true WebView 的子类,false 非 WebView 子类
111+
* @param owner
112+
* @return true 表示是 WebView 的子类,否则不是
66113
*/
67-
private boolean checkWebViewChild(String className) {
68-
if (superName == "com/tencent/smtt/sdk/WebViewClient") {
69-
return false
70-
}
71-
isAssignableWebView(className)
72-
}
73-
74114
private boolean isAssignableWebView(String owner) {
75115
try {
76116
if (OWNER_WHITE_SET.contains(owner)) {

0 commit comments

Comments
 (0)