From 6f171f4dd4316d66428207fcdec992007d0c9244 Mon Sep 17 00:00:00 2001 From: cpacm Date: Fri, 29 Jul 2022 18:07:46 +0800 Subject: [PATCH] Fix/lambda (#9) * fix lambda param error --- app/build.gradle | 3 +- .../android/plugin/LambdaSample.java | 18 +++++ .../android/plugin/AutoTrackerExtension.kt | 6 +- .../android/plugin/AutoTrackerPlugin.kt | 6 +- .../android/plugin/hook/HookInjectorClass.kt | 3 + .../android/plugin/utils/FilterUtils.kt | 25 +++++-- .../plugin/visitor/DesugarClassVisitor.kt | 43 ++++++++---- .../visitor/InjectTargetClassVisitor.kt | 15 +++-- .../descriptor/SensorAnalyticsInjector.kt | 65 +++++++++++++++++++ 9 files changed, 154 insertions(+), 30 deletions(-) create mode 100644 inject-descriptor/src/main/java/com/growingio/android/descriptor/SensorAnalyticsInjector.kt diff --git a/app/build.gradle b/app/build.gradle index 71af721..318fadc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -39,6 +39,7 @@ growingAutotracker { analyticsAdapter { firebaseAnalytics false googleAnalytics false + sensorAnalytics false } } @@ -50,7 +51,7 @@ dependencies { implementation 'com.google.android.material:material:1.6.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.3' - implementation 'com.growingio.android:autotracker-cdp:3.4.0-SNAPSHOT' + implementation 'com.growingio.android:autotracker-cdp:3.4.0' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.3' diff --git a/app/src/main/java/com/growingio/android/plugin/LambdaSample.java b/app/src/main/java/com/growingio/android/plugin/LambdaSample.java index 637a7eb..4b91f6b 100644 --- a/app/src/main/java/com/growingio/android/plugin/LambdaSample.java +++ b/app/src/main/java/com/growingio/android/plugin/LambdaSample.java @@ -96,5 +96,23 @@ public static boolean menuItemClick(MenuItem item) { } } + public void digitalClick(int i) { + Log.d("LambdaUtil", "digitalClick"); + } + + public void print7(MenuItem item, int position) { + float test2 = position * 1.0f; + item.getActionView().setOnClickListener(v -> { + digitalClick((int) test2); + }); + } + + public void print8(MenuItem item, int position) { + float test2 = position * 1.0f; + item.getActionView().setOnClickListener(v -> { + Log.d("LambdaUtil", test2+"cpacm"); + }); + } + } diff --git a/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/AutoTrackerExtension.kt b/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/AutoTrackerExtension.kt index 91a6701..110924d 100644 --- a/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/AutoTrackerExtension.kt +++ b/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/AutoTrackerExtension.kt @@ -46,8 +46,10 @@ open class AutoTrackerExtension (var instantiator: Instantiator) { //用于配置是否可以对第三方分析服务进行适配 open class AnalyticsAdapter ( - // 针对 FirebaseAnalytics + // 适配 FirebaseAnalytics var firebaseAnalytics: Boolean = false, - // 针对 GoogleAnalytics + // 适配 GoogleAnalytics var googleAnalytics: Boolean = false, + // 适配 sensorAnalytics + var sensorAnalytics: Boolean = false ) \ No newline at end of file diff --git a/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/AutoTrackerPlugin.kt b/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/AutoTrackerPlugin.kt index d2ec6bb..283de45 100644 --- a/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/AutoTrackerPlugin.kt +++ b/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/AutoTrackerPlugin.kt @@ -52,11 +52,11 @@ abstract class AutoTrackerPlugin : Plugin { var inAndroidProject = false - val autoTrackerExtension = project.extensions.create("growingAutotracker", AutoTrackerExtension::class.java, instantiator) + val autoTrackerExtension = + project.extensions.create("growingAutotracker", AutoTrackerExtension::class.java, instantiator) project.plugins.withType(AndroidBasePlugin::class.java) { inAndroidProject = true - if (SimpleAGPVersion.ANDROID_GRADLE_PLUGIN_VERSION < SimpleAGPVersion(4, 2)) { // Configures bytecode transform using older APIs pre AGP 4.2 configureBytecodeTransform(project, autoTrackerExtension) @@ -72,7 +72,7 @@ abstract class AutoTrackerPlugin : Plugin { "The GrowingIO AutoTracker Gradle plugin can only be applied to an Android project" } LOG_ENABLE = autoTrackerExtension.logEnabled - initInjectClass(autoTrackerExtension.injectClasses, autoTrackerExtension.analyticsAdapter) + initInjectClass(autoTrackerExtension) checkAutoTrackerDependency(it, autoTrackerExtension.skipDependencyCheck) } diff --git a/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/hook/HookInjectorClass.kt b/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/hook/HookInjectorClass.kt index d2f07b7..c95f14b 100644 --- a/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/hook/HookInjectorClass.kt +++ b/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/hook/HookInjectorClass.kt @@ -114,6 +114,9 @@ public object HookInjectorClass { TARGET_HOOK_CLASSES.add(HookData("com/google/android/gms/analytics/Tracker","set","(Ljava/lang/String;Ljava/lang/String;)V","com/growingio/android/analytics/google/GoogleAnalyticsInjector","set","(Lcom/google/android/gms/analytics/Tracker;Ljava/lang/String;Ljava/lang/String;)V",true)) TARGET_HOOK_CLASSES.add(HookData("com/google/android/gms/analytics/Tracker","send","(Ljava/util/Map;)V","com/growingio/android/analytics/google/GoogleAnalyticsInjector","send","(Lcom/google/android/gms/analytics/Tracker;Ljava/util/Map;)V",true)) TARGET_HOOK_CLASSES.add(HookData("com/google/android/gms/analytics/Tracker","setClientId","(Ljava/lang/String;)V","com/growingio/android/analytics/google/GoogleAnalyticsInjector","setClientId","(Lcom/google/android/gms/analytics/Tracker;Ljava/lang/String;)V",true)) + TARGET_HOOK_CLASSES.add(HookData("com/sensorsdata/analytics/android/sdk/SensorsDataAPI","disableSDK","()V","com/growingio/android/analytics/sensor/SensorAnalyticsInjector","disableSDK","()V",false)) + TARGET_HOOK_CLASSES.add(HookData("com/sensorsdata/analytics/android/sdk/SensorsDataAPI","enableSDK","()V","com/growingio/android/analytics/sensor/SensorAnalyticsInjector","enableSDK","()V",false)) + TARGET_HOOK_CLASSES.add(HookData("com/sensorsdata/analytics/android/sdk/SensorsDataAPI","profileSet","(Lorg/json/JSONObject;)V","com/growingio/android/analytics/sensor/SensorAnalyticsInjector","profileSet","(Lorg/json/JSONObject;)V",false)) return TARGET_HOOK_CLASSES } diff --git a/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/utils/FilterUtils.kt b/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/utils/FilterUtils.kt index baee802..68548eb 100644 --- a/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/utils/FilterUtils.kt +++ b/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/utils/FilterUtils.kt @@ -16,7 +16,7 @@ package com.growingio.android.plugin.utils -import com.growingio.android.plugin.AnalyticsAdapter +import com.growingio.android.plugin.AutoTrackerExtension /** *

@@ -30,16 +30,23 @@ internal fun shouldClassModified( if (isAndroidGenerated(className)) { return false } + + includePackages.forEach { + if (className.startsWith(it)) { + return true + } + } excludePackages.forEach { if (className.startsWith(it)) { return false } } - includePackages.forEach { + INCLUDED_PACKAGES.forEach { if (className.startsWith(it)) { return true } } + EXCLUDED_PACKAGES.forEach { if (className.startsWith(it)) { return false @@ -48,6 +55,8 @@ internal fun shouldClassModified( return true } +val INCLUDED_PACKAGES = arrayListOf() + val EXCLUDED_PACKAGES = arrayListOf( "com.growingio.android", "com.growingio.giokit", @@ -65,6 +74,7 @@ val EXCLUDED_PACKAGES = arrayListOf( //"android.support", //"org.jetbrains.kotlin", "android.arch", + "androidx.lifecycle.ReportFragment", //"com.google.android", //THIRD @@ -101,17 +111,22 @@ val DEFAULT_INJECT_CLASS = arrayListOf( "com.growingio.android.sdk.autotrack.inject.ViewClickInjector", ) -fun initInjectClass(injectClasses: Array?, adapter: AnalyticsAdapter?) { - injectClasses?.let { +fun initInjectClass(extension: AutoTrackerExtension) { + extension.injectClasses?.let { DEFAULT_INJECT_CLASS.addAll(it) } - adapter?.apply { + + extension.analyticsAdapter?.apply { if (firebaseAnalytics) { DEFAULT_INJECT_CLASS.add("com.growingio.android.analytics.firebase.FirebaseAnalyticsInjector") } if (googleAnalytics) { DEFAULT_INJECT_CLASS.add("com.growingio.android.analytics.google.GoogleAnalyticsInjector") } + if (sensorAnalytics) { + INCLUDED_PACKAGES.add("com.sensorsdata.analytics.android.sdk.SensorsDataAPI") + DEFAULT_INJECT_CLASS.add("com.growingio.android.analytics.sensor.SensorAnalyticsInjector") + } } } diff --git a/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/visitor/DesugarClassVisitor.kt b/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/visitor/DesugarClassVisitor.kt index 34b2c31..ef37374 100644 --- a/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/visitor/DesugarClassVisitor.kt +++ b/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/visitor/DesugarClassVisitor.kt @@ -84,13 +84,18 @@ internal class DesugarClassVisitor( // 插入hook before for (injectMethod in methodBlock.targetMethod.injectMethods) { if (!injectMethod.isAfter && classIncluded(injectMethod.className)) { - adapter.visitInsn(Opcodes.ACONST_NULL) - if (isStaticOrigin) { - adapter.loadArgs() - } else { - if (arguments.size > 1) { - adapter.loadArgs(1, arguments.size - 1) + val injectArgs = Type.getArgumentTypes(injectMethod.methodDesc) + injectArgs.forEach { + val argType = it.className + for (originType in arguments.reversed()) { + if (originType.className == argType) { + adapter.loadArg(arguments.lastIndexOf(originType)) + info("[GenerateMethod]${injectMethod.methodDesc}#${argType}<==>${originType.className}") + return@forEach + } } + info("[GenerateMethod]${injectMethod.methodDesc}#loadArg(null)") + adapter.visitInsn(Opcodes.ACONST_NULL) } adapter.invokeStatic( Type.getObjectType(injectMethod.className), @@ -112,13 +117,18 @@ internal class DesugarClassVisitor( // 插入hook after for (injectMethod in methodBlock.targetMethod.injectMethods) { if (injectMethod.isAfter && classIncluded(injectMethod.className)) { - adapter.visitInsn(Opcodes.ACONST_NULL) - if (isStaticOrigin) { - adapter.loadArgs() - } else { - if (arguments.size > 1) { - adapter.loadArgs(1, arguments.size - 1) + val injectArgs = Type.getArgumentTypes(injectMethod.methodDesc) + injectArgs.forEach { + val argType = it.className + for (originType in arguments.reversed()) { + if (originType.className == argType) { + adapter.loadArg(arguments.lastIndexOf(originType)) + info("[GenerateMethod]${injectMethod.methodDesc}#${argType}<==>${originType.className}") + return@forEach + } } + info("[GenerateMethod]${injectMethod.methodDesc}#loadArg(null)") + adapter.visitInsn(Opcodes.ACONST_NULL) } adapter.invokeStatic( Type.getObjectType(injectMethod.className), Method(injectMethod.methodName, injectMethod.methodDesc) @@ -180,6 +190,7 @@ internal class DesugarClassVisitor( super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethodHandle, *bootstrapMethodArguments) return } + if(bootstrapMethodArguments.isEmpty()) return //info("[visitInvokeDynamicInsn]${className}-${name}==>${(bootstrapMethodArguments[1] as Handle).name}") val handle = bootstrapMethodArguments[1] as Handle if (name == handle.name) { @@ -222,7 +233,13 @@ internal class DesugarClassVisitor( } val access = Opcodes.ACC_PRIVATE + Opcodes.ACC_STATIC + Opcodes.ACC_SYNTHETIC val methodBlock = - GenerateMethodBlock("lambda\$GIO\$" + generateMethodIndex, methodDesc, targetMethod, handle, access) + GenerateMethodBlock( + "${handle.name ?: "lambda"}\$GIO" + generateMethodIndex, + methodDesc, + targetMethod, + handle, + access + ) generateMethodBlocks.put(key, methodBlock) generateMethodIndex++ diff --git a/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/visitor/InjectTargetClassVisitor.kt b/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/visitor/InjectTargetClassVisitor.kt index d3c7fbe..405774b 100644 --- a/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/visitor/InjectTargetClassVisitor.kt +++ b/autotracker-gradle-plugin/src/main/kotlin/com/growingio/android/plugin/visitor/InjectTargetClassVisitor.kt @@ -118,7 +118,7 @@ internal class InjectTargetClassVisitor( continue } if (injectMethod.isAfter == isAfter) { - when(visitCode(isAfter, injectMethod.methodDesc, opcode)) { + when (visitCode(isAfter, injectMethod.methodDesc, opcode)) { 1 -> loadThis() 2 -> visitInsn(Opcodes.DUP) 3 -> { @@ -156,17 +156,20 @@ internal class InjectTargetClassVisitor( * 3 -> visitInsn(Opcodes.DUP); loadThis() * -1 -> 异常指令 */ - private fun visitCode(isAfter: Boolean, injectDescriptor: String, opcode: Int) : Int { + private fun visitCode(isAfter: Boolean, injectDescriptor: String, opcode: Int): Int { val isStatic = (methodAccess and Opcodes.ACC_STATIC) != 0 val hasReturnOpcode = opcode >= Opcodes.IRETURN && opcode <= Opcodes.ARETURN + val injectArgs = Type.getArgumentTypes(injectDescriptor) + if (injectArgs.isEmpty()) return 0 + val targetArgs = Type.getArgumentTypes(methodDesc) + if (!isAfter) { - return if (isStatic) 0 else 1 + // 方法注入在前面时,只允许注入方法中比原方法(static除外)多一个 + return if (isStatic || injectArgs.size == targetArgs.size) 0 else if (injectArgs.size - targetArgs.size == 1) 1 else -1 } - val targetArgs = Type.getArgumentTypes(methodDesc) - val injectArgs = Type.getArgumentTypes(injectDescriptor) - when(injectArgs.size - targetArgs.size) { + when (injectArgs.size - targetArgs.size) { 0 -> return 0 1 -> { if (!isStatic) { diff --git a/inject-descriptor/src/main/java/com/growingio/android/descriptor/SensorAnalyticsInjector.kt b/inject-descriptor/src/main/java/com/growingio/android/descriptor/SensorAnalyticsInjector.kt new file mode 100644 index 0000000..f8ffc35 --- /dev/null +++ b/inject-descriptor/src/main/java/com/growingio/android/descriptor/SensorAnalyticsInjector.kt @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022 Beijing Yishu Technology Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.growingio.android.descriptor + +import com.growingio.inject.annotation.Belong +import com.growingio.inject.annotation.Inject + +/** + *

+ * + * @author cpacm 2022/5/10 + */ +@Belong(className = "com.growingio.android.analytics.sensor.SensorAnalyticsInjector") +interface SensorAnalyticsInjector { + + @Inject( + targetClazz = "com/sensorsdata/analytics/android/sdk/SensorsDataAPI", + targetMethod = "disableSDK", + targetMethodDesc = "()V", + injectMethod = "disableSDK", + injectMethodDesc = "()V", + isAfter = false, + type = 0 + ) + fun disableSDK() + + @Inject( + targetClazz = "com/sensorsdata/analytics/android/sdk/SensorsDataAPI", + targetMethod = "enableSDK", + targetMethodDesc = "()V", + injectMethod = "enableSDK", + injectMethodDesc = "()V", + isAfter = false, + type = 0 + ) + fun enableSDK() + + + @Inject( + targetClazz = "com/sensorsdata/analytics/android/sdk/SensorsDataAPI", + targetMethod = "profileSet", + targetMethodDesc = "(Lorg/json/JSONObject;)V", + injectMethod = "profileSet", + injectMethodDesc = "(Lorg/json/JSONObject;)V", + isAfter = false, + type = 0 + ) + fun profileSet() + + +} \ No newline at end of file