diff --git a/build.gradle b/build.gradle
index a3a424da..a1f50a55 100644
--- a/build.gradle
+++ b/build.gradle
@@ -11,8 +11,8 @@ buildscript {
]
releaseConfiguration = [
- releaseVersion : "3.3.6",
- releaseVersionCode: 30306,
+ releaseVersion : "3.4.0",
+ releaseVersionCode: 30400,
]
versions = [
@@ -36,6 +36,7 @@ buildscript {
'androidx' : [
'appcompat' : 'androidx.appcompat:appcompat:1.3.1',
+ 'material' : 'com.google.android.material:material:1.6.0',
'fragment' : 'androidx.fragment:fragment:1.3.1',
'recyclerview' : 'androidx.recyclerview:recyclerview:1.2.1',
"swiperefreshlayout": "androidx.swiperefreshlayout:swiperefreshlayout:1.1.0",
@@ -52,6 +53,8 @@ buildscript {
'annotation' : "com.growingio.android:annotation:$releaseConfiguration.releaseVersion",
'compiler' : "com.growingio.android:compiler:$releaseConfiguration.releaseVersion",
+ 'analytics-fa' : "com.growingio.android:analytics-fa:$releaseConfiguration.releaseVersion",
+ 'analytics-ga' : "com.growingio.android:analytics-ga:$releaseConfiguration.releaseVersion",
'hybrid' : "com.growingio.android:hybrid:$releaseConfiguration.releaseVersion",
'okhttp3' : "com.growingio.android:okhttp3:$releaseConfiguration.releaseVersion",
'database' : "com.growingio.android:database:$releaseConfiguration.releaseVersion",
@@ -123,7 +126,7 @@ buildscript {
'asm_tree' : 'org.ow2.asm:asm-tree:9.1',
],
]
- kotlin_version = '1.4.32'
+ kotlin_version = '1.6.10'
}
repositories {
diff --git a/config/checkstyle/checkstyle.sh b/config/checkstyle/checkstyle.sh
index 2c58036c..4c4817e7 100755
--- a/config/checkstyle/checkstyle.sh
+++ b/config/checkstyle/checkstyle.sh
@@ -1,6 +1,5 @@
-./gradlew :growingio-autotracker-gradle-plugin:checkstyle \
-&& ./gradlew :growingio-annotation:checkstyle \
+./gradlew :growingio-annotation:checkstyle \
&& ./gradlew :growingio-annotation:compiler:checkstyle \
&& ./gradlew :growingio-tracker-core:checkstyle \
&& ./gradlew :growingio-autotracker-core:checkstyle \
@@ -17,6 +16,8 @@
&& ./gradlew :growingio-tools:crash:checkstyle \
&& ./gradlew :growingio-tools:oaid:checkstyle \
&& ./gradlew :growingio-tools:snappy:checkstyle \
+&& ./gradlew :growingio-adapter:analytics-fa:checkstyle \
+&& ./gradlew :growingio-adapter:analytics-ga:checkstyle \
&& ./gradlew :gio-sdk:tracker:checkstyle \
&& ./gradlew :gio-sdk:tracker-cdp:checkstyle \
&& ./gradlew :gio-sdk:autotracker:checkstyle \
diff --git a/demos/demo/build.gradle b/demos/demo/build.gradle
index cc875384..7562d642 100644
--- a/demos/demo/build.gradle
+++ b/demos/demo/build.gradle
@@ -1,11 +1,7 @@
apply plugin: 'com.android.application'
apply plugin: 'jacoco'
-def withAutotrack = true
-
-if (withAutotrack) {
- apply plugin: 'com.growingio.android.autotracker'
-}
+apply plugin: 'com.growingio.android.autotracker'
buildscript {
repositories {
@@ -16,7 +12,7 @@ buildscript {
}
dependencies {
classpath "com.growingio.android:autotracker-gradle-plugin:${releaseConfiguration.releaseVersion}"
- //classpath "com.growingio.android:autotracker-gradle-plugin:3.3.1"
+ //classpath "com.growingio.android:autotracker-gradle-plugin:3.4.0"
}
}
@@ -27,8 +23,6 @@ android {
minSdkVersion 26
targetSdkVersion buildConfiguration.targetSdkVersion
- buildConfigField "boolean", "withAutotrack", "$withAutotrack"
-
testInstrumentationRunner "com.growingio.autotest.TrackAndroidJUnitRunner"
testInstrumentationRunnerArguments listener: "com.growingio.autotest.TrackTestRunListener"
@@ -76,9 +70,10 @@ android {
}
growingAutotracker {
- development true
logEnabled true
-// excludePackages "com.gio.test.three.autotrack.fragments", "com.example"
+ skipDependencyCheck true
+ //includePackages "com.growingio.android.plugin"
+ //excludePackages "com.cpacm"
}
dependencies {
@@ -110,7 +105,7 @@ dependencies {
compileOnly libraries.androidx.appcompat
// leakcanary 避免发版前未使用Profiler进行内存泄漏检测
- debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
+ debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
}
apply from: "${rootProject.projectDir}/gradle/jacoco.gradle"
diff --git a/gradle/jacoco.gradle b/gradle/jacoco.gradle
index 49788c53..099843fd 100644
--- a/gradle/jacoco.gradle
+++ b/gradle/jacoco.gradle
@@ -11,7 +11,6 @@ def coverageSourceDirs = [
"$rootDir/growingio-annotation/src/main/java",
"$rootDir/growingio-tracker-core/src/main/java",
"$rootDir/growingio-autotracker-core/src/main/java",
- "$rootDir/growingio-autotracker-gradle-plugin/src/main/java",
"$rootDir/growingio-data/encoder/src/main/java",
"$rootDir/growingio-data/json/src/main/java",
"$rootDir/growingio-data/protobuf/src/main/java",
@@ -20,13 +19,14 @@ def coverageSourceDirs = [
"$rootDir/growingio-network/okhttp3/src/main/java",
"$rootDir/growingio-network/volley/src/main/java",
"$rootDir/growingio-network/urlconnection/src/main/java",
+ "$rootDir/growingio-adapter/analytics-fa/src/main/java",
+ "$rootDir/growingio-adapter/analytics-ga/src/main/java",
"$rootDir/growingio-tools/crash/src/main/java",
"$rootDir/growingio-tools/snappy/src/main/java",
"$rootDir/growingio-tools/oaid/src/main/java",
"$rootDir/growingio-webservice/circler/src/main/java",
"$rootDir/growingio-webservice/debugger/src/main/java",
"$rootDir/growingio-annotation/compiler/src/main/java",
- "$rootDir/inject-annotation/compiler/src/main/java",
// "$rootDir/gio-sdk/tracker/src/main/java",
// "$rootDir/gio-sdk/tracker-cdp/src/main/java",
// "$rootDir/gio-sdk/autotracker/src/main/java",
@@ -38,7 +38,6 @@ def coverageClassDirs = [
"$rootDir/growingio-annotation/build/intermediates/javac/debug/classes",
"$rootDir/growingio-tracker-core/build/intermediates/javac/debug/classes",
"$rootDir/growingio-autotracker-core/build/intermediates/javac/debug/classes",
- "$rootDir/growingio-autotracker-gradle-plugin/build/intermediates/javac/debug/classes",
"$rootDir/growingio-data/encoder/build/intermediates/javac/debug/classes",
"$rootDir/growingio-data/json/build/intermediates/javac/debug/classes",
"$rootDir/growingio-data/protobuf/build/intermediates/javac/debug/classes",
@@ -49,11 +48,12 @@ def coverageClassDirs = [
"$rootDir/growingio-tools/crash/build/intermediates/javac/debug/classes",
"$rootDir/growingio-tools/snappy/build/intermediates/javac/debug/classes",
"$rootDir/growingio-tools/oaid/build/intermediates/javac/debug/classes",
+ "$rootDir/growingio-adapter/analytics-fa/build/intermediates/javac/debug/classes",
+ "$rootDir/growingio-adapter/analytics-ga/build/intermediates/javac/debug/classes",
"$rootDir/growingio-webservice/circler/build/intermediates/javac/debug/classes",
"$rootDir/growingio-webservice/debugger/build/intermediates/javac/debug/classes",
"$rootDir/growingio-hybrid/build/intermediates/javac/debug/classes",
"$rootDir/growingio-annotation/compiler/build/classes/java/main",
- "$rootDir/inject-annotation/compiler/build/classes/java/main",
// "$rootDir/gio-sdk/tracker/build/intermediates/javac/debug/classes",
// "$rootDir/gio-sdk/tracker-cdp/build/intermediates/javac/debug/classes",
// "$rootDir/gio-sdk/autotracker/build/intermediates/javac/debug/classes",
diff --git a/gradle/publishAllToMavenLocal.sh b/gradle/publishAllToMavenLocal.sh
index e1bfc3c5..124868f8 100755
--- a/gradle/publishAllToMavenLocal.sh
+++ b/gradle/publishAllToMavenLocal.sh
@@ -18,10 +18,11 @@ export IS_EXCLUDE_DEMOS=true
&& ./gradlew :growingio-webservice:circler:publishMavenAgentPublicationToMavenLocal \
&& ./gradlew :growingio-tools:crash:publishMavenAgentPublicationToMavenLocal \
&& ./gradlew :growingio-tools:oaid:publishMavenAgentPublicationToMavenLocal \
+&& ./gradlew :growingio-adapter:analytics-fa:publishMavenAgentPublicationToMavenLocal \
+&& ./gradlew :growingio-adapter:analytics-ga:publishMavenAgentPublicationToMavenLocal \
&& ./gradlew :gio-sdk:tracker:publishMavenAgentPublicationToMavenLocal \
&& ./gradlew :gio-sdk:tracker-cdp:publishMavenAgentPublicationToMavenLocal \
&& ./gradlew :gio-sdk:autotracker:publishMavenAgentPublicationToMavenLocal \
&& ./gradlew :gio-sdk:autotracker-cdp:publishMavenAgentPublicationToMavenLocal \
-&& ./gradlew :growingio-autotracker-gradle-plugin:publishMavenAgentPublicationToMavenLocal \
&& ./gradlew clean
export IS_EXCLUDE_DEMOS=false
\ No newline at end of file
diff --git a/gradle/publishAutotrackerPluginToMavenLocal.sh b/gradle/publishAutotrackerPluginToMavenLocal.sh
deleted file mode 100755
index 5a0a4ae9..00000000
--- a/gradle/publishAutotrackerPluginToMavenLocal.sh
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/bash
-
-echo "准备开始打包 autotracker-gradle-plugin ..."
-export IS_EXCLUDE_DEMOS=true
-./gradlew clean \
-&& ./gradlew :growingio-autotracker-gradle-plugin:publishMavenAgentPublicationToMavenLocal \
-&& ./gradlew clean \
-&& export IS_EXCLUDE_DEMOS=false
\ No newline at end of file
diff --git a/inject-annotation/.gitignore b/growingio-adapter/analytics-fa/.gitignore
similarity index 100%
rename from inject-annotation/.gitignore
rename to growingio-adapter/analytics-fa/.gitignore
diff --git a/growingio-adapter/analytics-fa/build.gradle b/growingio-adapter/analytics-fa/build.gradle
new file mode 100644
index 00000000..60b98491
--- /dev/null
+++ b/growingio-adapter/analytics-fa/build.gradle
@@ -0,0 +1,59 @@
+plugins {
+ id 'com.android.library'
+}
+
+android {
+ compileSdkVersion buildConfiguration.compileVersion
+ defaultConfig {
+ minSdkVersion 19
+ targetSdkVersion buildConfiguration.targetSdkVersion
+ versionName releaseConfiguration.releaseVersion
+ versionCode releaseConfiguration.releaseVersionCode
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility buildConfiguration.sourceCompatibility
+ targetCompatibility buildConfiguration.targetCompatibility
+ }
+
+ testOptions {
+ unitTests.all {
+ jacoco {
+ includeNoLocationClasses = true
+ excludes = ['jdk.internal.*']
+ }
+ }
+ unitTests {
+ returnDefaultValues = true
+ includeAndroidResources = true
+ }
+ }
+}
+
+
+dependencies {
+ testImplementation libraries.test.junit
+ testImplementation libraries.test.truth
+ testImplementation libraries.test.androidx_core
+ testImplementation libraries.test.robolectric
+
+ testImplementation platform('com.google.firebase:firebase-bom:30.0.1')
+ testImplementation 'com.google.firebase:firebase-analytics-ktx'
+
+ implementation project(':growingio-tracker-core')
+
+ implementation project(":growingio-annotation")
+ annotationProcessor project(":growingio-annotation:compiler")
+
+ compileOnly platform('com.google.firebase:firebase-bom:30.0.1')
+ compileOnly 'com.google.firebase:firebase-analytics-ktx'
+}
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
+apply from: "${rootProject.projectDir}/gradle/jacocoModule.gradle"
\ No newline at end of file
diff --git a/growingio-adapter/analytics-fa/consumer-rules.pro b/growingio-adapter/analytics-fa/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/growingio-adapter/analytics-fa/gradle.properties b/growingio-adapter/analytics-fa/gradle.properties
new file mode 100644
index 00000000..ca879f1f
--- /dev/null
+++ b/growingio-adapter/analytics-fa/gradle.properties
@@ -0,0 +1,4 @@
+POM_NAME=analytics-fa
+POM_ARTIFACT_ID=analytics-fa
+POM_PACKAGING=aar
+POM_DESCRIPTION=Adapter Google Analytics data to Growingio's sdk.
\ No newline at end of file
diff --git a/growingio-autotracker-gradle-plugin/proguard-rules.pro b/growingio-adapter/analytics-fa/proguard-rules.pro
similarity index 94%
rename from growingio-autotracker-gradle-plugin/proguard-rules.pro
rename to growingio-adapter/analytics-fa/proguard-rules.pro
index f1b42451..481bb434 100644
--- a/growingio-autotracker-gradle-plugin/proguard-rules.pro
+++ b/growingio-adapter/analytics-fa/proguard-rules.pro
@@ -18,4 +18,4 @@
# If you keep the line number information, uncomment this to
# hide the original source file name.
-#-renamesourcefileattribute SourceFile
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/growingio-adapter/analytics-fa/src/main/AndroidManifest.xml b/growingio-adapter/analytics-fa/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..9351c9b6
--- /dev/null
+++ b/growingio-adapter/analytics-fa/src/main/AndroidManifest.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/growingio-adapter/analytics-fa/src/main/java/com/growingio/android/analytics/firebase/FirebaseAnalyticsAdapter.java b/growingio-adapter/analytics-fa/src/main/java/com/growingio/android/analytics/firebase/FirebaseAnalyticsAdapter.java
new file mode 100644
index 00000000..62ecc212
--- /dev/null
+++ b/growingio-adapter/analytics-fa/src/main/java/com/growingio/android/analytics/firebase/FirebaseAnalyticsAdapter.java
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2020 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.analytics.firebase;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.Size;
+import android.util.SizeF;
+import android.util.SparseArray;
+
+import androidx.annotation.NonNull;
+
+import com.google.android.gms.measurement.api.AppMeasurementSdk;
+import com.google.firebase.analytics.FirebaseAnalytics;
+import com.growingio.android.sdk.TrackerContext;
+import com.growingio.android.sdk.track.TrackMainThread;
+import com.growingio.android.sdk.track.events.TrackEventGenerator;
+import com.growingio.android.sdk.track.log.Logger;
+import com.growingio.android.sdk.track.providers.ConfigurationProvider;
+import com.growingio.android.sdk.track.providers.SessionProvider;
+import com.growingio.android.sdk.track.providers.UserInfoProvider;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ *
+ * @author cpacm 2022/5/19
+ */
+class FirebaseAnalyticsAdapter {
+
+ private static final String TAG = "GrowingAdapter";
+ private static final String DUEL_VECTOR_LINK = "_";
+ private static volatile FirebaseAnalyticsAdapter sGaAdapter;
+ private FirebaseAnalytics firebaseAnalytics;
+ private String appInstanceId;
+
+ public static FirebaseAnalyticsAdapter get() {
+ if (sGaAdapter == null) {
+ return new FirebaseAnalyticsAdapter();
+ }
+ synchronized (FirebaseAnalyticsAdapter.class) {
+ if (sGaAdapter != null) {
+ return sGaAdapter;
+ }
+ return new FirebaseAnalyticsAdapter();
+ }
+ }
+
+ public static void init(Context context) {
+ if (sGaAdapter == null) {
+ sGaAdapter = new FirebaseAnalyticsAdapter(context);
+ }
+ }
+
+ private FirebaseAnalyticsAdapter() {
+ //initFAdapter(TrackerContext.get());
+ //registerAppMeasureEvent(TrackerContext.get());
+ }
+
+ private FirebaseAnalyticsAdapter(Context context) {
+ initFAdapter(context);
+ registerAppMeasureEvent(context);
+ }
+
+ @SuppressLint("MissingPermission")
+ private void initFAdapter(Context context) {
+ if (firebaseAnalytics == null) {
+ firebaseAnalytics = FirebaseAnalytics.getInstance(context);
+ }
+ firebaseAnalytics.getAppInstanceId().addOnCompleteListener(task -> {
+ appInstanceId = task.getResult();
+ Map attr = new HashMap<>();
+ attr.put("app_instance_id", appInstanceId);
+ TrackEventGenerator.generateLoginUserAttributesEvent(new HashMap<>(attr));
+ });
+ }
+
+ @SuppressLint("MissingPermission")
+ private void registerAppMeasureEvent(Context context) {
+ AppMeasurementSdk.getInstance(context).registerOnMeasurementEventListener(new AppMeasurementSdk.OnEventListener() {
+ @Override
+ public void onEvent(@NonNull String type, @NonNull String eventName, @NonNull Bundle bundle, long timeMill) {
+ Logger.d("FA Event", type + ":" + eventName + ":" + bundle + ":" + timeMill);
+ if ("auto".equals(type)) {
+ // exclude auto event,like:_ab(应用进入后台),_e(设置页面名称) .etc.
+ return;
+ }
+ logEvent(eventName, bundle);
+ }
+ });
+ }
+
+ void logEvent(String name, Bundle bundle) {
+ if (!checkAnalyticsValid()) return;
+ if (TextUtils.isEmpty(name)) {
+ Logger.e(TAG, "trackCustomEvent: eventName is NULL");
+ return;
+ }
+ TrackEventGenerator.generateCustomEvent(name, parseBundle(bundle));
+ }
+
+ @SuppressLint("MissingPermission")
+ void setAnalyticsCollectionEnabled(boolean enabled) {
+ try {
+ if (!checkAnalyticsValid()) return;
+ TrackMainThread.trackMain().postActionToTrackMain(() -> {
+ if (enabled == ConfigurationProvider.core().isDataCollectionEnabled()) {
+ Logger.e(TAG, "当前数据采集开关 = " + enabled + ", 请勿重复操作");
+ } else {
+ ConfigurationProvider.core().setDataCollectionEnabled(enabled);
+ if (enabled) {
+ SessionProvider.get().generateVisit();
+ initFAdapter(TrackerContext.get());
+ }
+ }
+ });
+ } catch (Exception ignored) {
+ }
+ }
+
+ void setUserId(String userId) {
+ if (!checkAnalyticsValid()) return;
+ TrackMainThread.trackMain().postActionToTrackMain(() -> UserInfoProvider.get().setLoginUserId(userId));
+ }
+
+ void setUserProperty(String name, String value) {
+ if (!checkAnalyticsValid()) return;
+ Map attr = new HashMap<>();
+ if (value == null) value = "";
+ attr.put(name, value);
+ TrackEventGenerator.generateLoginUserAttributesEvent(new HashMap<>(attr));
+ }
+
+ /**
+ * 将 bundle 转化为扁平化Map
+ */
+ Map parseBundle(Bundle bundle) {
+ return duelVectorFoil("", bundle);
+ }
+
+ private Map duelVectorFoil(String prefix, Bundle bundle) {
+ Map attr = new HashMap<>();
+ for (String key : bundle.keySet()) {
+ if (key.startsWith("_")) continue; // exclude Firebase generate params
+ Object value = bundle.get(key);
+ String realKey = prefix + key;
+ if (value instanceof Bundle) {
+ Map childMap = duelVectorFoil(realKey + DUEL_VECTOR_LINK, (Bundle) value);
+ attr.putAll(childMap);
+ } else if (value.getClass().isArray()) {
+ if (value instanceof boolean[]) {
+ int index = 0;
+ for (Object child : (boolean[]) value) {
+ attr.put(realKey + DUEL_VECTOR_LINK + index, child.toString());
+ index += 1;
+ }
+ } else if (value instanceof byte[]) {
+ int index = 0;
+ for (Object child : (byte[]) value) {
+ attr.put(realKey + DUEL_VECTOR_LINK + index, child.toString());
+ index += 1;
+ }
+ } else if (value instanceof float[]) {
+ int index = 0;
+ for (Object child : (float[]) value) {
+ attr.put(realKey + DUEL_VECTOR_LINK + index, child.toString());
+ index += 1;
+ }
+ } else if (value instanceof double[]) {
+ int index = 0;
+ for (Object child : (double[]) value) {
+ attr.put(realKey + DUEL_VECTOR_LINK + index, child.toString());
+ index += 1;
+ }
+ } else if (value instanceof int[]) {
+ int index = 0;
+ for (Object child : (int[]) value) {
+ attr.put(realKey + DUEL_VECTOR_LINK + index, child.toString());
+ index += 1;
+ }
+ } else if (value instanceof char[]) {
+ int index = 0;
+ for (Object child : (char[]) value) {
+ attr.put(realKey + DUEL_VECTOR_LINK + index, child.toString());
+ index += 1;
+ }
+ } else if (value instanceof short[]) {
+ int index = 0;
+ for (Object child : (short[]) value) {
+ attr.put(realKey + DUEL_VECTOR_LINK + index, child.toString());
+ index += 1;
+ }
+ } else {
+ int index = 0;
+ for (Object child : (Object[]) value) {
+ if (child instanceof Bundle) {
+ Map childMap = duelVectorFoil(realKey + DUEL_VECTOR_LINK + index + DUEL_VECTOR_LINK, (Bundle) child);
+ attr.putAll(childMap);
+ } else {
+ attr.put(realKey + DUEL_VECTOR_LINK + index, child.toString());
+ }
+ index += 1;
+ }
+ }
+ } else if (value instanceof ArrayList) {
+ int index = 0;
+ for (Object child : (ArrayList) value) {
+ if (child instanceof Bundle) {
+ Map childMap = duelVectorFoil(realKey + DUEL_VECTOR_LINK + index + DUEL_VECTOR_LINK, (Bundle) child);
+ attr.putAll(childMap);
+ } else {
+ attr.put(realKey + DUEL_VECTOR_LINK + index, child.toString());
+ }
+ index += 1;
+ }
+ } else if (value instanceof SparseArray) {
+ SparseArray sa = (SparseArray) value;
+ for (int i = 0; i < sa.size(); i++) {
+ int index = sa.keyAt(i);
+ Object child = sa.get(index);
+ if (child instanceof Bundle) {
+ Map childMap = duelVectorFoil(realKey + DUEL_VECTOR_LINK + index + DUEL_VECTOR_LINK, (Bundle) child);
+ attr.putAll(childMap);
+ } else {
+ attr.put(realKey + DUEL_VECTOR_LINK + index, child.toString());
+ }
+ }
+ } else if (value instanceof Parcelable) {
+ attr.put(realKey, value.toString());
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ if (value instanceof Size) {
+ attr.put(realKey, value.toString());
+ } else if (value instanceof SizeF) {
+ attr.put(realKey, value.toString());
+ } else {
+ attr.put(realKey, value.toString());
+ }
+ } else {
+ attr.put(realKey, value.toString());
+ }
+ }
+ return attr;
+ }
+
+ boolean checkAnalyticsValid() {
+ if (firebaseAnalytics == null || TextUtils.isEmpty(appInstanceId)) return false;
+ return TrackerContext.initializedSuccessfully();
+ }
+
+// private boolean readManifestScreenTrackEnabled(Context context) {
+// try {
+// PackageManager packageManager = context.getPackageManager();
+// if (packageManager != null) {
+// ApplicationInfo applicationInfo =
+// packageManager.getApplicationInfo(
+// context.getPackageName(), PackageManager.GET_META_DATA);
+// if (applicationInfo != null
+// && applicationInfo.metaData != null
+// && applicationInfo.metaData.containsKey(DATA_SCREEN_TRACK_ENABLED)) {
+// return applicationInfo.metaData.getBoolean(DATA_SCREEN_TRACK_ENABLED);
+// }
+// }
+// } catch (PackageManager.NameNotFoundException e) {
+// // This shouldn't happen since it's this app's package, but fall through to default if so.
+// }
+// return true;
+// }
+//
+// public static final String DATA_SCREEN_TRACK_ENABLED = "google_analytics_automatic_screen_reporting_enabled";
+
+}
diff --git a/growingio-adapter/analytics-fa/src/main/java/com/growingio/android/analytics/firebase/FirebaseAnalyticsInjector.java b/growingio-adapter/analytics-fa/src/main/java/com/growingio/android/analytics/firebase/FirebaseAnalyticsInjector.java
new file mode 100644
index 00000000..fb73fed2
--- /dev/null
+++ b/growingio-adapter/analytics-fa/src/main/java/com/growingio/android/analytics/firebase/FirebaseAnalyticsInjector.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 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.analytics.firebase;
+
+import android.os.Bundle;
+
+/**
+ *
+ * Google Analytics message sender
+ *
+ * @author cpacm 2022/5/19
+ */
+public class FirebaseAnalyticsInjector {
+
+ private FirebaseAnalyticsInjector() {
+ }
+
+ public static void logEvent(String name, Bundle bundle) {
+ //FirebaseAnalyticsAdapter.get().logEvent(name, bundle);
+ }
+
+ public static void setDefaultEventParameters(Bundle bundle) {
+ //FirebaseAnalyticsAdapter.get().setDefaultEventParameters(bundle);
+ }
+
+ public static void setUserId(String userId) {
+ FirebaseAnalyticsAdapter.get().setUserId(userId);
+ }
+
+ public static void setUserProperty(String name, String value) {
+ FirebaseAnalyticsAdapter.get().setUserProperty(name, value);
+ }
+
+ public static void setAnalyticsCollectionEnabled(boolean enabled) {
+ FirebaseAnalyticsAdapter.get().setAnalyticsCollectionEnabled(enabled);
+ }
+}
diff --git a/growingio-autotracker-gradle-plugin/src/main/java/com/growingio/sdk/plugin/autotrack/compile/ErrorLog.java b/growingio-adapter/analytics-fa/src/main/java/com/growingio/android/analytics/firebase/FirebaseAnalyticsLibraryModule.java
similarity index 51%
rename from growingio-autotracker-gradle-plugin/src/main/java/com/growingio/sdk/plugin/autotrack/compile/ErrorLog.java
rename to growingio-adapter/analytics-fa/src/main/java/com/growingio/android/analytics/firebase/FirebaseAnalyticsLibraryModule.java
index 664979cc..78109990 100644
--- a/growingio-autotracker-gradle-plugin/src/main/java/com/growingio/sdk/plugin/autotrack/compile/ErrorLog.java
+++ b/growingio-adapter/analytics-fa/src/main/java/com/growingio/android/analytics/firebase/FirebaseAnalyticsLibraryModule.java
@@ -13,24 +13,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+package com.growingio.android.analytics.firebase;
-package com.growingio.sdk.plugin.autotrack.compile;
+import android.content.Context;
-public final class ErrorLog extends SystemLog {
-
- @Override
- public void info(String message) {
- }
-
- @Override
- public void debug(String message) {
- }
-
- @Override
- public void warning(String message) {
- }
+import com.growingio.android.sdk.LibraryGioModule;
+import com.growingio.android.sdk.track.modelloader.TrackerRegistry;
+import com.growingio.sdk.annotation.GIOLibraryModule;
+/**
+ *
+ *
+ * @author cpacm 2022/5/19
+ */
+@GIOLibraryModule
+public class FirebaseAnalyticsLibraryModule extends LibraryGioModule {
@Override
- public void warning(String message, Throwable cause) {
+ public void registerComponents(Context context, TrackerRegistry registry) {
+ //just init
+ FirebaseAnalyticsAdapter.init(context);
+ //registry.register(this.getClass(), Void.class, null);
}
}
diff --git a/growingio-adapter/analytics-fa/src/test/java/com/growingio/android/analytics/firebase/FirebaseAnalyticsTest.java b/growingio-adapter/analytics-fa/src/test/java/com/growingio/android/analytics/firebase/FirebaseAnalyticsTest.java
new file mode 100644
index 00000000..53ec99b0
--- /dev/null
+++ b/growingio-adapter/analytics-fa/src/test/java/com/growingio/android/analytics/firebase/FirebaseAnalyticsTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2020 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.analytics.firebase;
+
+import android.app.Application;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.util.Size;
+import android.util.SizeF;
+import android.util.SparseArray;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import com.growingio.android.sdk.CoreConfiguration;
+import com.growingio.android.sdk.TrackerContext;
+import com.growingio.android.sdk.track.providers.ConfigurationProvider;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.annotation.Config;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ *
+ * @author cpacm 2022/5/23
+ */
+@Config(manifest = Config.NONE, sdk = 30)
+@RunWith(RobolectricTestRunner.class)
+public class FirebaseAnalyticsTest {
+
+ Application application = ApplicationProvider.getApplicationContext();
+
+ @Before
+ public void setup() {
+ TrackerContext.init(application);
+ TrackerContext.initSuccess();
+ ConfigurationProvider.initWithConfig(new CoreConfiguration("test", "test"), new HashMap<>());
+ //FirebaseAnalyticsAdapter.init(application);
+ }
+
+ @Test
+ public void duelVectorFoilTest() {
+
+ Bundle bundle = new Bundle();
+ bundle.putString("s", "String");
+ bundle.putStringArray("s[]", new String[]{"s1", "s2"});
+ ArrayList arrayList = new ArrayList<>();
+ arrayList.add("name");
+ arrayList.add("cpacm");
+ bundle.putStringArrayList("slist", arrayList);
+
+ bundle.putInt("i", 1);
+ bundle.putIntArray("i[]", new int[]{1, 2, 3, 4});
+ ArrayList arrayList1 = new ArrayList<>();
+ arrayList1.add(1);
+ arrayList1.add(2);
+ bundle.putIntegerArrayList("ilist", arrayList1);
+
+ bundle.putChar("c", 'a');
+ bundle.putCharArray("c[]", "cpacm".toCharArray());
+ bundle.putCharSequence("cs", "CharSequence");
+ bundle.putCharSequenceArray("cs[]", new CharSequence[]{"s1", "s2"});
+ ArrayList arrayList2 = new ArrayList<>();
+ arrayList2.add("name");
+ arrayList2.add("cpacm");
+ bundle.putCharSequenceArrayList("cslist", arrayList2);
+
+ bundle.putByte("b", "cpacm".getBytes()[0]);
+ bundle.putByteArray("b[]", "cpacm".getBytes());
+ bundle.putFloat("f", 1.0f);
+ bundle.putFloatArray("f[]", new float[]{1.0f, 2.0f});
+ bundle.putDouble("d", 1d);
+ bundle.putDoubleArray("d[]", new double[]{1d, 2d});
+ bundle.putShort("st", Short.MIN_VALUE);
+ bundle.putShortArray("st[]", new short[]{Short.MIN_VALUE, Short.MAX_VALUE});
+ bundle.putBoolean("bool", false);
+ bundle.putBooleanArray("bool[]", new boolean[]{false, false, true});
+
+ bundle.putSize("size", new Size(100, 200));
+ bundle.putSizeF("sizeF", new SizeF(100f, 200f));
+
+ Bundle deepBundle = bundle.deepCopy();
+
+ bundle.putParcelable("p", deepBundle);
+ bundle.putParcelableArray("p[]", new Parcelable[]{deepBundle});
+ ArrayList arrayList3 = new ArrayList<>();
+ arrayList3.add(bundle.deepCopy());
+ bundle.putParcelableArrayList("plist", arrayList3);
+ SparseArray sa = new SparseArray<>();
+ sa.append(100, bundle.deepCopy());
+ bundle.putSparseParcelableArray("ps", sa);
+
+ bundle.putSerializable("serial", "cpacm");
+
+ bundle.putBundle("bundle", deepBundle);
+
+ FirebaseAnalyticsAdapter adapter = FirebaseAnalyticsAdapter.get();
+ Map attr = adapter.parseBundle(bundle);
+
+ Assert.assertEquals(attr.toString().length(), BUNDLE_RESULT.length());
+ Assert.assertEquals(attr.toString(), BUNDLE_RESULT);
+ }
+
+ private static final String BUNDLE_RESULT = "{ps_100_plist_0_i=1, ps_100_plist_0_f=1.0, ps_100_plist_0_p_cs[]_1=s2, ps_100_plist_0_d=1.0, ps_100_plist_0_p_cs[]_0=s1, ps_100_plist_0_c=a, ps_100_plist_0_b=99, bundle_ilist_1=2, ps_100_p[]_0_bool=false, ps_100_plist_0_p_bool=false, p[]_0_cslist_1=cpacm, p[]_0_cslist_0=name, bundle_ilist_0=1, ps_100_bool[]_2=true, ps_100_plist_0_p[]_0_c[]_4=m, ps_100_bool[]_1=false, ps_100_d[]_1=2.0, ps_100_plist_0_p[]_0_c[]_0=c, plist_0_slist_0=name, ps_100_plist_0_p[]_0_c[]_1=p, plist_0_slist_1=cpacm, ps_100_plist_0_p[]_0_c[]_2=a, ps_100_d[]_0=1.0, ps_100_plist_0_p[]_0_c[]_3=c, ps_100_bool[]_0=false, ps_100_p[]_0_sizeF=100.0x200.0, plist_0_p[]_0_ilist_0=1, plist_0_p[]_0_ilist_1=2, plist_0_p[]_0_cs=CharSequence, plist_0_bool=false, ps_100_bool=false, ps_100_cs[]_0=s1, size=100x200, ps_100_plist_0_s=String, ps_100_cs[]_1=s2, ps_100_plist_0_p[]_0_bool=false, ps_100_p_cslist_1=cpacm, ps_100_plist_0_p[]_0_ilist_0=1, ps_100_p_cslist_0=name, ps_100_plist_0_p[]_0_ilist_1=2, ps_100_plist_0_s[]_1=s2, ps_100_plist_0_s[]_0=s1, p_b=99, p_d=1.0, ps_100_p_c[]_3=c, p_c=a, ps_100_p_c[]_4=m, p_f=1.0, p_i=1, plist_0_ilist_0=1, plist_0_ilist_1=2, b=99, plist_0_d[]_0=1.0, c=a, d=1.0, p_s=String, f=1.0, i=1, ps_100_p_c[]_0=c, ps_100_p_c[]_1=p, ps_100_p_c[]_2=a, cs[]_1=s2, ps_100_plist_0_p_cslist_0=name, cs[]_0=s1, ps_100_plist_0_p_cslist_1=cpacm, plist_0_d[]_1=2.0, cs=CharSequence, s=String, b[]_4=109, b[]_3=99, b[]_2=97, b[]_1=112, b[]_0=99, plist_0_cs=CharSequence, plist_0_p_cs=CharSequence, ps_100_p[]_0_ilist_1=2, ps_100_plist_0_p[]_0_d[]_1=2.0, ps_100_p[]_0_ilist_0=1, ps_100_plist_0_p[]_0_d[]_0=1.0, plist_0_p[]_0_i=1, plist_0_p[]_0_f=1.0, plist_0_p[]_0_d=1.0, plist_0_p[]_0_b=99, plist_0_p[]_0_c=a, cslist_1=cpacm, p[]_0_i[]_3=4, p[]_0_i[]_2=3, p[]_0_i[]_1=2, p[]_0_i[]_0=1, ps_100_p[]_0_c=a, ps_100_p[]_0_b=99, p_c[]_0=c, ps_100_p[]_0_d=1.0, bundle_d[]_1=2.0, bundle_d[]_0=1.0, plist_0_p[]_0_bool=false, plist_0_p[]_0_s=String, p_c[]_1=p, p_c[]_2=a, p_c[]_3=c, p_c[]_4=m, ps_100_p[]_0_s=String, plist_0_p_b[]_1=112, plist_0_p_b[]_0=99, plist_0_p[]_0_bool[]_0=false, plist_0_p[]_0_bool[]_1=false, plist_0_p[]_0_bool[]_2=true, p_st=-32768, p[]_0_bool=false, ps_100_plist_0_p_cs=CharSequence, ps_100_p[]_0_f=1.0, plist_0_p_b[]_4=109, ps_100_p[]_0_i=1, plist_0_p_b[]_3=99, plist_0_p_b[]_2=97, ps_100_plist_0_d[]_1=2.0, ps_100_s[]_0=s1, plist_0_p[]_0_d[]_0=1.0, ps_100_s[]_1=s2, ps_100_plist_0_d[]_0=1.0, plist_0_p[]_0_d[]_1=2.0, ps_100_plist_0_cs=CharSequence, p[]_0_st[]_0=-32768, p[]_0_st[]_1=32767, plist_0_p_size=100x200, ps_100_p_b[]_4=109, bundle_s[]_0=s1, bundle_s[]_1=s2, plist_0_p[]_0_sizeF=100.0x200.0, ps_100_p[]_0_st=-32768, ps_100_plist_0_p_f[]_1=2.0, p[]_0_ilist_0=1, ps_100_plist_0_p_f[]_0=1.0, p[]_0_ilist_1=2, ps_100_cs=CharSequence, ps_100_plist_0_p[]_0_bool[]_0=false, c[]_3=c, c[]_2=a, ps_100_plist_0_p[]_0_bool[]_1=false, ps_100_plist_0_p[]_0_bool[]_2=true, c[]_4=m, p_d[]_0=1.0, c[]_1=p, p_d[]_1=2.0, c[]_0=c, bundle_st[]_1=32767, plist_0_s[]_0=s1, bundle_st[]_0=-32768, plist_0_s[]_1=s2, ps_100_plist_0_p[]_0_st[]_1=32767, bundle_st=-32768, bundle_slist_0=name, ps_100_plist_0_p[]_0_st[]_0=-32768, bundle_slist_1=cpacm, cslist_0=name, ps_100_p_b[]_2=97, ps_100_p_b[]_3=99, ps_100_p_b[]_0=99, bundle_size=100x200, ps_100_p_b[]_1=112, p_b[]_0=99, p_b[]_1=112, ps_100_plist_0_p_i[]_0=1, plist_0_p[]_0_cs[]_0=s1, ps_100_plist_0_p_i[]_3=4, ps_100_plist_0_p_i[]_1=2, ps_100_plist_0_p_i[]_2=3, ps_100_plist_0_p_size=100x200, p_b[]_4=109, p_b[]_2=97, ps_100_p[]_0_slist_0=name, p_b[]_3=99, ps_100_p[]_0_slist_1=cpacm, p[]_0_f[]_0=1.0, ps_100_p[]_0_bool[]_2=true, ps_100_p[]_0_bool[]_1=false, p[]_0_f[]_1=2.0, ps_100_p[]_0_bool[]_0=false, ps_100_plist_0_c[]_4=m, bundle_c[]_4=m, bundle_s=String, bundle_c[]_3=c, bundle_c[]_2=a, bundle_c[]_1=p, p_i[]_0=1, bundle_c[]_0=c, p_i[]_1=2, p_i[]_2=3, plist_0_p_slist_1=cpacm, plist_0_p_slist_0=name, bundle_sizeF=100.0x200.0, bundle_b=99, ps_100_p_bool=false, bundle_d=1.0, ps_100_i[]_1=2, bundle_c=a, ps_100_i[]_0=1, ps_100_i[]_3=4, ps_100_i[]_2=3, p_i[]_3=4, bundle_i=1, bundle_f=1.0, ps_100_plist_0_c[]_0=c, ps_100_plist_0_c[]_1=p, ps_100_plist_0_c[]_2=a, ps_100_plist_0_c[]_3=c, ps_100_plist_0_p[]_0_i[]_2=3, ps_100_p_slist_1=cpacm, ps_100_plist_0_p[]_0_i[]_3=4, ps_100_p_slist_0=name, p[]_0_st=-32768, ps_100_plist_0_p[]_0_s[]_1=s2, ps_100_plist_0_p[]_0_i=1, ps_100_plist_0_p[]_0_s[]_0=s1, ps_100_plist_0_p[]_0_f=1.0, plist_0_f[]_0=1.0, ps_100_plist_0_p[]_0_s=String, plist_0_f[]_1=2.0, ps_100_plist_0_p[]_0_i[]_0=1, ps_100_plist_0_p[]_0_i[]_1=2, plist_0_p_cslist_0=name, plist_0_p_cslist_1=cpacm, ps_100_plist_0_st[]_0=-32768, ps_100_plist_0_st[]_1=32767, d[]_1=2.0, d[]_0=1.0, ps_100_plist_0_sizeF=100.0x200.0, ps_100_p_st[]_1=32767, ps_100_p_st[]_0=-32768, ps_100_p[]_0_s[]_1=s2, ps_100_p[]_0_s[]_0=s1, ps_100_p_s[]_1=s2, ps_100_plist_0_p[]_0_d=1.0, ps_100_plist_0_p[]_0_b=99, ps_100_p_s[]_0=s1, ps_100_plist_0_p[]_0_c=a, plist_0_p[]_0_cs[]_1=s2, ps_100_plist_0_p[]_0_cs=CharSequence, ps_100_p[]_0_st[]_1=32767, ps_100_p[]_0_st[]_0=-32768, p[]_0_cs[]_0=s1, ps_100_ilist_1=2, plist_0_p[]_0_f[]_0=1.0, ps_100_p[]_0_cs[]_0=s1, ps_100_ilist_0=1, p_st[]_1=32767, ps_100_p[]_0_cs[]_1=s2, plist_0_p[]_0_f[]_1=2.0, p_st[]_0=-32768, plist_0_p_bool=false, p_s[]_0=s1, ps_100_plist_0_p[]_0_b[]_2=97, ps_100_plist_0_p[]_0_b[]_1=112, ps_100_plist_0_p[]_0_b[]_4=109, ps_100_plist_0_p[]_0_b[]_3=99, bundle_b[]_1=112, bundle_b[]_0=99, ps_100_plist_0_b[]_0=99, bundle_b[]_3=99, bundle_b[]_2=97, ps_100_plist_0_b[]_3=99, plist_0_p_cs[]_1=s2, bundle_b[]_4=109, p_s[]_1=s2, ps_100_plist_0_b[]_4=109, plist_0_p_cs[]_0=s1, ps_100_plist_0_b[]_1=112, ps_100_plist_0_b[]_2=97, p[]_0_size=100x200, ps_100_plist_0_p[]_0_b[]_0=99, ps_100_plist_0_ilist_0=1, ps_100_plist_0_ilist_1=2, plist_0_p_i[]_0=1, plist_0_p_i[]_2=3, plist_0_p_i[]_1=2, ps_100_plist_0_p[]_0_size=100x200, ps_100_plist_0_p_ilist_1=2, plist_0_p[]_0_slist_0=name, plist_0_p[]_0_slist_1=cpacm, ps_100_plist_0_p[]_0_cslist_1=cpacm, plist_0_p_i[]_3=4, bundle_bool=false, ps_100_plist_0_p[]_0_cslist_0=name, p_bool=false, ps_100_p_cs=CharSequence, ps_100_plist_0_cslist_0=name, ps_100_p_i[]_0=1, ps_100_plist_0_cslist_1=cpacm, ps_100_p_i[]_2=3, ps_100_p_i[]_1=2, ps_100_p[]_0_b[]_0=99, p[]_0_cs[]_1=s2, ps_100_p_i[]_3=4, ps_100_p[]_0_b[]_3=99, ps_100_p[]_0_b[]_4=109, ps_100_p[]_0_b[]_1=112, ps_100_p[]_0_b[]_2=97, ps_100_plist_0_p_ilist_0=1, p_slist_1=cpacm, plist_0_p[]_0_st=-32768, ps_100_plist_0_p_s=String, p_slist_0=name, ps_100_plist_0_p_i=1, ps_100_plist_0_size=100x200, plist_0_p[]_0_i[]_3=4, plist_0_p[]_0_i[]_2=3, plist_0_p[]_0_i[]_1=2, plist_0_p[]_0_i[]_0=1, ps_100_plist_0_p_b=99, ps_100_plist_0_p_c=a, ps_100_plist_0_p_d=1.0, ps_100_plist_0_p[]_0_sizeF=100.0x200.0, ps_100_plist_0_p_f=1.0, p[]_0_s[]_0=s1, p[]_0_s[]_1=s2, ps_100_p_size=100x200, ps_100_plist_0_p[]_0_cs[]_1=s2, ps_100_plist_0_p[]_0_cs[]_0=s1, plist_0_p[]_0_cslist_1=cpacm, plist_0_p_bool[]_1=false, plist_0_p_bool[]_0=false, plist_0_p[]_0_cslist_0=name, plist_0_p_bool[]_2=true, f[]_0=1.0, f[]_1=2.0, p[]_0_d[]_0=1.0, bundle_i[]_1=2, p[]_0_d[]_1=2.0, plist_0_bool[]_1=false, bundle_i[]_2=3, plist_0_bool[]_2=true, bundle_i[]_3=4, plist_0_bool[]_0=false, ps_100_plist_0_p_st[]_0=-32768, ps_100_plist_0_p_st[]_1=32767, plist_0_p_s[]_0=s1, plist_0_p_s[]_1=s2, ps_100_p_sizeF=100.0x200.0, ps_100_plist_0_p_c[]_0=c, plist_0_p[]_0_b[]_4=109, plist_0_p[]_0_b[]_3=99, ps_100_plist_0_p_c[]_2=a, ps_100_plist_0_p_c[]_1=p, plist_0_p[]_0_b[]_0=99, plist_0_p[]_0_b[]_2=97, plist_0_p[]_0_b[]_1=112, plist_0_p_st[]_0=-32768, plist_0_p_st[]_1=32767, ps_100_p[]_0_c[]_0=c, ps_100_plist_0_p_bool[]_1=false, ps_100_p[]_0_c[]_1=p, ps_100_plist_0_p_bool[]_0=false, st=-32768, ps_100_p[]_0_c[]_2=a, ps_100_p[]_0_c[]_3=c, ps_100_p[]_0_c[]_4=m, ps_100_st[]_1=32767, ps_100_st[]_0=-32768, ps_100_plist_0_p_c[]_4=m, ps_100_plist_0_p_c[]_3=c, plist_0_st=-32768, ps_100_plist_0_p_bool[]_2=true, plist_0_p_st=-32768, p_bool[]_0=false, p_bool[]_1=false, p_bool[]_2=true, p[]_0_bool[]_1=false, ps_100_plist_0_p_s[]_1=s2, p[]_0_bool[]_2=true, bundle_cs=CharSequence, ps_100_plist_0_p_s[]_0=s1, p[]_0_bool[]_0=false, ps_100_f=1.0, p_sizeF=100.0x200.0, ps_100_i=1, ps_100_c=a, ps_100_b=99, ps_100_d=1.0, ps_100_p[]_0_i[]_1=2, ps_100_p[]_0_i[]_0=1, plist_0_p_f[]_1=2.0, plist_0_p_f[]_0=1.0, ps_100_plist_0_p_st=-32768, ps_100_cslist_1=cpacm, ps_100_p[]_0_i[]_3=4, p_ilist_1=2, ps_100_p[]_0_i[]_2=3, p_ilist_0=1, ps_100_cslist_0=name, plist_0_i[]_3=4, plist_0_i[]_2=3, plist_0_i[]_1=2, plist_0_i[]_0=1, plist_0_cs[]_1=s2, ps_100_plist_0_st=-32768, p_cs=CharSequence, plist_0_cs[]_0=s1, ps_100_p_bool[]_2=true, slist_1=cpacm, slist_0=name, ps_100_p_bool[]_0=false, ps_100_s=String, ps_100_p_bool[]_1=false, ps_100_p_f[]_0=1.0, st[]_0=-32768, ps_100_p_f[]_1=2.0, st[]_1=32767, plist_0_p[]_0_c[]_1=p, plist_0_p[]_0_c[]_0=c, bool=false, plist_0_p[]_0_c[]_4=m, plist_0_p[]_0_c[]_3=c, plist_0_p[]_0_c[]_2=a, bundle_i[]_0=1, ps_100_st=-32768, ilist_1=2, ilist_0=1, p_cs[]_0=s1, ps_100_plist_0_i[]_3=4, p_cs[]_1=s2, ps_100_plist_0_i[]_2=3, ps_100_plist_0_i[]_1=2, ps_100_plist_0_i[]_0=1, ps_100_p[]_0_cs=CharSequence, ps_100_plist_0_cs[]_0=s1, ps_100_plist_0_cs[]_1=s2, ps_100_p_s=String, plist_0_size=100x200, sizeF=100.0x200.0, ps_100_plist_0_bool[]_0=false, ps_100_f[]_1=2.0, ps_100_p_i=1, ps_100_plist_0_bool[]_2=true, ps_100_plist_0_bool[]_1=false, bundle_cslist_1=cpacm, ps_100_p[]_0_d[]_1=2.0, bundle_cslist_0=name, ps_100_p[]_0_d[]_0=1.0, ps_100_p_c=a, ps_100_p_d=1.0, ps_100_p_b=99, ps_100_p_f=1.0, ps_100_f[]_0=1.0, p_size=100x200, ps_100_p[]_0_size=100x200, ps_100_plist_0_bool=false, plist_0_sizeF=100.0x200.0, ps_100_slist_0=name, ps_100_slist_1=cpacm, ps_100_plist_0_p_b[]_4=109, ps_100_plist_0_p_b[]_3=99, ps_100_plist_0_p_b[]_2=97, ps_100_plist_0_p_b[]_1=112, ps_100_plist_0_p_b[]_0=99, plist_0_p[]_0_st[]_0=-32768, plist_0_p[]_0_st[]_1=32767, p[]_0_slist_0=name, p[]_0_slist_1=cpacm, ps_100_b[]_3=99, ps_100_b[]_4=109, ps_100_b[]_1=112, plist_0_p_c[]_0=c, ps_100_b[]_2=97, ps_100_b[]_0=99, ps_100_plist_0_slist_1=cpacm, ps_100_plist_0_slist_0=name, plist_0_p_c[]_2=a, plist_0_p_c[]_1=p, plist_0_p_c[]_4=m, plist_0_p_c[]_3=c, ps_100_plist_0_p_slist_0=name, p[]_0_c[]_0=c, plist_0_i=1, p[]_0_c[]_1=p, ps_100_plist_0_p_slist_1=cpacm, ps_100_size=100x200, p[]_0_c[]_4=m, p[]_0_c[]_2=a, p[]_0_c[]_3=c, p[]_0_sizeF=100.0x200.0, plist_0_c=a, plist_0_b=99, plist_0_d=1.0, plist_0_f=1.0, ps_100_p_cs[]_0=s1, ps_100_p_cs[]_1=s2, plist_0_s=String, p[]_0_i=1, p[]_0_d=1.0, p[]_0_f=1.0, p[]_0_c=a, p[]_0_b=99, plist_0_p_sizeF=100.0x200.0, plist_0_st[]_1=32767, p[]_0_cs=CharSequence, plist_0_st[]_0=-32768, bundle_f[]_1=2.0, bundle_f[]_0=1.0, p[]_0_s=String, p_cslist_0=name, p_cslist_1=cpacm, ps_100_c[]_0=c, plist_0_b[]_3=99, ps_100_c[]_1=p, plist_0_b[]_4=109, bundle_cs[]_0=s1, ps_100_c[]_2=a, bundle_cs[]_1=s2, ps_100_c[]_3=c, plist_0_p[]_0_size=100x200, plist_0_p_ilist_0=1, ps_100_plist_0_f[]_1=2.0, plist_0_p_d[]_1=2.0, plist_0_p_ilist_1=2, plist_0_p_d[]_0=1.0, i[]_2=3, i[]_3=4, plist_0_b[]_0=99, i[]_0=1, plist_0_b[]_1=112, ps_100_sizeF=100.0x200.0, i[]_1=2, plist_0_b[]_2=97, ps_100_plist_0_p[]_0_st=-32768, ps_100_plist_0_f[]_0=1.0, plist_0_p[]_0_s[]_0=s1, plist_0_p[]_0_s[]_1=s2, ps_100_p[]_0_cslist_0=name, ps_100_p[]_0_cslist_1=cpacm, ps_100_p_d[]_0=1.0, ps_100_c[]_4=m, ps_100_p_d[]_1=2.0, ps_100_plist_0_p[]_0_slist_0=name, ps_100_plist_0_p[]_0_slist_1=cpacm, plist_0_cslist_0=name, ps_100_plist_0_p_sizeF=100.0x200.0, ps_100_plist_0_p_d[]_1=2.0, ps_100_plist_0_p_d[]_0=1.0, plist_0_cslist_1=cpacm, ps_100_p[]_0_f[]_0=1.0, ps_100_p_ilist_1=2, ps_100_p[]_0_f[]_1=2.0, p[]_0_b[]_3=99, plist_0_p_b=99, p[]_0_b[]_4=109, plist_0_p_f=1.0, p[]_0_b[]_0=99, p[]_0_b[]_1=112, plist_0_p_d=1.0, ps_100_p_st=-32768, p[]_0_b[]_2=97, plist_0_p_c=a, plist_0_p_i=1, plist_0_p_s=String, bundle_bool[]_2=true, bundle_bool[]_0=false, bundle_bool[]_1=false, bool[]_0=false, plist_0_c[]_1=p, plist_0_c[]_0=c, bool[]_2=true, bool[]_1=false, ps_100_p_ilist_0=1, p_f[]_0=1.0, serial=cpacm, p_f[]_1=2.0, s[]_1=s2, s[]_0=s1, ps_100_plist_0_p[]_0_f[]_1=2.0, ps_100_plist_0_p[]_0_f[]_0=1.0, plist_0_c[]_4=m, plist_0_c[]_3=c, plist_0_c[]_2=a}";
+
+}
diff --git a/inject-annotation/compiler/.gitignore b/growingio-adapter/analytics-ga/.gitignore
similarity index 100%
rename from inject-annotation/compiler/.gitignore
rename to growingio-adapter/analytics-ga/.gitignore
diff --git a/growingio-adapter/analytics-ga/build.gradle b/growingio-adapter/analytics-ga/build.gradle
new file mode 100644
index 00000000..3eab4154
--- /dev/null
+++ b/growingio-adapter/analytics-ga/build.gradle
@@ -0,0 +1,55 @@
+plugins {
+ id 'com.android.library'
+}
+
+android {
+ compileSdkVersion buildConfiguration.compileVersion
+ defaultConfig {
+ minSdkVersion buildConfiguration.minSdkVersion
+ targetSdkVersion buildConfiguration.targetSdkVersion
+ versionName releaseConfiguration.releaseVersion
+ versionCode releaseConfiguration.releaseVersionCode
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ sourceCompatibility buildConfiguration.sourceCompatibility
+ targetCompatibility buildConfiguration.targetCompatibility
+ }
+
+ testOptions {
+ unitTests.all {
+ jacoco {
+ includeNoLocationClasses = true
+ excludes = ['jdk.internal.*']
+ }
+ }
+ unitTests {
+ returnDefaultValues = true
+ includeAndroidResources = true
+ }
+ }
+}
+
+
+dependencies {
+ testImplementation libraries.test.junit
+ testImplementation libraries.test.truth
+ testImplementation libraries.test.androidx_core
+ testImplementation libraries.test.robolectric
+
+ implementation project(':growingio-tracker-core')
+
+ implementation project(":growingio-annotation")
+ annotationProcessor project(":growingio-annotation:compiler")
+
+ compileOnly "com.google.android.gms:play-services-analytics:18.0.1"
+}
+apply from: "${rootProject.projectDir}/gradle/publishMaven.gradle"
+apply from: "${rootProject.projectDir}/gradle/jacocoModule.gradle"
\ No newline at end of file
diff --git a/growingio-adapter/analytics-ga/consumer-rules.pro b/growingio-adapter/analytics-ga/consumer-rules.pro
new file mode 100644
index 00000000..e69de29b
diff --git a/growingio-adapter/analytics-ga/gradle.properties b/growingio-adapter/analytics-ga/gradle.properties
new file mode 100644
index 00000000..ac79748b
--- /dev/null
+++ b/growingio-adapter/analytics-ga/gradle.properties
@@ -0,0 +1,4 @@
+POM_NAME=analytics-ga
+POM_ARTIFACT_ID=analytics-ga
+POM_PACKAGING=aar
+POM_DESCRIPTION=Adapter Google Analytics data to Growingio's sdk.
\ No newline at end of file
diff --git a/growingio-adapter/analytics-ga/proguard-rules.pro b/growingio-adapter/analytics-ga/proguard-rules.pro
new file mode 100644
index 00000000..481bb434
--- /dev/null
+++ b/growingio-adapter/analytics-ga/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/growingio-adapter/analytics-ga/src/main/AndroidManifest.xml b/growingio-adapter/analytics-ga/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..708d5d3a
--- /dev/null
+++ b/growingio-adapter/analytics-ga/src/main/AndroidManifest.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/GoogleAnalyticsAdapter.java b/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/GoogleAnalyticsAdapter.java
new file mode 100644
index 00000000..a4163fc4
--- /dev/null
+++ b/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/GoogleAnalyticsAdapter.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2020 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.analytics.google;
+
+import android.content.res.XmlResourceParser;
+import android.text.TextUtils;
+
+import com.google.android.gms.analytics.GoogleAnalytics;
+import com.google.android.gms.analytics.Tracker;
+import com.growingio.android.analytics.google.model.AnalyticsEvent;
+import com.growingio.android.analytics.google.model.TrackerInfo;
+import com.growingio.android.sdk.TrackerContext;
+import com.growingio.android.sdk.track.TrackMainThread;
+import com.growingio.android.sdk.track.events.AutotrackEventType;
+import com.growingio.android.sdk.track.events.CustomEvent;
+import com.growingio.android.sdk.track.events.EventBuildInterceptor;
+import com.growingio.android.sdk.track.events.LoginUserAttributesEvent;
+import com.growingio.android.sdk.track.events.TrackEventType;
+import com.growingio.android.sdk.track.events.VisitEvent;
+import com.growingio.android.sdk.track.events.base.BaseEvent;
+import com.growingio.android.sdk.track.ipc.PersistentDataProvider;
+import com.growingio.android.sdk.track.listener.IActivityLifecycle;
+import com.growingio.android.sdk.track.listener.TrackThread;
+import com.growingio.android.sdk.track.listener.event.ActivityLifecycleEvent;
+import com.growingio.android.sdk.track.log.Logger;
+import com.growingio.android.sdk.track.middleware.GEvent;
+import com.growingio.android.sdk.track.providers.ActivityStateProvider;
+import com.growingio.android.sdk.track.providers.ConfigurationProvider;
+import com.growingio.android.sdk.track.providers.SessionProvider;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * 不支持多进程
+ */
+public class GoogleAnalyticsAdapter implements IActivityLifecycle {
+ private static final String TAG = "GoogleAnalyticsAdapter";
+ private static final String USER_ID_KEY = "&uid";
+ private static final String CLIENT_ID_KEY = "&cid";
+ private static final String MEASUREMENT_ID_KEY = "&tid";
+
+ private final Map mTrackers = new HashMap<>();
+ private final GoogleAnalyticsConfiguration mGoogleAnalyticsConfiguration;
+
+ private long mSessionInterval = 30 * 1000L;
+ private boolean mEnterBackground = true;
+
+ // true 为关闭采集,false 为开启采集
+ private boolean mOptOut;
+
+ private static class SingleInstance {
+ private static final GoogleAnalyticsAdapter INSTANCE = new GoogleAnalyticsAdapter();
+ }
+
+ // 注意两个时机
+ // 1. cdp的gioId事件拦截必定在newTracker,但是需要给新构建的事件增加gioId以及通用属性读取(不会被拦截器处理)
+ // 2. activity的生命周期注册先于SessionProvider
+ private GoogleAnalyticsAdapter() {
+ // 初始化 使用 GA的 开关配置,忽略本身的配置项
+ // TODO: 初始化前 在 子线程修改 AppOptOut 可能导致状态异常, GA中仅保证optOut的可见性(volatile)
+ mOptOut = GoogleAnalytics.getInstance(TrackerContext.get()).getAppOptOut();
+ // AppOptOut true/false 与 dataCollectionEnabled 相反
+ ConfigurationProvider.core().setDataCollectionEnabled(!mOptOut);
+ mGoogleAnalyticsConfiguration = ConfigurationProvider.get().getConfiguration(GoogleAnalyticsConfiguration.class);
+ mSessionInterval = ConfigurationProvider.core().getSessionInterval() * 1000L;
+ ActivityStateProvider.get().registerActivityLifecycleListener(this);
+ }
+
+ public static GoogleAnalyticsAdapter get() {
+ return SingleInstance.INSTANCE;
+ }
+
+ @Override
+ public void onActivityLifecycle(ActivityLifecycleEvent event) {
+ // 注意 该函数与SessionProvider中 latestPauseTime 与 activityCount的关系
+ // SessionProvider#init 先于 模块注册,即先执行SessionProvider中设置
+ if (event.eventType == ActivityLifecycleEvent.EVENT_TYPE.ON_STARTED) {
+ if (mEnterBackground) {
+ mEnterBackground = false;
+ long latestPauseTime = PersistentDataProvider.get().getLatestPauseTime();
+ if (latestPauseTime != 0 && (System.currentTimeMillis() - latestPauseTime >= mSessionInterval)) {
+ TrackMainThread.trackMain().postActionToTrackMain(new Runnable() {
+ @Override
+ public void run() {
+ // 更新所有 Tracker 的 session,并补发相应vst事件
+ for (TrackerInfo trackerInfo : mTrackers.values()) {
+ trackerInfo.setSessionId(UUID.randomUUID().toString());
+ newAnalyticsEvent(new VisitEvent.Builder(), trackerInfo);
+ }
+ }
+ });
+ }
+ }
+ } else if (event.eventType == ActivityLifecycleEvent.EVENT_TYPE.ON_STOPPED) {
+ // SessionProvider 先执行已经将对应count减去相关值 并设置对应latestPauseTime
+ if (PersistentDataProvider.get().getActivityCount() == 0) {
+ mEnterBackground = true;
+ }
+ }
+ }
+
+ // 解析 GA3 配置xml
+ void newTracker(Tracker tracker, int resId) {
+ try {
+ XmlResourceParser parser = TrackerContext.get().getResources().getXml(resId);
+ boolean foundTag = false;
+ while (parser.getEventType() != XmlResourceParser.END_DOCUMENT) {
+ if (parser.getEventType() == XmlResourceParser.START_TAG) {
+ String tagName = parser.getName();
+ String nameAttr = parser.getAttributeValue(null, "name");
+ foundTag = "string".equals(tagName) && "ga_trackingId".equals(nameAttr);
+ }
+ if (parser.getEventType() == XmlResourceParser.TEXT) {
+ if (foundTag) {
+ String measurementId = parser.getText();
+ if (!TextUtils.isEmpty(measurementId)) {
+ newTracker(tracker, measurementId);
+ return;
+ }
+ }
+ }
+ parser.next();
+ }
+ } catch (Exception ignored) {
+ }
+ }
+
+ void newTracker(Tracker tracker, String measurementId) {
+ TrackMainThread.trackMain().postActionToTrackMain(new Runnable() {
+ @Override
+ public void run() {
+ String datasourceId = mGoogleAnalyticsConfiguration.getDatasourceIds().get(measurementId);
+ if (measurementId != null && !TextUtils.isEmpty(datasourceId) && !mTrackers.containsKey(measurementId)) {
+ TrackerInfo trackerInfo = new TrackerInfo(datasourceId, UUID.randomUUID().toString());
+ trackerInfo.setEventBuildInterceptor(new EventBuildInterceptor() {
+ @Override
+ public void eventWillBuild(BaseEvent.BaseBuilder> eventBuilder) {
+ }
+
+ @Override
+ public void eventDidBuild(GEvent event) {
+ // 转发所有无埋点事件, VST不进行再次转发
+ if (TrackEventType.APP_CLOSED.equals(event.getEventType()) ||
+ TrackEventType.FORM_SUBMIT.equals(event.getEventType()) ||
+ AutotrackEventType.PAGE.equals(event.getEventType()) ||
+ AutotrackEventType.PAGE_ATTRIBUTES.equals(event.getEventType()) ||
+ AutotrackEventType.VIEW_CHANGE.equals(event.getEventType()) ||
+ AutotrackEventType.VIEW_CLICK.equals(event.getEventType())) {
+ if (event instanceof BaseEvent) {
+ transformAnalyticsEvent((BaseEvent) event, trackerInfo);
+ }
+ }
+ }
+ });
+ // 增加对应Tracker拦截器
+ TrackMainThread.trackMain().addEventBuildInterceptor(trackerInfo.getEventBuildInterceptor());
+
+ // 发送 用户属性事件 用于关联历史数据
+ String clientId = getClientId(tracker);
+ if (!TextUtils.isEmpty(clientId)) {
+ trackerInfo.setClientId(clientId);
+ }
+
+ sendNewTrackEvent(trackerInfo);
+
+ mTrackers.put(measurementId, trackerInfo);
+ }
+ }
+ });
+ }
+
+// void setClientId(Tracker tracker, String clientId) {
+// TrackMainThread.trackMain().postActionToTrackMain(new Runnable() {
+// @Override
+// public void run() {
+// TrackerInfo trackerInfo = mTrackers.get(getMeasurementId(tracker));
+// if (trackerInfo != null) {
+// trackerInfo.setClientId(clientId);
+// sendClientIdEvent(trackerInfo);
+// }
+// }
+// });
+// }
+
+ void send(Tracker tracker, Map params) {
+ TrackMainThread.trackMain().postActionToTrackMain(new Runnable() {
+ @Override
+ public void run() {
+ TrackerInfo trackerInfo = mTrackers.get(getMeasurementId(tracker));
+ if (trackerInfo != null) {
+ newAnalyticsEvent(new CustomEvent.Builder()
+ .setEventName("GAEvent")
+ .setAttributes(params), trackerInfo);
+ }
+ }
+ });
+ }
+
+ void set(Tracker tracker, String key, String value) {
+ TrackMainThread.trackMain().postActionToTrackMain(new Runnable() {
+ @Override
+ public void run() {
+ TrackerInfo trackerInfo = mTrackers.get(getMeasurementId(tracker));
+ if (trackerInfo != null) {
+ if (USER_ID_KEY.equals(key)) {
+ setUserId(trackerInfo, value);
+ return;
+ } else if (CLIENT_ID_KEY.equals(key)) {
+ // setClientId 内部调用 set 方法
+ trackerInfo.setClientId(value);
+ sendClientIdEvent(trackerInfo);
+ return;
+ }
+ setDefaultParam(trackerInfo, key, value);
+ }
+ }
+ });
+ }
+
+ void setAppOptOut(boolean optOut) {
+ TrackMainThread.trackMain().postActionToTrackMain(new Runnable() {
+ @Override
+ public void run() {
+ // GA3 全局控制 控制原生部分开关
+ // 考虑 使用运行时 API 进行开关控制,可能导致与 GA 全局控制开关不同
+ setDataCollectionEnabled(!optOut);
+
+ // GA3 全局控制 控制Tracker部分开关
+ if (optOut == mOptOut) {
+ Logger.e(TAG, "当前GA3数据采集开关 = " + optOut + ", 请勿重复操作");
+ } else {
+ mOptOut = optOut;
+ // 关 -> 开
+ if (!optOut) {
+ for (TrackerInfo trackerInfo : mTrackers.values()) {
+ sendNewTrackEvent(trackerInfo);
+ }
+ }
+ }
+ }
+ });
+ }
+
+ @TrackThread
+ private void setDataCollectionEnabled(boolean enabled) {
+ if (enabled == ConfigurationProvider.core().isDataCollectionEnabled()) {
+ Logger.e(TAG, "当前数据采集开关 = " + enabled + ", 请勿重复操作");
+ } else {
+ ConfigurationProvider.core().setDataCollectionEnabled(enabled);
+ if (enabled) {
+ SessionProvider.get().generateVisit();
+ }
+ }
+ }
+
+ @TrackThread
+ private void sendNewTrackEvent(TrackerInfo trackerInfo) {
+ // 补发vst
+ // 直接入库,不经过Interceptor
+ newAnalyticsEvent(new VisitEvent.Builder(), trackerInfo);
+
+ sendClientIdEvent(trackerInfo);
+ }
+
+ @TrackThread
+ private void sendClientIdEvent(TrackerInfo trackerInfo) {
+ // 发送 用户属性事件 用于关联历史数据
+ if (!TextUtils.isEmpty(trackerInfo.getClientId())) {
+ Map attributes = new HashMap<>();
+ attributes.put(CLIENT_ID_KEY, trackerInfo.getClientId());
+ newAnalyticsEvent(new LoginUserAttributesEvent.Builder()
+ .setAttributes(attributes), trackerInfo);
+ }
+ }
+
+ @TrackThread
+ private void setUserId(TrackerInfo trackerInfo, String userId) {
+ if (TextUtils.isEmpty(userId)) {
+ trackerInfo.setUserId(null);
+ return;
+ }
+
+ String oldUserId = trackerInfo.getUserId();
+ // A -> A 直接返回
+ if (userId.equals(oldUserId)) {
+ return;
+ }
+ trackerInfo.setUserId(userId);
+
+ String lastUserId = trackerInfo.getLastUserId();
+ trackerInfo.setLastUserId(userId);
+ // null -> A 补发vst
+ // A -> null -> A 不做session变更, 与3.0保持一致,不补发vst
+ if (TextUtils.isEmpty(lastUserId)) {
+ newAnalyticsEvent(new VisitEvent.Builder(), trackerInfo);
+ } else {
+ if (!userId.equals(lastUserId)) {
+ // 更新session, 补发vst事件
+ trackerInfo.setSessionId(UUID.randomUUID().toString());
+ newAnalyticsEvent(new VisitEvent.Builder(), trackerInfo);
+ }
+ }
+ }
+
+ @TrackThread
+ private void setDefaultParam(TrackerInfo trackerInfo, String key, String value) {
+ trackerInfo.addParam(key, value);
+ }
+
+ @TrackThread
+ private String getMeasurementId(Tracker tracker) {
+ try {
+ // GA 未初始化完成可能抛出IllegalStateException
+ return tracker.get(MEASUREMENT_ID_KEY);
+ } catch (Exception e) {
+ }
+
+ return null;
+ }
+
+ @TrackThread
+ private String getClientId(Tracker tracker) {
+ try {
+ return tracker.get(CLIENT_ID_KEY);
+ } catch (Exception e) {
+ }
+
+ return null;
+ }
+
+ // 主动构造的事件需要执行readPropertyInTrackThread读取通用参数
+ // 不通过readPropertyInTrackThread方法直接读取参数,避免导致esid、gesid自增
+ @TrackThread
+ private void newAnalyticsEvent(BaseEvent.BaseBuilder baseBuilder, TrackerInfo trackerInfo) {
+ postAnalyticsEvent(new AnalyticsEvent(baseBuilder.build(), trackerInfo, true));
+ }
+
+ // 转发事件已经执行过readPropertyInTrackThread
+ @TrackThread
+ private void transformAnalyticsEvent(BaseEvent event, TrackerInfo trackerInfo, long timestamp) {
+ postAnalyticsEvent(new AnalyticsEvent(event, trackerInfo, timestamp));
+ }
+
+ @TrackThread
+ private void transformAnalyticsEvent(BaseEvent event, TrackerInfo trackerInfo) {
+ postAnalyticsEvent(new AnalyticsEvent(event, trackerInfo));
+ }
+
+ @TrackThread
+ private void postAnalyticsEvent(AnalyticsEvent analyticsEvent) {
+ if (!mOptOut) {
+ // 转发给 MobileDebugger 的 EventBuildInterceptor
+ // MobileDebugger 默认 在 Tracker中 先于 第三方模块加载 直接调用 DebuggerEventWrapper 发送数据 / 缓存数据
+ sendToDebugger(analyticsEvent);
+
+ TrackMainThread.trackMain().postGEventToTrackMain(analyticsEvent);
+ }
+ }
+
+ private Object mDebuggerEventWrapper;
+ private Method mEventDidBuildMethod;
+ private boolean mDebuggerNotFind = false;
+
+ @TrackThread
+ private void sendToDebugger(AnalyticsEvent analyticsEvent) {
+ if (mDebuggerNotFind) return;
+
+ try {
+ if (mDebuggerEventWrapper == null || mEventDidBuildMethod == null) {
+ Class> clazz = Class.forName("com.growingio.android.debugger.DebuggerEventWrapper");
+ Method getMethod = clazz.getDeclaredMethod("get");
+ mDebuggerEventWrapper = getMethod.invoke(null);
+ mEventDidBuildMethod = clazz.getDeclaredMethod("eventDidBuild", Class.forName("com.growingio.android.sdk.track.middleware.GEvent"));
+ }
+ mEventDidBuildMethod.invoke(mDebuggerEventWrapper, analyticsEvent);
+
+ return;
+ } catch (Exception ignored) {
+ }
+
+ mDebuggerNotFind = true;
+ }
+}
diff --git a/inject-annotation/compiler/src/test/java/com/growingio/sdk/sample/TestOnClickListener.java b/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/GoogleAnalyticsConfiguration.java
similarity index 51%
rename from inject-annotation/compiler/src/test/java/com/growingio/sdk/sample/TestOnClickListener.java
rename to growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/GoogleAnalyticsConfiguration.java
index e21b4a02..896de3a2 100644
--- a/inject-annotation/compiler/src/test/java/com/growingio/sdk/sample/TestOnClickListener.java
+++ b/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/GoogleAnalyticsConfiguration.java
@@ -14,40 +14,25 @@
* limitations under the License.
*/
-package com.growingio.sdk.sample;
+package com.growingio.android.analytics.google;
+import com.growingio.android.sdk.Configurable;
-import java.util.List;
+import java.util.HashMap;
+import java.util.Map;
-public class TestOnClickListener {
- public void onClick(int obj) {
- }
-
- public void show() {
- }
-
- public boolean onOptionsItemSelected() {
- return false;
- }
-
- public boolean onOptionsItemSelected2() {
- return true;
- }
-
- public void loadUrl(String url) {
- }
+public class GoogleAnalyticsConfiguration implements Configurable {
- public void onResume() {
- }
-
- public void onResume2() {
- }
+ private Map mDatasourceIds = new HashMap<>();
- public String types(float type1, double type2, char type3, short type4, boolean type5, byte type6) {
- return "";
+ public GoogleAnalyticsConfiguration setDatasourceIds(Map map) {
+ if (map != null) {
+ this.mDatasourceIds.putAll(map);
+ }
+ return this;
}
- public Object arrays(List params) {
- return "";
+ public Map getDatasourceIds() {
+ return this.mDatasourceIds;
}
}
diff --git a/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/GoogleAnalyticsInjector.java b/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/GoogleAnalyticsInjector.java
new file mode 100644
index 00000000..b136ae36
--- /dev/null
+++ b/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/GoogleAnalyticsInjector.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2020 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.analytics.google;
+
+import com.google.android.gms.analytics.GoogleAnalytics;
+import com.google.android.gms.analytics.Tracker;
+import com.growingio.android.sdk.TrackerContext;
+import com.growingio.android.sdk.track.log.Logger;
+
+import java.util.Map;
+
+public class GoogleAnalyticsInjector {
+ private static final String TAG = "GoogleAnalyticsInjector";
+
+ private GoogleAnalyticsInjector() {
+ }
+
+ public static void newTracker(Tracker tracker, GoogleAnalytics googleAnalytics, int resId) {
+ if (!TrackerContext.initializedSuccessfully()) {
+ Logger.e(TAG, "Tracker do not initialized successfully");
+ return;
+ }
+
+ GoogleAnalyticsAdapter.get().newTracker(tracker, resId);
+ }
+
+ public static void newTracker(Tracker tracker, GoogleAnalytics googleAnalytics, String measurementId) {
+ if (!TrackerContext.initializedSuccessfully()) {
+ Logger.e(TAG, "Tracker do not initialized successfully");
+ return;
+ }
+
+ GoogleAnalyticsAdapter.get().newTracker(tracker, measurementId);
+ }
+
+ public static void setAppOptOut(GoogleAnalytics googleAnalytics, boolean optOut) {
+ if (!TrackerContext.initializedSuccessfully()) {
+ Logger.e(TAG, "Tracker do not initialized successfully");
+ return;
+ }
+
+ GoogleAnalyticsAdapter.get().setAppOptOut(optOut);
+ }
+
+ public static void setClientId(Tracker tracker, String clientId) {
+ // setClientId 内部调用 set("&cid", clientId);
+// if (!TrackerContext.initializedSuccessfully()) {
+// Logger.e(TAG, "Tracker do not initialized successfully");
+// return;
+// }
+//
+// GoogleAnalyticsAdapter.get().setClientId(tracker, clientId);
+ }
+
+ public static void send(Tracker tracker, Map params) {
+ if (!TrackerContext.initializedSuccessfully()) {
+ Logger.e(TAG, "Tracker do not initialized successfully");
+ return;
+ }
+
+ GoogleAnalyticsAdapter.get().send(tracker, params);
+ }
+
+ public static void set(Tracker tracker, String key, String value) {
+ if (!TrackerContext.initializedSuccessfully()) {
+ Logger.e(TAG, "Tracker do not initialized successfully");
+ return;
+ }
+
+ GoogleAnalyticsAdapter.get().set(tracker, key, value);
+ }
+}
diff --git a/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/GoogleAnalyticsLibraryModule.java b/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/GoogleAnalyticsLibraryModule.java
new file mode 100644
index 00000000..18e1c064
--- /dev/null
+++ b/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/GoogleAnalyticsLibraryModule.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 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.analytics.google;
+
+import android.content.Context;
+
+import com.growingio.android.sdk.LibraryGioModule;
+import com.growingio.android.sdk.track.modelloader.TrackerRegistry;
+import com.growingio.sdk.annotation.GIOLibraryModule;
+
+@GIOLibraryModule(config = GoogleAnalyticsConfiguration.class)
+public class GoogleAnalyticsLibraryModule extends LibraryGioModule {
+
+ @Override
+ public void registerComponents(Context context, TrackerRegistry registry) {
+ // 提前初始化
+ GoogleAnalyticsAdapter.get();
+ }
+}
\ No newline at end of file
diff --git a/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/model/AnalyticsEvent.java b/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/model/AnalyticsEvent.java
new file mode 100644
index 00000000..7a4f381a
--- /dev/null
+++ b/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/model/AnalyticsEvent.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2020 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.analytics.google.model;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import com.growingio.android.sdk.TrackerContext;
+import com.growingio.android.sdk.track.SDKConfig;
+import com.growingio.android.sdk.track.events.TrackEventType;
+import com.growingio.android.sdk.track.events.base.BaseEvent;
+import com.growingio.android.sdk.track.events.helper.FieldIgnoreFilter;
+import com.growingio.android.sdk.track.providers.AppInfoProvider;
+import com.growingio.android.sdk.track.providers.DeviceInfoProvider;
+import com.growingio.android.sdk.track.providers.SessionProvider;
+import com.growingio.android.sdk.track.utils.NetworkUtil;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * 当前仅支持 JSON模块上报,PB模块不依赖 toJSONObject方法
+ */
+public class AnalyticsEvent extends BaseEvent {
+ private static final String REPLACE_USER_KEY = "userKey";
+ private static final String REPLACE_SESSION_ID = "sessionId";
+ private static final String REPLACE_DATASOURCE_ID = "dataSourceId";
+ private static final String REPLACE_USER_ID = "userId";
+ private static final String REPLACE_GIO_ID = "gioId";
+ private static final String REPLACE_ATTRIBUTES = "attributes";
+ private static final String REPLACE_GLOBAL_SEQUENCE_ID = "globalSequenceId";
+ private static final String REPLACE_EVENT_SEQUENCE_ID = "eventSequenceId";
+
+ private static final String READ_DEVICE_ID = "deviceId";
+ private static final String READ_NETWORK_STATE = "networkState";
+ private static final String READ_SCREEN_HEIGHT = "screenHeight";
+ private static final String READ_SCREEN_WIDTH = "screenWidth";
+ private static final String READ_DEVICE_BRAND = "deviceBrand";
+ private static final String READ_DEVICE_MODEL = "deviceModel";
+ private static final String READ_DEVICE_TYPE = "deviceType";
+ private static final String READ_APP_CHANNEL = "appChannel";
+ private static final String READ_APP_NAME = "appName";
+ private static final String READ_APP_VERSION = "appVersion";
+ private static final String READ_LATITUDE = "latitude";
+ private static final String READ_LONGITUDE = "longitude";
+ private static final String READ_SDK_VERSION = "sdkVersion";
+ private static final String READ_LANGUAGE = "language";
+
+ private static final String READ_VISIT_IMEI = "imei";
+ private static final String READ_VISIT_ANDROID_ID = "androidId";
+ private static final String READ_VISIT_OAID = "oaid";
+ private static final String READ_VISIT_GOOGLE_ADVERTISING_ID = "googleAdvertisingId";
+
+ private static final String READ_AND_REPLACE_TIMESTAMP = "timestamp";
+
+ private final TrackerInfo mTrackerInfo;
+ private final long mTimestamp;
+ private final boolean mReadProperty;
+
+ private final String mEventType;
+ private final int mSendPolicy;
+
+ private JSONObject mJsonObject;
+
+ public AnalyticsEvent(final BaseEvent baseEvent, final TrackerInfo trackerInfo) {
+ this(baseEvent, trackerInfo, 0L, false);
+ }
+
+ public AnalyticsEvent(final BaseEvent baseEvent, final TrackerInfo trackerInfo, final boolean readProperty) {
+ this(baseEvent, trackerInfo, 0L, readProperty);
+ }
+
+ public AnalyticsEvent(final BaseEvent baseEvent, final TrackerInfo trackerInfo, final long timestamp) {
+ this(baseEvent, trackerInfo, timestamp, false);
+ }
+
+ public AnalyticsEvent(final BaseEvent baseEvent, final TrackerInfo trackerInfo, final long timestamp, final boolean readProperty) {
+ // 空实现
+ super(new BaseBuilder() {
+ @Override
+ public String getEventType() {
+ return null;
+ }
+
+ @Override
+ public BaseEvent build() {
+ return null;
+ }
+ });
+
+ this.mTrackerInfo = trackerInfo;
+ this.mTimestamp = timestamp;
+ this.mReadProperty = readProperty;
+
+ this.mEventType = baseEvent.getEventType();
+ this.mSendPolicy = baseEvent.getSendPolicy();
+ this.mJsonObject = baseEvent.toJSONObject();
+
+ if (mReadProperty) {
+ readProperty();
+ }
+ }
+
+ private void readProperty() {
+ try {
+ readBaseProperty();
+
+ if (TrackEventType.VISIT.equals(mEventType)) {
+ DeviceInfoProvider deviceInfo = DeviceInfoProvider.get();
+ String imei = deviceInfo.getImei();
+ if (!TextUtils.isEmpty(imei)) {
+ mJsonObject.put(READ_VISIT_IMEI, imei);
+ }
+ String androidId = deviceInfo.getAndroidId();
+ if (!TextUtils.isEmpty(androidId)) {
+ mJsonObject.put(READ_VISIT_ANDROID_ID, androidId);
+ }
+ String oaid = deviceInfo.getOaid();
+ if (!TextUtils.isEmpty(oaid)) {
+ mJsonObject.put(READ_VISIT_OAID, oaid);
+ }
+// String googleAdvertisingId = "";
+// if (!TextUtils.isEmpty(googleAdvertisingId)) {
+// mJsonObject.put(READ_VISIT_GOOGLE_ADVERTISING_ID, googleAdvertisingId);
+// }
+ }
+ } catch (JSONException ignored) {
+
+ }
+ }
+
+ private void readBaseProperty() throws JSONException {
+ mJsonObject.put(READ_AND_REPLACE_TIMESTAMP, System.currentTimeMillis());
+ mJsonObject.put(READ_DEVICE_ID, DeviceInfoProvider.get().getDeviceId());
+
+ Context context = TrackerContext.get().getApplicationContext();
+ String netWorkState = FieldIgnoreFilter.isFieldFilter("networkState") ? "" : NetworkUtil.getActiveNetworkState(context).getNetworkName();
+ if (!TextUtils.isEmpty(netWorkState)) {
+ mJsonObject.put(READ_NETWORK_STATE, netWorkState);
+ }
+
+ DeviceInfoProvider deviceInfo = DeviceInfoProvider.get();
+ int screenHeight = FieldIgnoreFilter.isFieldFilter("screenHeight") ? 0 : deviceInfo.getScreenHeight();
+ if (screenHeight > 0) {
+ mJsonObject.put(READ_SCREEN_HEIGHT, screenHeight);
+ }
+ int screenWidth = FieldIgnoreFilter.isFieldFilter("screenWidth") ? 0 : deviceInfo.getScreenWidth();
+ if (screenWidth > 0) {
+ mJsonObject.put(READ_SCREEN_WIDTH, screenWidth);
+ }
+ String deviceBrand = FieldIgnoreFilter.isFieldFilter("deviceBrand") ? "" : deviceInfo.getDeviceBrand();
+ if (!TextUtils.isEmpty(deviceBrand)) {
+ mJsonObject.put(READ_DEVICE_BRAND, deviceBrand);
+ }
+ String deviceModel = FieldIgnoreFilter.isFieldFilter("deviceModel") ? "" : deviceInfo.getDeviceModel();
+ if (!TextUtils.isEmpty(deviceModel)) {
+ mJsonObject.put(READ_DEVICE_MODEL, deviceModel);
+ }
+ String deviceType = FieldIgnoreFilter.isFieldFilter("deviceType") ? "" : deviceInfo.getDeviceType();
+ if (!TextUtils.isEmpty(deviceType)) {
+ mJsonObject.put(READ_DEVICE_TYPE, deviceType);
+ }
+
+ AppInfoProvider appInfo = AppInfoProvider.get();
+ String appChannel = appInfo.getAppChannel();
+ if (!TextUtils.isEmpty(appChannel)) {
+ mJsonObject.put(READ_APP_CHANNEL, appChannel);
+ }
+ mJsonObject.put(READ_APP_NAME, appInfo.getAppName());
+ mJsonObject.put(READ_APP_VERSION, appInfo.getAppVersion());
+
+ SessionProvider session = SessionProvider.get();
+ double latitude = session.getLatitude();
+ double longitude = session.getLongitude();
+ if (latitude != 0 || longitude != 0) {
+ mJsonObject.put(READ_LATITUDE, latitude);
+ mJsonObject.put(READ_LONGITUDE, longitude);
+ }
+
+ mJsonObject.put(READ_SDK_VERSION, SDKConfig.SDK_VERSION);
+ mJsonObject.put(READ_LANGUAGE, Locale.getDefault().getLanguage());
+ }
+
+ @Override
+ public String getEventType() {
+ return mEventType;
+ }
+
+ @Override
+ public int getSendPolicy() {
+ return mSendPolicy;
+ }
+
+ @Override
+ public JSONObject toJSONObject() {
+ try {
+ // 如果存在则移除 userKey 字段
+ mJsonObject.remove(REPLACE_USER_KEY);
+ // 如果存在则移除 esid、gesid 字段
+ mJsonObject.remove(REPLACE_GLOBAL_SEQUENCE_ID);
+ mJsonObject.remove(REPLACE_EVENT_SEQUENCE_ID);
+
+ // 替换 / 增加 gioId
+ mJsonObject.put(REPLACE_GIO_ID, mTrackerInfo.getLastUserId());
+ // 替换 / 增加 dataSourceId
+ mJsonObject.put(REPLACE_DATASOURCE_ID, mTrackerInfo.getDatasourceId());
+ // 替换 / 增加 sessionId
+ mJsonObject.put(REPLACE_SESSION_ID, mTrackerInfo.getSessionId());
+ // 替换 / 增加 userId
+ mJsonObject.put(REPLACE_USER_ID, mTrackerInfo.getUserId());
+ // 如果 timestamp 不为0L,替换 / 增加 timestamp
+ if (mTimestamp != 0L) {
+ mJsonObject.put(READ_AND_REPLACE_TIMESTAMP, mTimestamp);
+ }
+
+ // custom需要处理 通用参数
+ if (TrackEventType.CUSTOM.equals(mEventType)) {
+ JSONObject attributes = mJsonObject.optJSONObject(REPLACE_ATTRIBUTES);
+ if (attributes == null) {
+ attributes = new JSONObject();
+ }
+
+ for (Map.Entry attr : mTrackerInfo.getParams().entrySet()) {
+ // 如果与send设置的字段冲突,优先使用send方法中设置的字段值
+ String attrKey = attr.getKey();
+ if (attrKey != null && !attributes.has(attrKey)) {
+ attributes.put(attr.getKey(), attr.getValue());
+ }
+ }
+ }
+
+ // 不直接返回 jsonObject, 避免 被 拦截器修改 mobile debugger
+ return new JSONObject(mJsonObject.toString());
+ } catch (JSONException ignored) {
+ }
+
+ return new JSONObject();
+ }
+}
diff --git a/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/model/TrackerInfo.java b/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/model/TrackerInfo.java
new file mode 100644
index 00000000..456b785a
--- /dev/null
+++ b/growingio-adapter/analytics-ga/src/main/java/com/growingio/android/analytics/google/model/TrackerInfo.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2020 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.analytics.google.model;
+
+import android.text.TextUtils;
+
+import com.growingio.android.sdk.track.events.EventBuildInterceptor;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class TrackerInfo {
+ private String mSessionId;
+ private String mDataSourceId;
+ private String mUserId;
+ private String mLastUserId;
+ private String mClientId;
+ private Map extraParams;
+ private EventBuildInterceptor mEventBuildInterceptor;
+
+ public TrackerInfo(String datasourceId, String sessionId) {
+ this.mDataSourceId = datasourceId;
+ this.mSessionId = sessionId;
+ this.extraParams = new HashMap<>();
+ }
+
+ public String getSessionId() {
+ return mSessionId;
+ }
+
+ public void setSessionId(String sessionId) {
+ this.mSessionId = sessionId;
+ }
+
+ public String getDatasourceId() {
+ return mDataSourceId;
+ }
+
+ public void setDatasourceId(String datasource) {
+ this.mDataSourceId = datasource;
+ }
+
+ public String getUserId() {
+ return mUserId;
+ }
+
+ public void setUserId(String userId) {
+ this.mUserId = userId;
+ }
+
+ public String getLastUserId() {
+ return mLastUserId;
+ }
+
+ public void setLastUserId(String mLastUserId) {
+ this.mLastUserId = mLastUserId;
+ }
+
+ public String getClientId() {
+ return mClientId;
+ }
+
+ public void setClientId(String clientId) {
+ this.mClientId = clientId;
+ }
+
+ public EventBuildInterceptor getEventBuildInterceptor() {
+ return mEventBuildInterceptor;
+ }
+
+ public void setEventBuildInterceptor(EventBuildInterceptor mEventBuildInterceptor) {
+ this.mEventBuildInterceptor = mEventBuildInterceptor;
+ }
+
+ public void addParam(String key, String value) {
+ if (TextUtils.isEmpty(key)) {
+ return;
+ }
+ if (value == null) {
+ extraParams.remove(key);
+ return;
+ }
+ extraParams.put(key, value);
+ }
+
+ public Map getParams() {
+ return extraParams;
+ }
+}
diff --git a/growingio-adapter/build.gradle b/growingio-adapter/build.gradle
new file mode 100644
index 00000000..d4e8437e
--- /dev/null
+++ b/growingio-adapter/build.gradle
@@ -0,0 +1 @@
+// keep an empty file to make sure Gradle recognizes the properties
diff --git a/growingio-autotracker-core/build.gradle b/growingio-autotracker-core/build.gradle
index 25a0df66..610dfa31 100644
--- a/growingio-autotracker-core/build.gradle
+++ b/growingio-autotracker-core/build.gradle
@@ -42,16 +42,6 @@ android {
lintOptions {
abortOnError false
}
-
- defaultConfig {
- javaCompileOptions {
- annotationProcessorOptions {
- arguments = [
- GRADLE_PLUGIN_DIR : ("$rootDir/growingio-autotracker-gradle-plugin".toString())
- ]
- }
- }
- }
}
dependencies {
@@ -72,10 +62,8 @@ dependencies {
debugApi project(':growingio-tracker-core')
releaseApi libraries.growingio.tracker_core
- implementation project(':inject-annotation')
- annotationProcessor project(':inject-annotation:compiler')
-
compileOnly libraries.androidx.appcompat
+ compileOnly libraries.androidx.material
compileOnly libraries.androidx.recyclerview
compileOnly libraries.android.appcompat
compileOnly libraries.android.recyclerview
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/click/ViewClickInjector.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/click/ViewClickInjector.java
deleted file mode 100644
index 39f2a3fa..00000000
--- a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/click/ViewClickInjector.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (C) 2020 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.sdk.autotrack.click;
-
-import android.accounts.AccountAuthenticatorActivity;
-import android.app.Activity;
-import android.app.ActivityGroup;
-import android.app.AlertDialog;
-import android.app.AliasActivity;
-import android.app.ExpandableListActivity;
-import android.app.LauncherActivity;
-import android.app.ListActivity;
-import android.app.NativeActivity;
-import android.app.TabActivity;
-import android.content.DialogInterface;
-import android.preference.PreferenceActivity;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ActionMenuView;
-import android.widget.AdapterView;
-import android.widget.CompoundButton;
-import android.widget.ExpandableListView;
-import android.widget.ListView;
-import android.widget.PopupMenu;
-import android.widget.RadioGroup;
-import android.widget.RatingBar;
-import android.widget.SeekBar;
-import android.widget.Spinner;
-import android.widget.Toolbar;
-
-import com.growingio.sdk.inject.annotation.After;
-import com.growingio.sdk.inject.annotation.BeforeSuper;
-
-public class ViewClickInjector {
- private static final String TAG = "ViewClickInjector";
-
- private ViewClickInjector() {
- }
-
- @BeforeSuper(clazz = View.OnClickListener.class, method = "onClick", parameterTypes = {View.class})
- public static void viewOnClick(View.OnClickListener listener, View view) {
- ViewClickProvider.viewOnClick(view);
- }
-
- @After(clazz = AlertDialog.class, method = "show")
- public static void alertDialogShow(AlertDialog alertDialog) {
- ViewClickProvider.alertDialogShow(alertDialog);
- }
-
- @BeforeSuper(clazz = DialogInterface.OnClickListener.class, method = "onClick", parameterTypes = {DialogInterface.class, int.class})
- public static void dialogOnClick(DialogInterface.OnClickListener listener, DialogInterface dialogInterface, int which) {
- if (dialogInterface instanceof AlertDialog) {
- ViewClickProvider.alertDialogOnClick((AlertDialog) dialogInterface, which);
- }
- }
-
- @BeforeSuper(clazz = AdapterView.OnItemClickListener.class, method = "onItemClick", parameterTypes = {AdapterView.class, View.class, int.class, long.class})
- public static void adapterViewOnItemClick(AdapterView.OnItemClickListener listener, AdapterView adapterView, View view, int position, long id) {
- ViewClickProvider.viewOnClick(view);
- }
-
- @BeforeSuper(clazz = AdapterView.OnItemSelectedListener.class, method = "onItemSelected", parameterTypes = {AdapterView.class, View.class, int.class, long.class})
- public static void adapterViewOnItemSelected(AdapterView.OnItemSelectedListener listener, AdapterView adapterView, View view, int position, long id) {
- if (adapterView instanceof Spinner) {
- // 目前只需要将Spinner的onItemSelected回调触发点击事件,因为Spinner的元素点击只会触发onItemSelected回调
- ViewClickProvider.viewOnClick(view);
- }
- }
-
- @BeforeSuper(clazz = ExpandableListView.OnGroupClickListener.class, method = "onGroupClick", parameterTypes = {ExpandableListView.class, View.class, int.class, long.class}, returnType = boolean.class)
- public static void expandableListViewOnGroupClick(ExpandableListView.OnGroupClickListener listener, ExpandableListView parent, View v, int groupPosition, long id) {
- ViewClickProvider.viewOnClick(v);
- }
-
- @BeforeSuper(clazz = ExpandableListView.OnChildClickListener.class, method = "onChildClick", parameterTypes = {ExpandableListView.class, View.class, int.class, int.class, long.class}, returnType = boolean.class)
- public static void expandableListViewOnChildClick(ExpandableListView.OnChildClickListener listener, ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
- ViewClickProvider.viewOnClick(v);
- }
-
- @BeforeSuper(clazz = ExpandableListActivity.class, method = "onChildClick", parameterTypes = {ExpandableListView.class, View.class, int.class, int.class, long.class}, returnType = boolean.class)
- public static void expandableListActivityOnChildClick(ExpandableListActivity activity, ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
- ViewClickProvider.viewOnClick(v);
- }
-
- @BeforeSuper(clazz = ListActivity.class, method = "onListItemClick", parameterTypes = {ListView.class, View.class, int.class, long.class})
- public static void listActivityOnListItemClick(ListActivity activity, ListView listView, View view, int position, long id) {
- ViewClickProvider.viewOnClick(view);
- }
-
- @BeforeSuper(clazz = CompoundButton.OnCheckedChangeListener.class, method = "onCheckedChanged", parameterTypes = {CompoundButton.class, boolean.class})
- public static void compoundButtonOnChecked(CompoundButton.OnCheckedChangeListener listener, CompoundButton button, boolean checked) {
- ViewClickProvider.viewOnClick(button);
- }
-
- @BeforeSuper(clazz = RadioGroup.OnCheckedChangeListener.class, method = "onCheckedChanged", parameterTypes = {RadioGroup.class, int.class})
- public static void radioGroupOnChecked(RadioGroup.OnCheckedChangeListener listener, RadioGroup radioGroup, int i) {
- ViewClickProvider.viewOnClick(radioGroup.findViewById(radioGroup.getCheckedRadioButtonId()));
- }
-
- @BeforeSuper(clazz = RatingBar.OnRatingBarChangeListener.class, method = "onRatingChanged", parameterTypes = {RatingBar.class, float.class, boolean.class})
- public static void ratingBarOnRatingBarChange(RatingBar.OnRatingBarChangeListener listener, RatingBar ratingBar, float rating, boolean fromUser) {
- if (fromUser) {
- ViewClickProvider.viewOnClick(ratingBar);
- }
- }
-
- @BeforeSuper(clazz = SeekBar.OnSeekBarChangeListener.class, method = "onStopTrackingTouch", parameterTypes = {SeekBar.class})
- public static void seekBarOnSeekBarChange(SeekBar.OnSeekBarChangeListener listener, SeekBar seekBar) {
- ViewClickProvider.viewOnClick(seekBar);
- }
-
- @BeforeSuper(clazz = Toolbar.OnMenuItemClickListener.class, method = "onMenuItemClick", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- public static void toolbarOnMenuItemClick(Toolbar.OnMenuItemClickListener listener, MenuItem item) {
- ViewClickProvider.menuItemOnClick(item);
- }
-
- @BeforeSuper(clazz = ActionMenuView.OnMenuItemClickListener.class, method = "onMenuItemClick", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- public static void actionMenuViewOnMenuItemClick(ActionMenuView.OnMenuItemClickListener listener, MenuItem item) {
- ViewClickProvider.menuItemOnClick(item);
- }
-
- @BeforeSuper(clazz = PopupMenu.OnMenuItemClickListener.class, method = "onMenuItemClick", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- public static void popupMenuOnMenuItemClick(PopupMenu.OnMenuItemClickListener listener, MenuItem item) {
- ViewClickProvider.menuItemOnClick(item);
- }
-
- @BeforeSuper(clazz = Activity.class, method = "onOptionsItemSelected", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- @BeforeSuper(clazz = AccountAuthenticatorActivity.class, method = "onOptionsItemSelected", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- @BeforeSuper(clazz = ActivityGroup.class, method = "onOptionsItemSelected", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- @BeforeSuper(clazz = AliasActivity.class, method = "onOptionsItemSelected", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- @BeforeSuper(clazz = ExpandableListActivity.class, method = "onOptionsItemSelected", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- @BeforeSuper(clazz = LauncherActivity.class, method = "onOptionsItemSelected", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- @BeforeSuper(clazz = ListActivity.class, method = "onOptionsItemSelected", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- @BeforeSuper(clazz = NativeActivity.class, method = "onOptionsItemSelected", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- @BeforeSuper(clazz = TabActivity.class, method = "onOptionsItemSelected", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- @BeforeSuper(clazz = PreferenceActivity.class, method = "onOptionsItemSelected", parameterTypes = {MenuItem.class}, returnType = boolean.class)
- public static void menuItemOnOptionsItemSelected(Activity activity, MenuItem item) {
- ViewClickProvider.menuItemOnClick(activity, item);
- }
-}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/click/ViewClickProvider.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/click/ViewClickProvider.java
deleted file mode 100644
index 05dec5b0..00000000
--- a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/click/ViewClickProvider.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright (C) 2020 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.sdk.autotrack.click;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
-import android.text.TextUtils;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.Button;
-import android.widget.ListView;
-
-import com.growingio.android.sdk.TrackerContext;
-import com.growingio.android.sdk.track.events.AutotrackEventType;
-import com.growingio.android.sdk.track.events.ViewElementEvent;
-import com.growingio.android.sdk.autotrack.page.Page;
-import com.growingio.android.sdk.autotrack.page.PageProvider;
-import com.growingio.android.sdk.autotrack.shadow.AlertControllerShadow;
-import com.growingio.android.sdk.autotrack.util.ClassUtil;
-import com.growingio.android.sdk.autotrack.view.ViewAttributeUtil;
-import com.growingio.android.sdk.autotrack.view.ViewHelper;
-import com.growingio.android.sdk.autotrack.view.ViewNode;
-import com.growingio.android.sdk.track.TrackMainThread;
-import com.growingio.android.sdk.track.log.Logger;
-import com.growingio.android.sdk.track.providers.ActivityStateProvider;
-import com.growingio.android.sdk.track.utils.ThreadUtils;
-
-class ViewClickProvider {
- private static final String TAG = "ViewClickProvider";
- private static final int[] DIALOG_BUTTON_IDS = new int[]{DialogInterface.BUTTON_NEUTRAL, DialogInterface.BUTTON_NEGATIVE, DialogInterface.BUTTON_POSITIVE};
- private static final String[] DIALOG_BUTTON_NAMES = new String[]{"BUTTON_NEUTRAL", "BUTTON_NEGATIVE", "BUTTON_POSITIVE"};
-
- private ViewClickProvider() {
- }
-
- public static void alertDialogOnClick(AlertDialog dialog, int which) {
- Logger.d(TAG, "alertDialogOnClick: which = " + which);
- if (which < 0) {
- Button button = dialog.getButton(which);
- if (button != null) {
- viewOnClick(button);
- }
- } else {
- ListView listView = dialog.getListView();
- if (listView != null) {
- viewOnClick(listView.getChildAt(which - listView.getFirstVisiblePosition()));
- }
- }
- }
-
- /**
- * 由于Android的不同版本的AlertDialog实现机制不一样,导致view xpath也不一样,如
- * Android 7.0之前 /DialogWindow/DecorView/FrameLayout[0]/FrameLayout[0]/LinearLayout[0]/LinearLayout[2]/LinearLayout[0]/Button[2]
- * Android 7,0及其之后 /DialogWindow/DecorView/FrameLayout[0]/FrameLayout[0]/AlertDialogLayout[0]/ScrollView[0]/ButtonBarLayout[0]/Button[2]
- * 所以这里人为的给view定义一个id
- */
- public static void alertDialogShow(AlertDialog dialog) {
- if (!TrackerContext.initializedSuccessfully()) {
- Logger.e(TAG, "Autotracker do not initialized successfully");
- return;
- }
-
- if (dialog == null) {
- Logger.d(TAG, "alertDialogShow: dialog is NULL");
- return;
- }
-
- Logger.d(TAG, "alertDialogShow: " + dialog);
- for (int i = 0; i < DIALOG_BUTTON_IDS.length; i++) {
- Button button = dialog.getButton(DIALOG_BUTTON_IDS[i]);
- if (button != null && TextUtils.isEmpty(ViewAttributeUtil.getCustomId(button))) {
- String dialogButtonName = DIALOG_BUTTON_NAMES[i];
- ThreadUtils.runOnUiThread(new Runnable() {
- @Override
- public void run() {
- ViewAttributeUtil.setCustomId(button, getAlertDialogName(dialog) + "/" + dialogButtonName);
- }
- });
- }
- }
-
- // TODO: 2020/10/10 list dialog等也要处理
- }
-
- private static String getAlertDialogName(AlertDialog dialog) {
- String className = ClassUtil.getSimpleClassName(dialog.getClass());
- try {
- AlertControllerShadow alertControllerShadow = new AlertControllerShadow(dialog);
- CharSequence title = alertControllerShadow.getTitle();
- if (!TextUtils.isEmpty(title)) {
- return className + "/" + title;
- }
-
- CharSequence message = alertControllerShadow.getMessage();
- if (!TextUtils.isEmpty(message)) {
- return className + "/" + message;
- }
- } catch (Exception e) {
- Logger.e(TAG, e);
- }
- return className;
- }
-
- public static void viewOnClick(View view) {
- if (!TrackerContext.initializedSuccessfully()) {
- Logger.e(TAG, "Autotracker do not initialized successfully");
- return;
- }
-
- ViewNode viewNode = ViewHelper.getClickViewNode(view);
- if (viewNode != null) {
- Page> page = PageProvider.get().findPage(view);
- sendClickEvent(page, viewNode);
- } else {
- Logger.e(TAG, "ViewNode is NULL");
- }
- }
-
- public static void menuItemOnClick(Activity activity, MenuItem menuItem) {
- if (!TrackerContext.initializedSuccessfully()) {
- Logger.e(TAG, "Autotracker do not initialized successfully");
- return;
- }
- if (activity == null || menuItem == null) {
- Logger.e(TAG, "menuItemOnClick: activity or menuItem is NULL");
- return;
- }
-
- Page> page = PageProvider.get().findPage(activity);
- ViewNode viewNode = ViewHelper.getMenuItemViewNode(page, menuItem);
- if (viewNode != null) {
- sendClickEvent(page, viewNode);
- } else {
- Logger.e(TAG, "MenuItem ViewNode is NULL");
- }
- }
-
- public static void menuItemOnClick(MenuItem menuItem) {
- if (!TrackerContext.initializedSuccessfully()) {
- Logger.e(TAG, "Autotracker do not initialized successfully");
- return;
- }
-
- Activity activity = ActivityStateProvider.get().getForegroundActivity();
- menuItemOnClick(activity, menuItem);
- }
-
- private static void sendClickEvent(Page> page, ViewNode viewNode) {
- if (page == null) {
- Logger.e(TAG, "sendClickEvent page Activity is NULL");
- return;
- }
- TrackMainThread.trackMain().postEventToTrackMain(
- new ViewElementEvent.Builder()
- .setEventType(AutotrackEventType.VIEW_CLICK)
- .setPath(page.path())
- .setPageShowTimestamp(page.getShowTimestamp())
- .setXpath(viewNode.getXPath())
- .setIndex(viewNode.getIndex())
- .setTextValue(viewNode.getViewContent())
- );
- }
-}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/ActivityInjector.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/ActivityInjector.java
index a86d1af0..161a057c 100644
--- a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/ActivityInjector.java
+++ b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/ActivityInjector.java
@@ -16,36 +16,34 @@
package com.growingio.android.sdk.autotrack.inject;
-import android.accounts.AccountAuthenticatorActivity;
import android.app.Activity;
-import android.app.ActivityGroup;
-import android.app.AliasActivity;
import android.app.ExpandableListActivity;
-import android.app.LauncherActivity;
import android.app.ListActivity;
-import android.app.NativeActivity;
-import android.app.TabActivity;
import android.content.Intent;
-import android.preference.PreferenceActivity;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ExpandableListView;
+import android.widget.ListView;
import com.growingio.android.sdk.track.providers.ActivityStateProvider;
-import com.growingio.sdk.inject.annotation.BeforeSuper;
public class ActivityInjector {
private ActivityInjector() {
}
- @BeforeSuper(clazz = Activity.class, method = "onNewIntent", parameterTypes = {Intent.class})
- @BeforeSuper(clazz = AccountAuthenticatorActivity.class, method = "onNewIntent", parameterTypes = {Intent.class})
- @BeforeSuper(clazz = ActivityGroup.class, method = "onNewIntent", parameterTypes = {Intent.class})
- @BeforeSuper(clazz = AliasActivity.class, method = "onNewIntent", parameterTypes = {Intent.class})
- @BeforeSuper(clazz = ExpandableListActivity.class, method = "onNewIntent", parameterTypes = {Intent.class})
- @BeforeSuper(clazz = LauncherActivity.class, method = "onNewIntent", parameterTypes = {Intent.class})
- @BeforeSuper(clazz = ListActivity.class, method = "onNewIntent", parameterTypes = {Intent.class})
- @BeforeSuper(clazz = NativeActivity.class, method = "onNewIntent", parameterTypes = {Intent.class})
- @BeforeSuper(clazz = TabActivity.class, method = "onNewIntent", parameterTypes = {Intent.class})
- @BeforeSuper(clazz = PreferenceActivity.class, method = "onNewIntent", parameterTypes = {Intent.class})
public static void onActivityNewIntent(Activity activity, Intent intent) {
ActivityStateProvider.get().onActivityNewIntent(activity, intent);
}
+
+ public static void menuItemOnOptionsItemSelected(Activity activity, MenuItem item) {
+ ViewClickProvider.menuItemOnClick(activity, item);
+ }
+
+ public static void expandableListActivityOnChildClick(ExpandableListActivity activity, ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
+ ViewClickProvider.viewOnClick(v);
+ }
+
+ public static void listActivityOnListItemClick(ListActivity activity, ListView listView, View view, int position, long id) {
+ ViewClickProvider.viewOnClick(view);
+ }
}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/DialogClickProvider.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/DialogClickProvider.java
new file mode 100644
index 00000000..dbb16e5d
--- /dev/null
+++ b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/DialogClickProvider.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2020 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.sdk.autotrack.inject;
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.text.TextUtils;
+import android.widget.Button;
+import android.widget.ListView;
+
+import com.growingio.android.sdk.TrackerContext;
+import com.growingio.android.sdk.autotrack.shadow.AlertControllerShadow;
+import com.growingio.android.sdk.autotrack.util.ClassUtil;
+import com.growingio.android.sdk.autotrack.view.ViewAttributeUtil;
+import com.growingio.android.sdk.track.log.Logger;
+import com.growingio.android.sdk.track.utils.ThreadUtils;
+
+class DialogClickProvider {
+ private static final String TAG = "DialogClickProvider";
+ private static final int[] DIALOG_BUTTON_IDS = new int[]{DialogInterface.BUTTON_NEUTRAL, DialogInterface.BUTTON_NEGATIVE, DialogInterface.BUTTON_POSITIVE};
+ private static final String[] DIALOG_BUTTON_NAMES = new String[]{"BUTTON_NEUTRAL", "BUTTON_NEGATIVE", "BUTTON_POSITIVE"};
+
+ private DialogClickProvider() {
+ }
+
+ /**
+ * 同版本下appcompat 包下的xpath应该也会一样。
+ */
+ public static void alertDialogXOnClick(androidx.appcompat.app.AlertDialog dialog, int which) {
+ Logger.d(TAG, "alertDialogXOnClick: which = " + which);
+ if (which < 0) {
+ Button button = dialog.getButton(which);
+ if (button != null) {
+ ViewClickProvider.viewOnClick(button);
+ }
+ } else {
+ ListView listView = dialog.getListView();
+ if (listView != null) {
+ ViewClickProvider.viewOnClick(listView.getChildAt(which - listView.getFirstVisiblePosition()));
+ }
+ }
+ }
+
+ public static void alertDialogSupportOnClick(android.support.v7.app.AlertDialog dialog, int which) {
+ Logger.d(TAG, "alertDialogSupportOnClick: which = " + which);
+ if (which < 0) {
+ Button button = dialog.getButton(which);
+ if (button != null) {
+ ViewClickProvider.viewOnClick(button);
+ }
+ } else {
+ ListView listView = dialog.getListView();
+ if (listView != null) {
+ ViewClickProvider.viewOnClick(listView.getChildAt(which - listView.getFirstVisiblePosition()));
+ }
+ }
+ }
+
+ public static void alertDialogOnClick(AlertDialog dialog, int which) {
+ Logger.d(TAG, "alertDialogOnClick: which = " + which);
+ if (which < 0) {
+ Button button = dialog.getButton(which);
+ if (button != null) {
+ ViewClickProvider.viewOnClick(button);
+ }
+ } else {
+ ListView listView = dialog.getListView();
+ if (listView != null) {
+ ViewClickProvider.viewOnClick(listView.getChildAt(which - listView.getFirstVisiblePosition()));
+ }
+ }
+ }
+
+ /**
+ * 由于Android的不同版本的AlertDialog实现机制不一样,导致view xpath也不一样,如
+ * Android 7.0之前 /DialogWindow/DecorView/FrameLayout[0]/FrameLayout[0]/LinearLayout[0]/LinearLayout[2]/LinearLayout[0]/Button[2]
+ * Android 7,0及其之后 /DialogWindow/DecorView/FrameLayout[0]/FrameLayout[0]/AlertDialogLayout[0]/ScrollView[0]/ButtonBarLayout[0]/Button[2]
+ * 所以这里人为的给view定义一个id
+ */
+ public static void alertDialogShow(AlertDialog dialog) {
+ if (!TrackerContext.initializedSuccessfully()) {
+ Logger.e(TAG, "Autotracker do not initialized successfully");
+ return;
+ }
+
+ if (dialog == null) {
+ Logger.d(TAG, "alertDialogShow: dialog is NULL");
+ return;
+ }
+
+ Logger.d(TAG, "alertDialogShow: " + dialog);
+ for (int i = 0; i < DIALOG_BUTTON_IDS.length; i++) {
+ Button button = dialog.getButton(DIALOG_BUTTON_IDS[i]);
+ if (button != null && TextUtils.isEmpty(ViewAttributeUtil.getCustomId(button))) {
+ String dialogButtonName = DIALOG_BUTTON_NAMES[i];
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ ViewAttributeUtil.setCustomId(button, getAlertDialogName(dialog) + "/" + dialogButtonName);
+ }
+ });
+ }
+ }
+
+ // TODO: 2020/10/10 list dialog等也要处理
+ }
+
+ private static String getAlertDialogName(AlertDialog dialog) {
+ String className = ClassUtil.getSimpleClassName(dialog.getClass());
+ try {
+ AlertControllerShadow alertControllerShadow = new AlertControllerShadow(dialog);
+ CharSequence title = alertControllerShadow.getTitle();
+ if (!TextUtils.isEmpty(title)) {
+ return className + "/" + title;
+ }
+
+ CharSequence message = alertControllerShadow.getMessage();
+ if (!TextUtils.isEmpty(message)) {
+ return className + "/" + message;
+ }
+ } catch (Exception e) {
+ Logger.e(TAG, e);
+ }
+ return className;
+ }
+}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/DialogInjector.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/DialogInjector.java
new file mode 100644
index 00000000..4e9d32a6
--- /dev/null
+++ b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/DialogInjector.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 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.sdk.autotrack.inject;
+
+
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+
+import com.growingio.android.sdk.track.utils.ClassExistHelper;
+
+
+public class DialogInjector {
+
+ private DialogInjector() {
+ }
+
+ public static void alertDialogShow(AlertDialog alertDialog) {
+ DialogClickProvider.alertDialogShow(alertDialog);
+ }
+
+ public static void dialogOnClick(DialogInterface.OnClickListener listener, DialogInterface dialogInterface, int which) {
+ if (dialogInterface instanceof AlertDialog) {
+ DialogClickProvider.alertDialogOnClick((AlertDialog) dialogInterface, which);
+ } else if (ClassExistHelper.instanceOfAndroidXAlertDialog(dialogInterface)) {
+ DialogClickProvider.alertDialogXOnClick((androidx.appcompat.app.AlertDialog) dialogInterface, which);
+ } else if (ClassExistHelper.instanceOfSupportAlertDialog(dialogInterface)) {
+ DialogClickProvider.alertDialogSupportOnClick((android.support.v7.app.AlertDialog) dialogInterface, which);
+ }
+ }
+}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/FragmentInjector.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/FragmentInjector.java
new file mode 100644
index 00000000..26063335
--- /dev/null
+++ b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/FragmentInjector.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2020 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.sdk.autotrack.inject;
+
+import com.growingio.android.sdk.autotrack.page.PageProvider;
+import com.growingio.android.sdk.autotrack.page.SuperFragment;
+import com.growingio.android.sdk.track.log.Logger;
+
+public class FragmentInjector {
+ private static final String TAG = "FragmentInjector";
+
+ private FragmentInjector() {
+ }
+
+ public static void systemFragmentOnResume(android.app.Fragment fragment) {
+ Logger.d(TAG, "systemFragmentOnResume: fragment = " + fragment.getClass().getName());
+ PageProvider.get().createOrResumePage(SuperFragment.make(fragment));
+ }
+
+ public static void systemFragmentSetUserVisibleHint(android.app.Fragment fragment, boolean isVisibleToUser) {
+ Logger.d(TAG, "systemFragmentSetUserVisibleHint: fragment = " + fragment.getClass().getName() + ", isVisibleToUser = " + isVisibleToUser);
+ if (isVisibleToUser) {
+ PageProvider.get().createOrResumePage(SuperFragment.make(fragment));
+ }
+ }
+
+ public static void systemFragmentOnHiddenChanged(android.app.Fragment fragment, boolean hidden) {
+ Logger.d(TAG, "systemFragmentOnHiddenChanged: fragment = " + fragment.getClass().getName() + ", hidden" + hidden);
+ PageProvider.get().fragmentOnHiddenChanged(SuperFragment.make(fragment), hidden);
+ }
+
+ public static void systemFragmentOnDestroyView(android.app.Fragment fragment) {
+ Logger.d(TAG, "systemFragmentOnDestroyView: fragment = " + fragment.getClass().getName());
+ PageProvider.get().removePage(SuperFragment.make(fragment));
+ }
+
+ public static void androidxFragmentOnResume(androidx.fragment.app.Fragment fragment) {
+ Logger.d(TAG, "androidxFragmentOnResume: fragment = " + fragment.getClass().getName());
+ PageProvider.get().createOrResumePage(SuperFragment.makeX(fragment));
+ }
+
+ /**
+ * 新版本的AndroidX Fragment setUserVisibleHint 将通过 FragmentTransaction setMaxLifecycle 来控制生命周期实现
+ */
+ @Deprecated
+ public static void androidxFragmentSetUserVisibleHint(androidx.fragment.app.Fragment fragment, boolean isVisibleToUser) {
+ Logger.d(TAG, "androidxFragmentSetUserVisibleHint: fragment = " + fragment.getClass().getName() + ", isVisibleToUser = " + isVisibleToUser);
+ if (isVisibleToUser) {
+ PageProvider.get().createOrResumePage(SuperFragment.makeX(fragment));
+ }
+ }
+
+ public static void androidxFragmentOnHiddenChanged(androidx.fragment.app.Fragment fragment, boolean hidden) {
+ Logger.d(TAG, "androidxFragmentOnHiddenChanged: fragment = " + fragment.getClass().getName() + ", hidden" + hidden);
+ PageProvider.get().fragmentOnHiddenChanged(SuperFragment.makeX(fragment), hidden);
+ }
+
+ public static void androidxFragmentOnDestroyView(androidx.fragment.app.Fragment fragment) {
+ Logger.d(TAG, "androidxFragmentOnDestroyView: fragment = " + fragment.getClass().getName());
+ PageProvider.get().removePage(SuperFragment.makeX(fragment));
+ }
+
+}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/FragmentV4Injector.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/FragmentV4Injector.java
new file mode 100644
index 00000000..42669767
--- /dev/null
+++ b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/FragmentV4Injector.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 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.sdk.autotrack.inject;
+
+import com.growingio.android.sdk.autotrack.page.PageProvider;
+import com.growingio.android.sdk.autotrack.page.SuperFragment;
+import com.growingio.android.sdk.track.log.Logger;
+
+public class FragmentV4Injector {
+ private static final String TAG = "FragmentV4Injector";
+
+ private FragmentV4Injector() {
+ }
+
+ public static void v4FragmentOnResume(android.support.v4.app.Fragment fragment) {
+ Logger.d(TAG, "v4FragmentOnResume: fragment = " + fragment.getClass().getName());
+ PageProvider.get().createOrResumePage(SuperFragment.makeSupport(fragment));
+ }
+
+ public static void v4FragmentSetUserVisibleHint(android.support.v4.app.Fragment fragment, boolean isVisibleToUser) {
+ Logger.d(TAG, "v4FragmentSetUserVisibleHint: fragment = " + fragment.getClass().getName() + ", isVisibleToUser = " + isVisibleToUser);
+ if (isVisibleToUser) {
+ PageProvider.get().createOrResumePage(SuperFragment.makeSupport(fragment));
+ }
+ }
+
+ public static void v4FragmentOnHiddenChanged(android.support.v4.app.Fragment fragment, boolean hidden) {
+ Logger.d(TAG, "v4FragmentOnHiddenChanged: fragment = " + fragment.getClass().getName() + ", hidden = " + hidden);
+ PageProvider.get().fragmentOnHiddenChanged(SuperFragment.makeSupport(fragment), hidden);
+ }
+
+ public static void v4FragmentOnDestroyView(android.support.v4.app.Fragment fragment) {
+ Logger.d(TAG, "v4FragmentOnDestroyView: fragment = " + fragment.getClass().getName());
+ PageProvider.get().removePage(SuperFragment.makeSupport(fragment));
+ }
+}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/MenuItemInjector.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/MenuItemInjector.java
new file mode 100644
index 00000000..140a758d
--- /dev/null
+++ b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/MenuItemInjector.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 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.sdk.autotrack.inject;
+
+import android.view.MenuItem;
+import android.widget.ActionMenuView;
+import android.widget.PopupMenu;
+import android.widget.Toolbar;
+
+public class MenuItemInjector {
+ private static final String TAG = "MenuItemInjector";
+
+ private MenuItemInjector() {
+ }
+
+ public static void toolbarOnMenuItemClick(Toolbar.OnMenuItemClickListener listener, MenuItem item) {
+ ViewClickProvider.menuItemOnClick(item);
+ }
+/*
+ public static void toolbarXOnMenuItemClick(androidx.appcompat.widget.Toolbar.OnMenuItemClickListener listener, MenuItem item) {
+ ViewClickProvider.menuItemOnClick(item);
+ }
+
+ public static void toolbarSupportOnMenuItemClick(android.support.v7.widget.Toolbar.OnMenuItemClickListener listener, MenuItem item) {
+ ViewClickProvider.menuItemOnClick(item);
+ }
+*/
+
+ public static void actionMenuViewOnMenuItemClick(ActionMenuView.OnMenuItemClickListener listener, MenuItem item) {
+ ViewClickProvider.menuItemOnClick(item);
+ }
+
+ public static void popupMenuOnMenuItemClick(PopupMenu.OnMenuItemClickListener listener, MenuItem item) {
+ ViewClickProvider.menuItemOnClick(item);
+ }
+
+/*
+ public static void popupMenuXOnMenuItemClick(androidx.appcompat.widget.PopupMenu.OnMenuItemClickListener listener, MenuItem item) {
+ ViewClickProvider.menuItemOnClick(item);
+ }
+
+ public static void popupMenuSupportOnMenuItemClick(android.support.v7.widget.PopupMenu.OnMenuItemClickListener listener, MenuItem item) {
+ ViewClickProvider.menuItemOnClick(item);
+ }
+*/
+
+/*
+ public static void naviBarViewOnMenuItemClick(com.google.android.material.navigation.NavigationBarView.OnItemSelectedListener listener, MenuItem item) {
+ ViewClickProvider.menuItemOnClick(item);
+ }
+
+ public static void tabLayoutSelected(TabLayout.Tab tab) {
+ ViewClickProvider.viewOnClick(tab.view);
+ }
+*/
+
+}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/UcWebViewInjector.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/UcWebViewInjector.java
new file mode 100644
index 00000000..22d8a2cc
--- /dev/null
+++ b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/UcWebViewInjector.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 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.sdk.autotrack.inject;
+
+import com.growingio.android.sdk.TrackerContext;
+import com.growingio.android.sdk.track.log.Logger;
+import com.growingio.android.sdk.track.modelloader.ModelLoader;
+import com.growingio.android.sdk.track.middleware.hybrid.HybridBridge;
+import com.uc.webview.export.WebView;
+
+import java.util.Map;
+
+public class UcWebViewInjector {
+ private static final String TAG = "UCWebViewInjector";
+
+ private static void bridgeForWebView(WebView view) {
+ if (!TrackerContext.initializedSuccessfully()) {
+ Logger.e(TAG, "Autotracker do not initialized successfully");
+ return;
+ }
+
+ boolean result = false;
+ ModelLoader modelLoader = TrackerContext.get().getRegistry().getModelLoader(HybridBridge.class, Boolean.class);
+ if (modelLoader != null) {
+ result = modelLoader.buildLoadData(new HybridBridge(view)).fetcher.executeData();
+ }
+ Logger.d(TAG, "bridgeForWebView: webView = " + view.getClass().getName() + ", result = " + result);
+ }
+
+ private UcWebViewInjector() {
+ }
+
+ public static void ucWebViewLoadUrl(WebView webView, String url) {
+ Logger.d(TAG, "ucWebViewLoadUrl: webView = " + webView.getClass().getName() + ", url = " + url);
+ bridgeForWebView(webView);
+ }
+
+ public static void ucWebViewLoadUrl(WebView webView, String url, Map additionalHttpHeaders) {
+ Logger.d(TAG, "ucWebViewLoadUrl: webView = " + webView.getClass().getName() + ", url = " + url + ", additionalHttpHeaders = " + additionalHttpHeaders);
+ bridgeForWebView(webView);
+ }
+
+ public static void ucWebViewLoadData(WebView webView, String data, String mimeType, String encoding) {
+ Logger.d(TAG, "ucWebViewLoadData: webView = " + webView.getClass().getName());
+ bridgeForWebView(webView);
+ }
+
+ public static void ucWebViewLoadDataWithBaseURL(WebView webView, String baseUrl, String data, String mimeType, String encoding, String historyUrl) {
+ Logger.d(TAG, "ucWebViewLoadDataWithBaseURL: webView = " + webView.getClass().getName());
+ bridgeForWebView(webView);
+ }
+
+ public static void ucWebViewPostUrl(WebView webView, String url, byte[] postData) {
+ Logger.d(TAG, "ucWebViewPostUrl: webView = " + webView.getClass().getName());
+ bridgeForWebView(webView);
+ }
+
+}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/ViewClickInjector.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/ViewClickInjector.java
new file mode 100644
index 00000000..f63996bb
--- /dev/null
+++ b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/ViewClickInjector.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 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.sdk.autotrack.inject;
+
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.CompoundButton;
+import android.widget.ExpandableListView;
+import android.widget.RadioGroup;
+import android.widget.RatingBar;
+import android.widget.SeekBar;
+import android.widget.Spinner;
+
+
+public class ViewClickInjector {
+ private static final String TAG = "ViewClickInjector";
+
+ private ViewClickInjector() {
+ }
+
+ public static void viewOnClick(View.OnClickListener listener, View view) {
+ ViewClickProvider.viewOnClick(view);
+ }
+
+ public static void seekBarOnSeekBarChange(SeekBar.OnSeekBarChangeListener listener, SeekBar seekBar) {
+ ViewClickProvider.viewOnClick(seekBar);
+ }
+
+ public static void adapterViewOnItemClick(AdapterView.OnItemClickListener listener, AdapterView adapterView, View view, int position, long id) {
+ ViewClickProvider.viewOnClick(view);
+ }
+
+ public static void adapterViewOnItemSelected(AdapterView.OnItemSelectedListener listener, AdapterView adapterView, View view, int position, long id) {
+ if (adapterView instanceof Spinner) {
+ // 目前只需要将Spinner的onItemSelected回调触发点击事件,因为Spinner的元素点击只会触发onItemSelected回调
+ ViewClickProvider.viewOnClick(view);
+ }
+ }
+
+ public static void expandableListViewOnGroupClick(ExpandableListView.OnGroupClickListener listener, ExpandableListView parent, View v, int groupPosition, long id) {
+ ViewClickProvider.viewOnClick(v);
+ }
+
+ public static void expandableListViewOnChildClick(ExpandableListView.OnChildClickListener listener, ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
+ ViewClickProvider.viewOnClick(v);
+ }
+
+
+ public static void compoundButtonOnChecked(CompoundButton.OnCheckedChangeListener listener, CompoundButton button, boolean checked) {
+ ViewClickProvider.viewOnClick(button);
+ }
+
+ public static void radioGroupOnChecked(RadioGroup.OnCheckedChangeListener listener, RadioGroup radioGroup, int i) {
+ ViewClickProvider.viewOnClick(radioGroup.findViewById(radioGroup.getCheckedRadioButtonId()));
+ }
+
+ public static void ratingBarOnRatingBarChange(RatingBar.OnRatingBarChangeListener listener, RatingBar ratingBar, float rating, boolean fromUser) {
+ if (fromUser) {
+ ViewClickProvider.viewOnClick(ratingBar);
+ }
+ }
+}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/ViewClickProvider.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/ViewClickProvider.java
new file mode 100644
index 00000000..e604b222
--- /dev/null
+++ b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/ViewClickProvider.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2020 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.sdk.autotrack.inject;
+
+import android.app.Activity;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.growingio.android.sdk.TrackerContext;
+import com.growingio.android.sdk.autotrack.util.ClassUtil;
+import com.growingio.android.sdk.track.events.AutotrackEventType;
+import com.growingio.android.sdk.track.events.ViewElementEvent;
+import com.growingio.android.sdk.autotrack.page.Page;
+import com.growingio.android.sdk.autotrack.page.PageProvider;
+import com.growingio.android.sdk.autotrack.view.ViewHelper;
+import com.growingio.android.sdk.autotrack.view.ViewNode;
+import com.growingio.android.sdk.track.TrackMainThread;
+import com.growingio.android.sdk.track.log.Logger;
+import com.growingio.android.sdk.track.providers.ActivityStateProvider;
+
+class ViewClickProvider {
+ private static final String TAG = "ViewClickProvider";
+
+ private ViewClickProvider() {
+ }
+
+ public static void viewOnClick(View view) {
+ if (!TrackerContext.initializedSuccessfully()) {
+ Logger.e(TAG, "Autotracker do not initialized successfully");
+ return;
+ }
+
+ // 为了防止click事件重复发送
+ if (ClassUtil.isDuplicateClick(view)) {
+ view.hasOnClickListeners();
+ Logger.e(TAG, "Duplicate Click");
+ return;
+ }
+
+ ViewNode viewNode = ViewHelper.getClickViewNode(view);
+ if (viewNode != null) {
+ Page> page = PageProvider.get().findPage(view);
+ sendClickEvent(page, viewNode);
+ } else {
+ Logger.e(TAG, "ViewNode is NULL");
+ }
+ }
+
+ public static void menuItemOnClick(Activity activity, MenuItem menuItem) {
+ if (!TrackerContext.initializedSuccessfully()) {
+ Logger.e(TAG, "Autotracker do not initialized successfully");
+ return;
+ }
+ if (activity == null || menuItem == null) {
+ Logger.e(TAG, "menuItemOnClick: activity or menuItem is NULL");
+ return;
+ }
+
+ Page> page = PageProvider.get().findPage(activity);
+ ViewNode viewNode = ViewHelper.getMenuItemViewNode(page, menuItem);
+ if (viewNode != null) {
+ sendClickEvent(page, viewNode);
+ } else {
+ Logger.e(TAG, "MenuItem ViewNode is NULL");
+ }
+ }
+
+ public static void menuItemOnClick(MenuItem menuItem) {
+ if (!TrackerContext.initializedSuccessfully()) {
+ Logger.e(TAG, "Autotracker do not initialized successfully");
+ return;
+ }
+
+ Activity activity = ActivityStateProvider.get().getForegroundActivity();
+ menuItemOnClick(activity, menuItem);
+ }
+
+ private static void sendClickEvent(Page> page, ViewNode viewNode) {
+ if (page == null) {
+ Logger.e(TAG, "sendClickEvent page Activity is NULL");
+ return;
+ }
+ TrackMainThread.trackMain().postEventToTrackMain(
+ new ViewElementEvent.Builder()
+ .setEventType(AutotrackEventType.VIEW_CLICK)
+ .setPath(page.path())
+ .setPageShowTimestamp(page.getShowTimestamp())
+ .setXpath(viewNode.getXPath())
+ .setIndex(viewNode.getIndex())
+ .setTextValue(viewNode.getViewContent())
+ );
+ }
+}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/WebViewInjector.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/WebViewInjector.java
index 367fd479..4bb0ab28 100644
--- a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/WebViewInjector.java
+++ b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/WebViewInjector.java
@@ -22,8 +22,7 @@
import com.growingio.android.sdk.TrackerContext;
import com.growingio.android.sdk.track.log.Logger;
import com.growingio.android.sdk.track.modelloader.ModelLoader;
-import com.growingio.android.sdk.track.modelloader.data.HybridBridge;
-import com.growingio.sdk.inject.annotation.Before;
+import com.growingio.android.sdk.track.middleware.hybrid.HybridBridge;
import java.util.Map;
@@ -47,93 +46,28 @@ private static void bridgeForWebView(View view) {
private WebViewInjector() {
}
- @Before(clazz = WebView.class, method = "loadUrl", parameterTypes = {String.class})
public static void webkitWebViewLoadUrl(WebView webView, String url) {
Logger.d(TAG, "webkitWebViewLoadUrl: webView = " + webView.getClass().getName() + ", url = " + url);
bridgeForWebView(webView);
}
- @Before(clazz = WebView.class, method = "loadUrl", parameterTypes = {String.class, Map.class})
public static void webkitWebViewLoadUrl(WebView webView, String url, Map additionalHttpHeaders) {
Logger.d(TAG, "webkitWebViewLoadUrl: webView = " + webView.getClass().getName() + ", url = " + url + ", additionalHttpHeaders = " + additionalHttpHeaders);
bridgeForWebView(webView);
}
- @Before(clazz = WebView.class, method = "loadData", parameterTypes = {String.class, String.class, String.class})
public static void webkitWebViewLoadData(WebView webView, String data, String mimeType, String encoding) {
Logger.d(TAG, "webkitWebViewLoadData: webView = " + webView.getClass().getName());
bridgeForWebView(webView);
}
- @Before(clazz = WebView.class, method = "loadDataWithBaseURL", parameterTypes = {String.class, String.class, String.class, String.class, String.class})
public static void webkitWebViewLoadDataWithBaseURL(WebView webView, String baseUrl, String data, String mimeType, String encoding, String historyUrl) {
Logger.d(TAG, "webkitWebViewLoadDataWithBaseURL: webView = " + webView.getClass().getName());
bridgeForWebView(webView);
}
- @Before(clazz = WebView.class, method = "postUrl", parameterTypes = {String.class, byte[].class})
public static void webkitWebViewPostUrl(WebView webView, String url, byte[] postData) {
Logger.d(TAG, "webkitWebViewPostUrl: webView = " + webView.getClass().getName());
bridgeForWebView(webView);
}
-
- @Before(clazz = com.tencent.smtt.sdk.WebView.class, method = "loadUrl", parameterTypes = {String.class})
- public static void x5WebViewLoadUrl(View webView, String url) {
- Logger.d(TAG, "x5WebViewLoadUrl: webView = " + webView.getClass().getName() + ", url = " + url);
- bridgeForWebView(webView);
- }
-
- @Before(clazz = com.tencent.smtt.sdk.WebView.class, method = "loadUrl", parameterTypes = {String.class, Map.class})
- public static void x5WebViewLoadUrl(View webView, String url, Map additionalHttpHeaders) {
- Logger.d(TAG, "x5WebViewLoadUrl: webView = " + webView.getClass().getName() + ", url = " + url + ", additionalHttpHeaders = " + additionalHttpHeaders);
- bridgeForWebView(webView);
- }
-
- @Before(clazz = com.tencent.smtt.sdk.WebView.class, method = "loadData", parameterTypes = {String.class, String.class, String.class})
- public static void x5WebViewLoadData(View webView, String data, String mimeType, String encoding) {
- Logger.d(TAG, "x5WebViewLoadData: webView = " + webView.getClass().getName());
- bridgeForWebView(webView);
- }
-
- @Before(clazz = com.tencent.smtt.sdk.WebView.class, method = "loadDataWithBaseURL", parameterTypes = {String.class, String.class, String.class, String.class, String.class})
- public static void x5WebViewLoadDataWithBaseURL(View webView, String baseUrl, String data, String mimeType, String encoding, String historyUrl) {
- Logger.d(TAG, "x5WebViewLoadDataWithBaseURL: webView = " + webView.getClass().getName());
- bridgeForWebView(webView);
- }
-
- @Before(clazz = com.tencent.smtt.sdk.WebView.class, method = "postUrl", parameterTypes = {String.class, byte[].class})
- public static void x5WebViewPostUrl(View webView, String url, byte[] postData) {
- Logger.d(TAG, "x5WebViewPostUrl: webView = " + webView.getClass().getName());
- bridgeForWebView(webView);
- }
-
- @Before(clazz = com.uc.webview.export.WebView.class, method = "loadUrl", parameterTypes = {String.class})
- public static void ucWebViewLoadUrl(View webView, String url) {
- Logger.d(TAG, "ucWebViewLoadUrl: webView = " + webView.getClass().getName() + ", url = " + url);
- bridgeForWebView(webView);
- }
-
- @Before(clazz = com.uc.webview.export.WebView.class, method = "loadUrl", parameterTypes = {String.class, Map.class})
- public static void ucWebViewLoadUrl(View webView, String url, Map additionalHttpHeaders) {
- Logger.d(TAG, "ucWebViewLoadUrl: webView = " + webView.getClass().getName() + ", url = " + url + ", additionalHttpHeaders = " + additionalHttpHeaders);
- bridgeForWebView(webView);
- }
-
- @Before(clazz = com.uc.webview.export.WebView.class, method = "loadData", parameterTypes = {String.class, String.class, String.class})
- public static void ucWebViewLoadData(View webView, String data, String mimeType, String encoding) {
- Logger.d(TAG, "ucWebViewLoadData: webView = " + webView.getClass().getName());
- bridgeForWebView(webView);
- }
-
- @Before(clazz = com.uc.webview.export.WebView.class, method = "loadDataWithBaseURL", parameterTypes = {String.class, String.class, String.class, String.class, String.class})
- public static void ucWebViewLoadDataWithBaseURL(View webView, String baseUrl, String data, String mimeType, String encoding, String historyUrl) {
- Logger.d(TAG, "ucWebViewLoadDataWithBaseURL: webView = " + webView.getClass().getName());
- bridgeForWebView(webView);
- }
-
- @Before(clazz = com.uc.webview.export.WebView.class, method = "postUrl", parameterTypes = {String.class, byte[].class})
- public static void ucWebViewPostUrl(View webView, String url, byte[] postData) {
- Logger.d(TAG, "ucWebViewPostUrl: webView = " + webView.getClass().getName());
- bridgeForWebView(webView);
- }
}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/X5WebViewInjector.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/X5WebViewInjector.java
new file mode 100644
index 00000000..4bb0a492
--- /dev/null
+++ b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/inject/X5WebViewInjector.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2020 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.sdk.autotrack.inject;
+
+
+import com.growingio.android.sdk.TrackerContext;
+import com.growingio.android.sdk.track.log.Logger;
+import com.growingio.android.sdk.track.modelloader.ModelLoader;
+import com.growingio.android.sdk.track.middleware.hybrid.HybridBridge;
+import com.tencent.smtt.sdk.WebView;
+
+import java.util.Map;
+
+public class X5WebViewInjector {
+ private static final String TAG = "X5WebViewInjector";
+
+ private static void bridgeForWebView(WebView view) {
+ if (!TrackerContext.initializedSuccessfully()) {
+ Logger.e(TAG, "Autotracker do not initialized successfully");
+ return;
+ }
+
+ boolean result = false;
+ ModelLoader modelLoader = TrackerContext.get().getRegistry().getModelLoader(HybridBridge.class, Boolean.class);
+ if (modelLoader != null) {
+ result = modelLoader.buildLoadData(new HybridBridge(view)).fetcher.executeData();
+ }
+ Logger.d(TAG, "bridgeForWebView: webView = " + view.getClass().getName() + ", result = " + result);
+ }
+
+ private X5WebViewInjector() {
+ }
+
+ public static void x5WebViewLoadUrl(WebView webView, String url) {
+ Logger.d(TAG, "x5WebViewLoadUrl: webView = " + webView.getClass().getName() + ", url = " + url);
+ bridgeForWebView(webView);
+ }
+
+ public static void x5WebViewLoadUrl(WebView webView, String url, Map additionalHttpHeaders) {
+ Logger.d(TAG, "x5WebViewLoadUrl: webView = " + webView.getClass().getName() + ", url = " + url + ", additionalHttpHeaders = " + additionalHttpHeaders);
+ bridgeForWebView(webView);
+ }
+
+ public static void x5WebViewLoadData(WebView webView, String data, String mimeType, String encoding) {
+ Logger.d(TAG, "x5WebViewLoadData: webView = " + webView.getClass().getName());
+ bridgeForWebView(webView);
+ }
+
+ public static void x5WebViewLoadDataWithBaseURL(WebView webView, String baseUrl, String data, String mimeType, String encoding, String historyUrl) {
+ Logger.d(TAG, "x5WebViewLoadDataWithBaseURL: webView = " + webView.getClass().getName());
+ bridgeForWebView(webView);
+ }
+
+ public static void x5WebViewPostUrl(WebView webView, String url, byte[] postData) {
+ Logger.d(TAG, "x5WebViewPostUrl: webView = " + webView.getClass().getName());
+ bridgeForWebView(webView);
+ }
+}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/page/FragmentInjector.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/page/FragmentInjector.java
deleted file mode 100644
index 0a1957ac..00000000
--- a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/page/FragmentInjector.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2020 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.sdk.autotrack.page;
-
-import com.growingio.android.sdk.track.log.Logger;
-import com.growingio.sdk.inject.annotation.AfterSuper;
-
-public class FragmentInjector {
- private static final String TAG = "FragmentInjector";
-
- private FragmentInjector() {
- }
-
- @AfterSuper(clazz = android.app.Fragment.class, method = "onResume")
- @AfterSuper(clazz = android.app.DialogFragment.class, method = "onResume")
- @AfterSuper(clazz = android.app.ListFragment.class, method = "onResume")
- @AfterSuper(clazz = android.preference.PreferenceFragment.class, method = "onResume")
- @AfterSuper(clazz = android.webkit.WebViewFragment.class, method = "onResume")
- public static void systemFragmentOnResume(android.app.Fragment fragment) {
- Logger.d(TAG, "systemFragmentOnResume: fragment = " + fragment.getClass().getName());
- PageProvider.get().createOrResumePage(SuperFragment.make(fragment));
- }
-
- @AfterSuper(clazz = android.app.Fragment.class, method = "setUserVisibleHint", parameterTypes = {boolean.class})
- @AfterSuper(clazz = android.app.DialogFragment.class, method = "setUserVisibleHint", parameterTypes = {boolean.class})
- @AfterSuper(clazz = android.app.ListFragment.class, method = "setUserVisibleHint", parameterTypes = {boolean.class})
- @AfterSuper(clazz = android.preference.PreferenceFragment.class, method = "setUserVisibleHint", parameterTypes = {boolean.class})
- @AfterSuper(clazz = android.webkit.WebViewFragment.class, method = "setUserVisibleHint", parameterTypes = {boolean.class})
- public static void systemFragmentSetUserVisibleHint(android.app.Fragment fragment, boolean isVisibleToUser) {
- Logger.d(TAG, "systemFragmentSetUserVisibleHint: fragment = " + fragment.getClass().getName() + ", isVisibleToUser = " + isVisibleToUser);
- if (isVisibleToUser) {
- PageProvider.get().createOrResumePage(SuperFragment.make(fragment));
- }
- }
-
- @AfterSuper(clazz = android.app.Fragment.class, method = "onHiddenChanged", parameterTypes = {boolean.class})
- @AfterSuper(clazz = android.app.DialogFragment.class, method = "onHiddenChanged", parameterTypes = {boolean.class})
- @AfterSuper(clazz = android.app.ListFragment.class, method = "onHiddenChanged", parameterTypes = {boolean.class})
- @AfterSuper(clazz = android.preference.PreferenceFragment.class, method = "onHiddenChanged", parameterTypes = {boolean.class})
- @AfterSuper(clazz = android.webkit.WebViewFragment.class, method = "onHiddenChanged", parameterTypes = {boolean.class})
- public static void systemFragmentOnHiddenChanged(android.app.Fragment fragment, boolean hidden) {
- Logger.d(TAG, "systemFragmentOnHiddenChanged: fragment = " + fragment.getClass().getName() + ", hidden" + hidden);
- PageProvider.get().fragmentOnHiddenChanged(SuperFragment.make(fragment), hidden);
- }
-
- @AfterSuper(clazz = android.app.Fragment.class, method = "onDestroyView")
- @AfterSuper(clazz = android.app.DialogFragment.class, method = "onDestroyView")
- @AfterSuper(clazz = android.app.ListFragment.class, method = "onDestroyView")
- @AfterSuper(clazz = android.preference.PreferenceFragment.class, method = "onDestroyView")
- @AfterSuper(clazz = android.webkit.WebViewFragment.class, method = "onDestroyView")
- public static void systemFragmentOnDestroyView(android.app.Fragment fragment) {
- Logger.d(TAG, "systemFragmentOnDestroyView: fragment = " + fragment.getClass().getName());
- PageProvider.get().removePage(SuperFragment.make(fragment));
- }
-
- @AfterSuper(clazz = android.support.v4.app.Fragment.class, method = "onResume")
- public static void v4FragmentOnResume(android.support.v4.app.Fragment fragment) {
- Logger.d(TAG, "v4FragmentOnResume: fragment = " + fragment.getClass().getName());
- PageProvider.get().createOrResumePage(SuperFragment.makeSupport(fragment));
- }
-
- @AfterSuper(clazz = android.support.v4.app.Fragment.class, method = "setUserVisibleHint", parameterTypes = {boolean.class})
- public static void v4FragmentSetUserVisibleHint(android.support.v4.app.Fragment fragment, boolean isVisibleToUser) {
- Logger.d(TAG, "v4FragmentSetUserVisibleHint: fragment = " + fragment.getClass().getName() + ", isVisibleToUser = " + isVisibleToUser);
- if (isVisibleToUser) {
- PageProvider.get().createOrResumePage(SuperFragment.makeSupport(fragment));
- }
- }
-
- @AfterSuper(clazz = android.support.v4.app.Fragment.class, method = "onHiddenChanged", parameterTypes = {boolean.class})
- public static void v4FragmentOnHiddenChanged(android.support.v4.app.Fragment fragment, boolean hidden) {
- Logger.d(TAG, "v4FragmentOnHiddenChanged: fragment = " + fragment.getClass().getName() + ", hidden = " + hidden);
- PageProvider.get().fragmentOnHiddenChanged(SuperFragment.makeSupport(fragment), hidden);
- }
-
- @AfterSuper(clazz = android.support.v4.app.Fragment.class, method = "onDestroyView")
- public static void v4FragmentOnDestroyView(android.support.v4.app.Fragment fragment) {
- Logger.d(TAG, "v4FragmentOnDestroyView: fragment = " + fragment.getClass().getName());
- PageProvider.get().removePage(SuperFragment.makeSupport(fragment));
- }
-
- @AfterSuper(clazz = androidx.fragment.app.Fragment.class, method = "onResume")
- public static void androidxFragmentOnResume(androidx.fragment.app.Fragment fragment) {
- Logger.d(TAG, "androidxFragmentOnResume: fragment = " + fragment.getClass().getName());
- PageProvider.get().createOrResumePage(SuperFragment.makeX(fragment));
- }
-
- @AfterSuper(clazz = androidx.fragment.app.Fragment.class, method = "setUserVisibleHint", parameterTypes = {boolean.class})
- public static void androidxFragmentSetUserVisibleHint(androidx.fragment.app.Fragment fragment, boolean isVisibleToUser) {
- Logger.d(TAG, "androidxFragmentSetUserVisibleHint: fragment = " + fragment.getClass().getName() + ", isVisibleToUser = " + isVisibleToUser);
- if (isVisibleToUser) {
- PageProvider.get().createOrResumePage(SuperFragment.makeX(fragment));
- }
- }
-
- @AfterSuper(clazz = androidx.fragment.app.Fragment.class, method = "onHiddenChanged", parameterTypes = {boolean.class})
- public static void androidxFragmentOnHiddenChanged(androidx.fragment.app.Fragment fragment, boolean hidden) {
- Logger.d(TAG, "androidxFragmentOnHiddenChanged: fragment = " + fragment.getClass().getName() + ", hidden" + hidden);
- PageProvider.get().fragmentOnHiddenChanged(SuperFragment.makeX(fragment), hidden);
- }
-
- @AfterSuper(clazz = androidx.fragment.app.Fragment.class, method = "onDestroyView")
- public static void androidxFragmentOnDestroyView(androidx.fragment.app.Fragment fragment) {
- Logger.d(TAG, "androidxFragmentOnDestroyView: fragment = " + fragment.getClass().getName());
- PageProvider.get().removePage(SuperFragment.makeX(fragment));
- }
-
-}
diff --git a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/util/ClassUtil.java b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/util/ClassUtil.java
index bb2eebd0..b2fa7bbf 100644
--- a/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/util/ClassUtil.java
+++ b/growingio-autotracker-core/src/main/java/com/growingio/android/sdk/autotrack/util/ClassUtil.java
@@ -18,7 +18,11 @@
import android.annotation.TargetApi;
import android.os.Build;
+import android.os.SystemClock;
import android.text.TextUtils;
+import android.view.View;
+
+import com.growingio.android.sdk.autotrack.R;
@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
@@ -35,5 +39,23 @@ public static String getSimpleClassName(Class> clazz) {
}
return name;
}
+
+ public static boolean isDuplicateClick(View view) {
+ if (view == null) {
+ return false;
+ }
+ try {
+ String timeStamp = (String) view.getTag(R.id.growing_tracker_duplicate_click_timestamp);
+ if (!TextUtils.isEmpty(timeStamp)) {
+ long lastTime = Long.parseLong(timeStamp);
+ if (SystemClock.elapsedRealtime() - lastTime <= 200) {
+ return true;
+ }
+ }
+ view.setTag(R.id.growing_tracker_duplicate_click_timestamp, String.valueOf(SystemClock.elapsedRealtime()));
+ } catch (Exception ignored) {
+ }
+ return false;
+ }
}
diff --git a/growingio-autotracker-core/src/main/res/values/ids.xml b/growingio-autotracker-core/src/main/res/values/ids.xml
index a82a805d..7baf211f 100644
--- a/growingio-autotracker-core/src/main/res/values/ids.xml
+++ b/growingio-autotracker-core/src/main/res/values/ids.xml
@@ -7,4 +7,5 @@
+
\ No newline at end of file
diff --git a/growingio-autotracker-core/src/test/java/com/growingio/android/sdk/autotrack/click/ViewClickTest.java b/growingio-autotracker-core/src/test/java/com/growingio/android/sdk/autotrack/click/ViewClickTest.java
index 95f7962d..3f215795 100644
--- a/growingio-autotracker-core/src/test/java/com/growingio/android/sdk/autotrack/click/ViewClickTest.java
+++ b/growingio-autotracker-core/src/test/java/com/growingio/android/sdk/autotrack/click/ViewClickTest.java
@@ -25,6 +25,8 @@
import com.google.common.truth.Truth;
import com.growingio.android.sdk.TrackerContext;
import com.growingio.android.sdk.autotrack.RobolectricActivity;
+import com.growingio.android.sdk.autotrack.inject.DialogInjector;
+import com.growingio.android.sdk.autotrack.inject.ViewClickInjector;
import com.growingio.android.sdk.track.events.ViewElementEvent;
import com.growingio.android.sdk.track.providers.ActivityStateProvider;
@@ -78,9 +80,8 @@ public void injectTest() {
})
.create();
testDialog.show();
- ViewClickInjector.alertDialogShow(testDialog);
- ViewClickInjector.dialogOnClick((dialog, which) -> {
-
+ DialogInjector.alertDialogShow(testDialog);
+ DialogInjector.dialogOnClick((dialog, which) -> {
}, testDialog, -1);
}
}
diff --git a/growingio-autotracker-core/src/test/java/com/growingio/android/sdk/autotrack/hybrid/HybridTest.java b/growingio-autotracker-core/src/test/java/com/growingio/android/sdk/autotrack/hybrid/HybridTest.java
index 4ea18f2e..f87abc80 100644
--- a/growingio-autotracker-core/src/test/java/com/growingio/android/sdk/autotrack/hybrid/HybridTest.java
+++ b/growingio-autotracker-core/src/test/java/com/growingio/android/sdk/autotrack/hybrid/HybridTest.java
@@ -24,7 +24,9 @@
import com.growingio.android.sdk.TrackerContext;
import com.growingio.android.sdk.autotrack.RobolectricActivity;
+import com.growingio.android.sdk.autotrack.inject.UcWebViewInjector;
import com.growingio.android.sdk.autotrack.inject.WebViewInjector;
+import com.growingio.android.sdk.autotrack.inject.X5WebViewInjector;
import org.junit.Before;
import org.junit.Test;
@@ -58,18 +60,18 @@ public void webInjectTest() {
WebViewInjector.webkitWebViewPostUrl(webView, "https://www.baidu.com/", null);
com.uc.webview.export.WebView ucWebView = new com.uc.webview.export.WebView(activity);
- WebViewInjector.ucWebViewLoadUrl(ucWebView, "https://www.baidu.com/");
- WebViewInjector.ucWebViewLoadUrl(ucWebView, "https://www.baidu.com/", new HashMap<>());
- WebViewInjector.ucWebViewLoadData(ucWebView, "", "text", "UTF8");
- WebViewInjector.ucWebViewLoadDataWithBaseURL(ucWebView, "https://www.baidu.com/", "