diff --git a/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/FragmentCacheInfo.java b/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/FragmentCacheInfo.java new file mode 100644 index 00000000..ffdbc5fa --- /dev/null +++ b/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/FragmentCacheInfo.java @@ -0,0 +1,51 @@ +package com.sensorsdata.analytics.android.sdk; + +import android.app.Activity; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.lang.ref.WeakReference; + +/** + * author : Handy + * e-mail : huxq17@gmail.com + * time : 2021/09/07 + * desc : + */ +public class FragmentCacheInfo { + private WeakReference activityWeakReference; + private final Class fragmentClazz; + private final JSONObject trackProperties; + + public FragmentCacheInfo(Activity activity, Object fragment) { + this.activityWeakReference = new WeakReference<>(activity); + this.fragmentClazz = fragment.getClass(); + JSONObject trackProperties = null; + if (fragment instanceof ScreenAutoTracker) { + ScreenAutoTracker screenAutoTracker = (ScreenAutoTracker) fragment; + try { + trackProperties = screenAutoTracker.getTrackProperties(); + } catch (JSONException e) { + e.printStackTrace(); + } + } + this.trackProperties = trackProperties; + } + + public Activity getActivity() { + return activityWeakReference == null ? null : activityWeakReference.get(); + } + + public void setActivity(Activity activity) { + this.activityWeakReference = new WeakReference<>(activity); + } + + public Class getFragmentClazz() { + return fragmentClazz; + } + + public JSONObject getTrackProperties() { + return trackProperties; + } +} diff --git a/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/SensorsDataAutoTrackHelper.java b/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/SensorsDataAutoTrackHelper.java index c4ad9517..effff577 100644 --- a/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/SensorsDataAutoTrackHelper.java +++ b/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/SensorsDataAutoTrackHelper.java @@ -179,12 +179,12 @@ public static void trackExpandableListViewOnGroupClick(ExpandableListView expand } } - // 获取 view 所在的 fragment - Object fragment = AopUtil.getFragmentFromView(expandableListView, activity); + // 获取 view 所在的 fragment缓存信息 + FragmentCacheInfo fragmentCacheInfo = AopUtil.getFragmentFromView(expandableListView, activity); // fragment 忽略 - if (fragment != null) { - if (SensorsDataAPI.sharedInstance().isActivityAutoTrackAppClickIgnored(fragment.getClass())) { + if (fragmentCacheInfo != null) { + if (SensorsDataAPI.sharedInstance().isActivityAutoTrackAppClickIgnored(fragmentCacheInfo.getFragmentClazz())) { return; } } @@ -235,8 +235,8 @@ public static void trackExpandableListViewOnGroupClick(ExpandableListView expand } //fragmentName - if (fragment != null) { - AopUtil.getScreenNameAndTitleFromFragment(properties, fragment, activity); + if (fragmentCacheInfo != null) { + AopUtil.getScreenNameAndTitleFromFragmentCacheInfo(properties, fragmentCacheInfo, activity); } // 获取 View 自定义属性 @@ -300,12 +300,12 @@ public static void trackExpandableListViewOnChildClick(ExpandableListView expand } } - // 获取 view 所在的 fragment - Object fragment = AopUtil.getFragmentFromView(expandableListView, activity); + // 获取 view 所在的 fragment缓存信息 + FragmentCacheInfo fragmentCacheInfo = AopUtil.getFragmentFromView(expandableListView, activity); // fragment 忽略 - if (fragment != null) { - if (SensorsDataAPI.sharedInstance().isActivityAutoTrackAppClickIgnored(fragment.getClass())) { + if (fragmentCacheInfo != null) { + if (SensorsDataAPI.sharedInstance().isActivityAutoTrackAppClickIgnored(fragmentCacheInfo.getFragmentClazz())) { return; } } @@ -378,8 +378,8 @@ public static void trackExpandableListViewOnChildClick(ExpandableListView expand } //fragmentName - if (fragment != null) { - AopUtil.getScreenNameAndTitleFromFragment(properties, fragment, activity); + if (fragmentCacheInfo != null) { + AopUtil.getScreenNameAndTitleFromFragmentCacheInfo(properties, fragmentCacheInfo, activity); } //获取 View 自定义属性 @@ -435,12 +435,12 @@ public void run() { } SensorsDataUtils.mergeJSONObject(AopUtil.buildTitleAndScreenName(activity), properties); - Object fragment = AopUtil.getFragmentFromView(view, activity); - if (fragment != null) { - if (SensorsDataAPI.sharedInstance().isActivityAutoTrackAppClickIgnored(fragment.getClass())) { + FragmentCacheInfo fragmentCacheInfo = AopUtil.getFragmentFromView(view, activity); + if (fragmentCacheInfo != null) { + if (SensorsDataAPI.sharedInstance().isActivityAutoTrackAppClickIgnored(fragmentCacheInfo.getFragmentClazz())) { return; } - AopUtil.getScreenNameAndTitleFromFragment(properties, fragment, activity); + AopUtil.getScreenNameAndTitleFromFragmentCacheInfo(properties, fragmentCacheInfo, activity); } viewNode = AopUtil.addViewPathProperties(activity, view, properties); @@ -853,12 +853,12 @@ public static void trackRadioGroup(RadioGroup view, int checkedId) { } } - // 获取 view 所在的 fragment - Object fragment = AopUtil.getFragmentFromView(view, activity); + // 获取 view 所在的 fragment缓存信息 + FragmentCacheInfo fragmentCacheInfo = AopUtil.getFragmentFromView(view, activity); // fragment 忽略 - if (fragment != null) { - if (SensorsDataAPI.sharedInstance().isActivityAutoTrackAppClickIgnored(fragment.getClass())) { + if (fragmentCacheInfo != null) { + if (SensorsDataAPI.sharedInstance().isActivityAutoTrackAppClickIgnored(fragmentCacheInfo.getFragmentClazz())) { return; } } @@ -908,8 +908,8 @@ public static void trackRadioGroup(RadioGroup view, int checkedId) { } //fragmentName - if (fragment != null) { - AopUtil.getScreenNameAndTitleFromFragment(properties, fragment, activity); + if (fragmentCacheInfo != null) { + AopUtil.getScreenNameAndTitleFromFragmentCacheInfo(properties, fragmentCacheInfo, activity); } //获取 View 自定义属性 @@ -1125,12 +1125,12 @@ public static void trackListView(AdapterView adapterView, View view, int posi } } - // 获取 view 所在的 fragment - Object fragment = AopUtil.getFragmentFromView(adapterView, activity); + // 获取 view 所在的 fragment缓存信息 + FragmentCacheInfo fragmentCacheInfo = AopUtil.getFragmentFromView(adapterView, activity); // fragment 忽略 - if (fragment != null) { - if (SensorsDataAPI.sharedInstance().isActivityAutoTrackAppClickIgnored(fragment.getClass())) { + if (fragmentCacheInfo != null) { + if (SensorsDataAPI.sharedInstance().isActivityAutoTrackAppClickIgnored(fragmentCacheInfo.getFragmentClazz())) { return; } } @@ -1210,8 +1210,8 @@ public static void trackListView(AdapterView adapterView, View view, int posi } //fragmentName - if (fragment != null) { - AopUtil.getScreenNameAndTitleFromFragment(properties, fragment, activity); + if (fragmentCacheInfo != null) { + AopUtil.getScreenNameAndTitleFromFragmentCacheInfo(properties, fragmentCacheInfo, activity); } //获取 View 自定义属性 @@ -1292,12 +1292,12 @@ public static void trackViewOnClick(View view, boolean isFromUser) { } } - // 获取 view 所在的 fragment - Object fragment = AopUtil.getFragmentFromView(view, activity); + // 获取 view 所在的 fragment缓存信息 + FragmentCacheInfo fragmentCacheInfo = AopUtil.getFragmentFromView(view, activity); // fragment 忽略 - if (fragment != null) { - if (SensorsDataAPI.sharedInstance().isActivityAutoTrackAppClickIgnored(fragment.getClass())) { + if (fragmentCacheInfo != null) { + if (SensorsDataAPI.sharedInstance().isActivityAutoTrackAppClickIgnored(fragmentCacheInfo.getFragmentClazz())) { return; } } diff --git a/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/util/AopUtil.java b/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/util/AopUtil.java index 04cffb93..2c0673b3 100644 --- a/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/util/AopUtil.java +++ b/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/util/AopUtil.java @@ -41,6 +41,7 @@ import android.widget.ToggleButton; import com.sensorsdata.analytics.android.sdk.AopConstants; +import com.sensorsdata.analytics.android.sdk.FragmentCacheInfo; import com.sensorsdata.analytics.android.sdk.R; import com.sensorsdata.analytics.android.sdk.SALog; import com.sensorsdata.analytics.android.sdk.ScreenAutoTracker; @@ -61,7 +62,7 @@ public class AopUtil { - private static LruCache sLruCache; + private static LruCache sLruCache; // 采集 viewType 忽略以下包内 view 直接返回对应的基础控件 viewType private static ArrayList sOSViewPackage = new ArrayList() {{ @@ -284,6 +285,68 @@ public static void getScreenNameAndTitleFromFragment(JSONObject properties, Obje } } + /** + * 尝试读取页面 title + * + * @param properties JSONObject + * @param fragmentCacheInfo FragmentCacheInfo + * @param activity Activity + */ + public static void getScreenNameAndTitleFromFragmentCacheInfo(JSONObject properties, FragmentCacheInfo fragmentCacheInfo, Activity activity) { + try { + String screenName = null; + String title = null; + JSONObject trackProperties = fragmentCacheInfo.getTrackProperties(); + if (trackProperties != null) { + if (trackProperties.has(AopConstants.SCREEN_NAME)) { + screenName = trackProperties.optString(AopConstants.SCREEN_NAME); + } + + if (trackProperties.has(AopConstants.TITLE)) { + title = trackProperties.optString(AopConstants.TITLE); + } + SensorsDataUtils.mergeJSONObject(trackProperties, properties); + } + + Class fragmentClazz = fragmentCacheInfo.getFragmentClazz(); + if (TextUtils.isEmpty(title) && fragmentClazz.isAnnotationPresent(SensorsDataFragmentTitle.class)) { + SensorsDataFragmentTitle sensorsDataFragmentTitle = fragmentClazz.getAnnotation(SensorsDataFragmentTitle.class); + if (sensorsDataFragmentTitle != null) { + title = sensorsDataFragmentTitle.title(); + } + } + + boolean isTitleNull = TextUtils.isEmpty(title); + boolean isScreenNameNull = TextUtils.isEmpty(screenName); + if (isTitleNull || isScreenNameNull) { + if (activity == null) { + activity = fragmentCacheInfo.getActivity(); + } + if (activity != null) { + if (isTitleNull) { + title = SensorsDataUtils.getActivityTitle(activity); + } + + if (isScreenNameNull) { + screenName = fragmentClazz.getCanonicalName(); + screenName = String.format(Locale.CHINA, "%s|%s", activity.getClass().getCanonicalName(), screenName); + } + } + } + + if (!TextUtils.isEmpty(title)) { + properties.put(AopConstants.TITLE, title); + } + + if (TextUtils.isEmpty(screenName)) { + screenName = fragmentClazz.getCanonicalName(); + } + properties.put("$screen_name", screenName); + } catch (Exception ex) { + SALog.printStackTrace(ex); + } + } + /** * 根据 Fragment 获取对应的 Activity * @@ -675,9 +738,9 @@ public static boolean injectClickInfo(View view, JSONObject properties, boolean } //fragmentName - Object fragment = AopUtil.getFragmentFromView(view, activity); - if (fragment != null) { - AopUtil.getScreenNameAndTitleFromFragment(eventJson, fragment, activity); + FragmentCacheInfo fragmentCacheInfo = AopUtil.getFragmentFromView(view, activity); + if (fragmentCacheInfo != null) { + AopUtil.getScreenNameAndTitleFromFragmentCacheInfo(eventJson, fragmentCacheInfo, activity); } //3.获取 View 自定义属性 JSONObject p = (JSONObject) view.getTag(R.id.sensors_analytics_tag_view_properties); @@ -699,19 +762,19 @@ public static boolean injectClickInfo(View view, JSONObject properties, boolean * @param view 点击的 view * @return object 这里是 fragment 实例对象 */ - public static Object getFragmentFromView(View view) { + public static FragmentCacheInfo getFragmentFromView(View view) { return getFragmentFromView(view, null); } /** - * 获取点击 view 的 fragment 对象 + * 获取点击 view 的 fragmentCacheInfo 对象 * * @param view 点击的 view * @param activity Activity - * @return object 这里是 fragment 实例对象 + * @return object 这里是 fragmentCacheInfo 实例对象 */ @SuppressLint("NewApi") - public static Object getFragmentFromView(View view, Activity activity) { + public static FragmentCacheInfo getFragmentFromView(View view, Activity activity) { try { if (view != null) { String fragmentName = (String) view.getTag(R.id.sensors_analytics_tag_view_fragment_name); @@ -740,13 +803,15 @@ public static Object getFragmentFromView(View view, Activity activity) { if (sLruCache == null) { sLruCache = new LruCache<>(10); } - Object object = sLruCache.get(fragmentName); - if (object != null) { - return object; + FragmentCacheInfo cacheInfo = sLruCache.get(fragmentName); + if (cacheInfo != null) { + cacheInfo.setActivity(activity); + return cacheInfo; } - object = Class.forName(fragmentName).newInstance(); - sLruCache.put(fragmentName, object); - return object; + Object object = Class.forName(fragmentName).newInstance(); + cacheInfo = new FragmentCacheInfo(activity, object); + sLruCache.put(fragmentName, cacheInfo); + return cacheInfo; } } } catch (Exception e) { diff --git a/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/util/ViewUtil.java b/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/util/ViewUtil.java index 0f39c9a9..8d86c0df 100644 --- a/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/util/ViewUtil.java +++ b/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/util/ViewUtil.java @@ -44,6 +44,7 @@ import android.widget.ToggleButton; import com.sensorsdata.analytics.android.sdk.AppStateManager; +import com.sensorsdata.analytics.android.sdk.FragmentCacheInfo; import com.sensorsdata.analytics.android.sdk.SALog; import com.sensorsdata.analytics.android.sdk.visual.model.ViewNode; import com.sensorsdata.analytics.android.sdk.visual.util.VisualUtil; @@ -162,8 +163,8 @@ private static String getCanonicalName(Class clazz) { * view 是否为 Fragment 中的顶层 View */ private static Object instanceOfFragmentRootView(View parentView, View childView) { - Object parentFragment = AopUtil.getFragmentFromView(parentView); - Object childFragment = AopUtil.getFragmentFromView(childView); + FragmentCacheInfo parentFragment = AopUtil.getFragmentFromView(parentView); + FragmentCacheInfo childFragment = AopUtil.getFragmentFromView(childView); if (parentFragment == null && childFragment != null) { return childFragment; } diff --git a/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/visual/util/VisualUtil.java b/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/visual/util/VisualUtil.java index 9f12d4d3..a533e749 100644 --- a/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/visual/util/VisualUtil.java +++ b/SensorsAnalyticsSDK/src/main/java/com/sensorsdata/analytics/android/sdk/visual/util/VisualUtil.java @@ -34,6 +34,7 @@ import com.sensorsdata.analytics.android.sdk.AppStateManager; import com.sensorsdata.analytics.android.sdk.AopConstants; +import com.sensorsdata.analytics.android.sdk.FragmentCacheInfo; import com.sensorsdata.analytics.android.sdk.SALog; import com.sensorsdata.analytics.android.sdk.util.AopUtil; import com.sensorsdata.analytics.android.sdk.util.ReflectUtil; @@ -138,9 +139,9 @@ public static JSONObject getScreenNameAndTitle(View view, SnapInfo info) { } if (activity != null && activity.getWindow() != null && activity.getWindow().isActive()) { object = new JSONObject(); - Object fragment = AopUtil.getFragmentFromView(view, activity); - if (fragment != null) { - AopUtil.getScreenNameAndTitleFromFragment(object, fragment, activity); + FragmentCacheInfo fragmentCacheInfo = AopUtil.getFragmentFromView(view, activity); + if (fragmentCacheInfo != null) { + AopUtil.getScreenNameAndTitleFromFragmentCacheInfo(object, fragmentCacheInfo, activity); if (info != null && !info.hasFragment) { info.hasFragment = true; }