diff --git a/SensorsAnalyticsSDK.podspec b/SensorsAnalyticsSDK.podspec index f4ba4be7..94efe519 100644 --- a/SensorsAnalyticsSDK.podspec +++ b/SensorsAnalyticsSDK.podspec @@ -1,9 +1,9 @@ Pod::Spec.new do |s| s.name = "SensorsAnalyticsSDK" - s.version = "4.2.1" + s.version = "4.2.2" s.summary = "The official iOS SDK of Sensors Analytics." s.homepage = "http://www.sensorsdata.cn" - s.source = { :git => 'https://github.com/sensorsdata/sa-sdk-ios.git', :tag => "v#{s.version}" } + s.source = { :git => 'https://github.com/sensorsdata/sa-sdk-ios.git', :tag => "v#{s.version}" } s.license = { :type => "Apache License, Version 2.0" } s.author = { "Yuhan ZOU" => "zouyuhan@sensorsdata.cn" } s.ios.deployment_target = '8.0' @@ -11,7 +11,7 @@ Pod::Spec.new do |s| s.default_subspec = 'Core' s.frameworks = 'Foundation', 'SystemConfiguration' - s.libraries = 'icucore', 'sqlite3', 'z' + s.libraries = 'icucore', 'z' s.subspec '__Store' do |ss| ss.source_files = 'SensorsAnalyticsSDK/Store/*.{h,m}' @@ -39,7 +39,7 @@ Pod::Spec.new do |s| c.ios.source_files = 'SensorsAnalyticsSDK/RemoteConfig/**/*.{h,m}', 'SensorsAnalyticsSDK/ChannelMatch/**/*.{h,m}', 'SensorsAnalyticsSDK/Encrypt/**/*.{h,m}', 'SensorsAnalyticsSDK/Deeplink/**/*.{h,m}', 'SensorsAnalyticsSDK/DebugMode/**/*.{h,m}', 'SensorsAnalyticsSDK/Core/SAAlertController.h' c.ios.public_header_files = 'SensorsAnalyticsSDK/{Encrypt,RemoteConfig,ChannelMatch,Deeplink,DebugMode}/{SAConfigOptions,SensorsAnalyticsSDK}+*.h', 'SensorsAnalyticsSDK/Encrypt/SAEncryptProtocol.h', 'SensorsAnalyticsSDK/Encrypt/SASecretKey.h' end - + s.subspec 'Core' do |c| c.ios.dependency 'SensorsAnalyticsSDK/Visualized' c.osx.dependency 'SensorsAnalyticsSDK/Common' diff --git a/SensorsAnalyticsSDK.xcodeproj/project.pbxproj b/SensorsAnalyticsSDK.xcodeproj/project.pbxproj index 38cd86a4..fb46d582 100644 --- a/SensorsAnalyticsSDK.xcodeproj/project.pbxproj +++ b/SensorsAnalyticsSDK.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 451427A12796B353004DE16C /* SAPresetPropertyObjectTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 451427A02796B353004DE16C /* SAPresetPropertyObjectTest.m */; }; + 451427A32796BD85004DE16C /* SAPhonePresetPropertyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 451427A22796BD85004DE16C /* SAPhonePresetPropertyTest.m */; }; + 451427A52796C5A1004DE16C /* SACatalystPresetPropertyTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 451427A42796C5A1004DE16C /* SACatalystPresetPropertyTest.m */; }; 452472C8273E3ACB00865E44 /* SADelegateProxyObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 452472C6273E3ACB00865E44 /* SADelegateProxyObject.h */; }; 452472C9273E3ACB00865E44 /* SADelegateProxyObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 452472C7273E3ACB00865E44 /* SADelegateProxyObject.m */; }; 45A5655C263C174300C9C41B /* SAIDFAHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 45A56548263C174300C9C41B /* SAIDFAHelper.m */; }; @@ -32,6 +35,8 @@ 45A565BD263C17E400C9C41B /* SAReferrerManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 45A565B9263C17E400C9C41B /* SAReferrerManager.m */; }; 45A565BE263C17E400C9C41B /* SAAppLifecycle.m in Sources */ = {isa = PBXBuildFile; fileRef = 45A565BA263C17E400C9C41B /* SAAppLifecycle.m */; }; 45A565BF263C17E400C9C41B /* SAAppLifecycle.h in Headers */ = {isa = PBXBuildFile; fileRef = 45A565BB263C17E400C9C41B /* SAAppLifecycle.h */; }; + 45BBC8CF2787DF22004D2D0C /* SAPresetPropertyObject.h in Headers */ = {isa = PBXBuildFile; fileRef = 45BBC8CD2787DF22004D2D0C /* SAPresetPropertyObject.h */; }; + 45BBC8D02787DF22004D2D0C /* SAPresetPropertyObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 45BBC8CE2787DF22004D2D0C /* SAPresetPropertyObject.m */; }; 45BD80CE26F0B49700DCC759 /* SAThreadSafeDictionary.h in Headers */ = {isa = PBXBuildFile; fileRef = 45BD80CC26F0B49700DCC759 /* SAThreadSafeDictionary.h */; }; 45BD80CF26F0B49700DCC759 /* SAThreadSafeDictionary.m in Sources */ = {isa = PBXBuildFile; fileRef = 45BD80CD26F0B49700DCC759 /* SAThreadSafeDictionary.m */; }; 4D14F13E25FC5BF200113EA2 /* SAVisualizedUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D14F13C25FC5BF200113EA2 /* SAVisualizedUtils.m */; }; @@ -84,8 +89,6 @@ 4DA89BC225C2BC1E003ABA43 /* SAReachability.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DA89BBE25C2BC1E003ABA43 /* SAReachability.h */; }; 4DA89BC325C2BC1E003ABA43 /* SANetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DA89BBF25C2BC1E003ABA43 /* SANetwork.h */; }; 4DA89BC425C2BC1E003ABA43 /* SAReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DA89BC025C2BC1E003ABA43 /* SAReachability.m */; }; - 4DD1281825F8721A008C0B1E /* UIView+SAElementSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DD1281625F8721A008C0B1E /* UIView+SAElementSelector.m */; }; - 4DD1281925F8721A008C0B1E /* UIView+SAElementSelector.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD1281725F8721A008C0B1E /* UIView+SAElementSelector.h */; }; 4DD1282025F87225008C0B1E /* UIView+SAElementPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD1281D25F87225008C0B1E /* UIView+SAElementPath.h */; }; 4DD1282125F87225008C0B1E /* SAVisualizedViewPathProperty.h in Headers */ = {isa = PBXBuildFile; fileRef = 4DD1281E25F87225008C0B1E /* SAVisualizedViewPathProperty.h */; }; 4DD1282225F87225008C0B1E /* UIView+SAElementPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DD1281F25F87225008C0B1E /* UIView+SAElementPath.m */; }; @@ -377,6 +380,9 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 451427A02796B353004DE16C /* SAPresetPropertyObjectTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAPresetPropertyObjectTest.m; sourceTree = ""; }; + 451427A22796BD85004DE16C /* SAPhonePresetPropertyTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAPhonePresetPropertyTest.m; sourceTree = ""; }; + 451427A42796C5A1004DE16C /* SACatalystPresetPropertyTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SACatalystPresetPropertyTest.m; sourceTree = ""; }; 452472C6273E3ACB00865E44 /* SADelegateProxyObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SADelegateProxyObject.h; sourceTree = ""; }; 452472C7273E3ACB00865E44 /* SADelegateProxyObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SADelegateProxyObject.m; sourceTree = ""; }; 45A56548263C174300C9C41B /* SAIDFAHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAIDFAHelper.m; sourceTree = ""; }; @@ -402,6 +408,8 @@ 45A565B9263C17E400C9C41B /* SAReferrerManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAReferrerManager.m; sourceTree = ""; }; 45A565BA263C17E400C9C41B /* SAAppLifecycle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAAppLifecycle.m; sourceTree = ""; }; 45A565BB263C17E400C9C41B /* SAAppLifecycle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SAAppLifecycle.h; sourceTree = ""; }; + 45BBC8CD2787DF22004D2D0C /* SAPresetPropertyObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SAPresetPropertyObject.h; sourceTree = ""; }; + 45BBC8CE2787DF22004D2D0C /* SAPresetPropertyObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAPresetPropertyObject.m; sourceTree = ""; }; 45BD80CC26F0B49700DCC759 /* SAThreadSafeDictionary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SAThreadSafeDictionary.h; sourceTree = ""; }; 45BD80CD26F0B49700DCC759 /* SAThreadSafeDictionary.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAThreadSafeDictionary.m; sourceTree = ""; }; 4D14F13C25FC5BF200113EA2 /* SAVisualizedUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAVisualizedUtils.m; sourceTree = ""; }; @@ -476,8 +484,6 @@ 4DA89BBE25C2BC1E003ABA43 /* SAReachability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SAReachability.h; sourceTree = ""; }; 4DA89BBF25C2BC1E003ABA43 /* SANetwork.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SANetwork.h; sourceTree = ""; }; 4DA89BC025C2BC1E003ABA43 /* SAReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SAReachability.m; sourceTree = ""; }; - 4DD1281625F8721A008C0B1E /* UIView+SAElementSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+SAElementSelector.m"; sourceTree = ""; }; - 4DD1281725F8721A008C0B1E /* UIView+SAElementSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+SAElementSelector.h"; sourceTree = ""; }; 4DD1281D25F87225008C0B1E /* UIView+SAElementPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+SAElementPath.h"; sourceTree = ""; }; 4DD1281E25F87225008C0B1E /* SAVisualizedViewPathProperty.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SAVisualizedViewPathProperty.h; sourceTree = ""; }; 4DD1281F25F87225008C0B1E /* UIView+SAElementPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+SAElementPath.m"; sourceTree = ""; }; @@ -799,6 +805,8 @@ 45A56548263C174300C9C41B /* SAIDFAHelper.m */, 45A5654B263C174300C9C41B /* SAPresetProperty.h */, 45A5655A263C174300C9C41B /* SAPresetProperty.m */, + 45BBC8CD2787DF22004D2D0C /* SAPresetPropertyObject.h */, + 45BBC8CE2787DF22004D2D0C /* SAPresetPropertyObject.m */, 45A5655B263C174300C9C41B /* SASuperProperty.h */, 45A5654A263C174300C9C41B /* SASuperProperty.m */, A8FEFB2A277C0ADA0011D0BB /* SASessionProperty.h */, @@ -833,7 +841,6 @@ 4D754E2626CB58A900300835 /* WebElementInfo */, 4DD128B125F8A003008C0B1E /* Config */, 4D6AE7F626086CED00A9CB08 /* EventCheck */, - 4D0571AA25A2FC46007F7B72 /* ElementSelector */, 4D0571AD25A2FC46007F7B72 /* ElementPath */, 4DD128A625F8A003008C0B1E /* VisualProperties */, 4DD128A525F8A003008C0B1E /* SensorsAnalyticsSDK+Visualized.h */, @@ -877,15 +884,6 @@ path = Visualized; sourceTree = ""; }; - 4D0571AA25A2FC46007F7B72 /* ElementSelector */ = { - isa = PBXGroup; - children = ( - 4DD1281725F8721A008C0B1E /* UIView+SAElementSelector.h */, - 4DD1281625F8721A008C0B1E /* UIView+SAElementSelector.m */, - ); - path = ElementSelector; - sourceTree = ""; - }; 4D0571AD25A2FC46007F7B72 /* ElementPath */ = { isa = PBXGroup; children = ( @@ -1409,6 +1407,9 @@ A8A2BBDC2722AF6F00B2DEDC /* EventObject */, A8A2BBD52722AB6F00B2DEDC /* SAIdentifierTest.m */, A8A2BBD62722AB6F00B2DEDC /* SASuperPropertyTest.m */, + 451427A02796B353004DE16C /* SAPresetPropertyObjectTest.m */, + 451427A22796BD85004DE16C /* SAPhonePresetPropertyTest.m */, + 451427A42796C5A1004DE16C /* SACatalystPresetPropertyTest.m */, ); path = Builder; sourceTree = ""; @@ -1722,6 +1723,7 @@ F277F5C825CF9A43009B5CE6 /* UNUserNotificationCenter+PushClick.h in Headers */, 4DD1282125F87225008C0B1E /* SAVisualizedViewPathProperty.h in Headers */, 4D79695A2609D8FE001B0A6C /* SAEventIdentifier.h in Headers */, + 45BBC8CF2787DF22004D2D0C /* SAPresetPropertyObject.h in Headers */, 45A56562263C174300C9C41B /* SAEventBuildStrategyProtocol.h in Headers */, 88EC2DF7275768DE00EF9778 /* SAFileStorePlugin.h in Headers */, 45A56564263C174300C9C41B /* SATrackEventObject.h in Headers */, @@ -1792,7 +1794,6 @@ F26FDDD8270312C400E1DF32 /* SAConfigOptions+AppPush.h in Headers */, A82E8951267D918100475757 /* SAEncryptProtocol.h in Headers */, 45A56560263C174300C9C41B /* SAIDFAHelper.h in Headers */, - 4DD1281925F8721A008C0B1E /* UIView+SAElementSelector.h in Headers */, A82E8953267D918100475757 /* SAECCEncryptor.h in Headers */, A8356DDB2656459A00FD64AA /* UIViewController+AutoTrack.h in Headers */, 4D6AE7FC26086E9300A9CB08 /* SAVisualizedEventCheck.h in Headers */, @@ -1987,6 +1988,7 @@ A8356DC62656459A00FD64AA /* SAScrollViewDelegateProxy.m in Sources */, F2E4AB9E26EC86C800BA7F01 /* SensorsAnalyticsSDK+Location.m in Sources */, A8356DE52656459A00FD64AA /* SAAppViewScreenTracker.m in Sources */, + 45BBC8D02787DF22004D2D0C /* SAPresetPropertyObject.m in Sources */, F277F5C625CF9A43009B5CE6 /* SAUNUserNotificationCenterDelegateProxy.m in Sources */, F277F5C125CF9A43009B5CE6 /* SANotificationUtil.m in Sources */, 4DA89BC125C2BC1E003ABA43 /* SANetwork.m in Sources */, @@ -2103,7 +2105,6 @@ 4DD1286625F872A4008C0B1E /* SAVisualizedAbstractMessage.m in Sources */, 4DD1282225F87225008C0B1E /* UIView+SAElementPath.m in Sources */, A8356DE02656459A00FD64AA /* SAViewElementInfo.m in Sources */, - 4DD1281825F8721A008C0B1E /* UIView+SAElementSelector.m in Sources */, A8356DD32656459A00FD64AA /* UIGestureRecognizer+SAAutoTrack.m in Sources */, A8356DC92656459A00FD64AA /* UIScrollView+AutoTrack.m in Sources */, 45A56566263C174300C9C41B /* SAProfileEventObject.m in Sources */, @@ -2134,8 +2135,10 @@ 883ED1A22768AF0900A0706A /* SAAESCrypt.m in Sources */, 88C9062F2759EC2B00A2712C /* SAUserDefaultsStorePluginTests.m in Sources */, 88E6BED4277F0CCA006B1E4C /* SAStoreManagerTests.m in Sources */, + 451427A52796C5A1004DE16C /* SACatalystPresetPropertyTest.m in Sources */, 88C9062927589B0C00A2712C /* SAUserDefaultsStorePlugin.m in Sources */, 4D6A189122978F5B00F6B218 /* ElementViewController.m in Sources */, + 451427A12796B353004DE16C /* SAPresetPropertyObjectTest.m in Sources */, 88C9062A27589B1100A2712C /* SAFileStorePlugin.m in Sources */, A8A2BBCB2722AB4900B2DEDC /* SACommonUtilityTest.m in Sources */, A8A2BBDE2722AF8300B2DEDC /* SABaseEventObjectTest.m in Sources */, @@ -2151,6 +2154,7 @@ A8A2BBC72722AB4900B2DEDC /* SAURLUtilsTest.m in Sources */, A8302C402726C65A006E78CC /* SATrackEventObjectTest.m in Sources */, A8A2BBC92722AB4900B2DEDC /* SANSStringHashCodeTest.m in Sources */, + 451427A32796BD85004DE16C /* SAPhonePresetPropertyTest.m in Sources */, A8A2BBCE2722AB4900B2DEDC /* SAUtilsTest.m in Sources */, A8A2BBCF2722AB4900B2DEDC /* SADateFormatterTest.m in Sources */, A8B48EB027281097009C71ED /* SANetworkTest.m in Sources */, diff --git a/SensorsAnalyticsSDK.xcodeproj/xcshareddata/xcbaselines/CB6EBAE2228551EC003CFBA8.xcbaseline/4A4FC828-8637-4FD4-908C-A121843061EE.plist b/SensorsAnalyticsSDK.xcodeproj/xcshareddata/xcbaselines/CB6EBAE2228551EC003CFBA8.xcbaseline/4A4FC828-8637-4FD4-908C-A121843061EE.plist new file mode 100644 index 00000000..1e1f99b1 --- /dev/null +++ b/SensorsAnalyticsSDK.xcodeproj/xcshareddata/xcbaselines/CB6EBAE2228551EC003CFBA8.xcbaseline/4A4FC828-8637-4FD4-908C-A121843061EE.plist @@ -0,0 +1,48 @@ + + + + + classNames + + SACatalystPresetPropertyTest + + testPerformanceProperties + + com.apple.XCTPerformanceMetric_WallClockTime + + baselineAverage + 0.004000 + baselineIntegrationDisplayName + Local Baseline + + + + SAPhonePresetPropertyTest + + testPerformanceProperties + + com.apple.XCTPerformanceMetric_WallClockTime + + baselineAverage + 0.006000 + baselineIntegrationDisplayName + Local Baseline + + + + SAPresetPropertyObjectTest + + testPerformanceProperties + + com.apple.XCTPerformanceMetric_WallClockTime + + baselineAverage + 0.000100 + baselineIntegrationDisplayName + Local Baseline + + + + + + diff --git a/SensorsAnalyticsSDK.xcodeproj/xcshareddata/xcbaselines/CB6EBAE2228551EC003CFBA8.xcbaseline/DD5A9A1D-65DF-4A66-89C9-346053C62E4B.plist b/SensorsAnalyticsSDK.xcodeproj/xcshareddata/xcbaselines/CB6EBAE2228551EC003CFBA8.xcbaseline/DD5A9A1D-65DF-4A66-89C9-346053C62E4B.plist index 7d8736e6..6ff44be2 100644 --- a/SensorsAnalyticsSDK.xcodeproj/xcshareddata/xcbaselines/CB6EBAE2228551EC003CFBA8.xcbaseline/DD5A9A1D-65DF-4A66-89C9-346053C62E4B.plist +++ b/SensorsAnalyticsSDK.xcodeproj/xcshareddata/xcbaselines/CB6EBAE2228551EC003CFBA8.xcbaseline/DD5A9A1D-65DF-4A66-89C9-346053C62E4B.plist @@ -11,7 +11,7 @@ com.apple.XCTPerformanceMetric_WallClockTime baselineAverage - 0.5 + 0.500000 baselineIntegrationDisplayName Local Baseline diff --git a/SensorsAnalyticsSDK.xcodeproj/xcshareddata/xcbaselines/CB6EBAE2228551EC003CFBA8.xcbaseline/Info.plist b/SensorsAnalyticsSDK.xcodeproj/xcshareddata/xcbaselines/CB6EBAE2228551EC003CFBA8.xcbaseline/Info.plist index cb690e46..91b15f23 100644 --- a/SensorsAnalyticsSDK.xcodeproj/xcshareddata/xcbaselines/CB6EBAE2228551EC003CFBA8.xcbaseline/Info.plist +++ b/SensorsAnalyticsSDK.xcodeproj/xcshareddata/xcbaselines/CB6EBAE2228551EC003CFBA8.xcbaseline/Info.plist @@ -4,6 +4,37 @@ runDestinationsByUUID + 4A4FC828-8637-4FD4-908C-A121843061EE + + localComputer + + busSpeedInMHz + 0 + cpuCount + 1 + cpuKind + Apple M1 + cpuSpeedInMHz + 0 + logicalCPUCoresPerPackage + 8 + modelCode + MacBookPro17,1 + physicalCPUCoresPerPackage + 8 + platformIdentifier + com.apple.platform.macosx + + targetArchitecture + arm64 + targetDevice + + modelCode + iPhone13,1 + platformIdentifier + com.apple.platform.iphonesimulator + + 9DB209C1-1E17-44D0-8CD6-73814D5EA805 localComputer diff --git a/SensorsAnalyticsSDK/AutoTrack/AppClick/UIView+AutoTrack.m b/SensorsAnalyticsSDK/AutoTrack/AppClick/UIView+AutoTrack.m index 6ca905f7..f8dda6f4 100644 --- a/SensorsAnalyticsSDK/AutoTrack/AppClick/UIView+AutoTrack.m +++ b/SensorsAnalyticsSDK/AutoTrack/AppClick/UIView+AutoTrack.m @@ -207,7 +207,6 @@ - (NSString *)sensorsdata_elementPosition { } return [NSString stringWithFormat:@"%ld", (long)index]; } - return super.sensorsdata_elementPosition; } diff --git a/SensorsAnalyticsSDK/AutoTrack/AppPageLeave/SAAppPageLeaveTracker.h b/SensorsAnalyticsSDK/AutoTrack/AppPageLeave/SAAppPageLeaveTracker.h index f2d6580a..04b0e620 100644 --- a/SensorsAnalyticsSDK/AutoTrack/AppPageLeave/SAAppPageLeaveTracker.h +++ b/SensorsAnalyticsSDK/AutoTrack/AppPageLeave/SAAppPageLeaveTracker.h @@ -23,15 +23,21 @@ NS_ASSUME_NONNULL_BEGIN +@interface SAPageLeaveObject : NSObject + +@property (nonatomic, weak) UIViewController *viewController; +@property (nonatomic, assign) NSTimeInterval timestamp; +@property (nonatomic, copy) NSString *referrerURL; + +@end + @interface SAAppPageLeaveTracker : SAAppTracker -@property (nonatomic, strong) NSMutableDictionary *timestamp; +@property (nonatomic, strong) NSMutableDictionary *pageLeaveObjects; - (void)trackEvents; - (void)trackPageEnter:(UIViewController *)viewController; - (void)trackPageLeave:(UIViewController *)viewController; -- (NSDictionary *)propertiesWithViewController:(UIViewController *)viewController; -- (BOOL)shouldTrackViewController:(UIViewController *)viewController; @end diff --git a/SensorsAnalyticsSDK/AutoTrack/AppPageLeave/SAAppPageLeaveTracker.m b/SensorsAnalyticsSDK/AutoTrack/AppPageLeave/SAAppPageLeaveTracker.m index 4344feb9..57b0686d 100644 --- a/SensorsAnalyticsSDK/AutoTrack/AppPageLeave/SAAppPageLeaveTracker.m +++ b/SensorsAnalyticsSDK/AutoTrack/AppPageLeave/SAAppPageLeaveTracker.m @@ -31,10 +31,13 @@ #import "SensorsAnalyticsSDK+Private.h" #import "SAAutoTrackManager.h" +@implementation SAPageLeaveObject + +@end + @interface SAAppPageLeaveTracker () -@property (nonatomic, copy, readwrite) NSDictionary *referrerProperties; -@property (nonatomic, copy, readwrite) NSString *referrerURL; +@property (nonatomic, copy) NSString *referrerURL; @end @@ -53,13 +56,18 @@ - (NSString *)eventId { } - (void)trackEvents { - [self.timestamp enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSMutableDictionary * _Nonnull obj, BOOL * _Nonnull stop) { + [self.pageLeaveObjects enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, SAPageLeaveObject * _Nonnull obj, BOOL * _Nonnull stop) { + if (!obj.viewController) { + return; + } NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970]; - NSNumber *timestamp = obj[kSAPageLeaveTimestamp]; - NSTimeInterval startTimestamp = [timestamp doubleValue]; - NSMutableDictionary *tempProperties = [[NSMutableDictionary alloc] initWithDictionary:obj[kSAPageLeaveAutoTrackProperties]]; + NSTimeInterval startTimestamp = obj.timestamp; + NSMutableDictionary *tempProperties = [[NSMutableDictionary alloc] initWithDictionary:[self propertiesWithViewController:obj.viewController]]; NSTimeInterval duration = (currentTimestamp - startTimestamp) < 24 * 60 * 60 ? (currentTimestamp - startTimestamp) : 0; tempProperties[kSAEventDurationProperty] = @([[NSString stringWithFormat:@"%.3f", duration] floatValue]); + if (obj.referrerURL) { + tempProperties[kSAEventPropertyScreenReferrerUrl] = obj.referrerURL; + } [self trackWithProperties:[tempProperties copy]]; }]; } @@ -69,13 +77,20 @@ - (void)trackPageEnter:(UIViewController *)viewController { return; } NSString *address = [NSString stringWithFormat:@"%p", viewController]; - if (self.timestamp[address]) { + if (self.pageLeaveObjects[address]) { return; } - NSMutableDictionary *properties = [[NSMutableDictionary alloc] init]; - properties[kSAPageLeaveTimestamp] = @([[NSDate date] timeIntervalSince1970]); - properties[kSAPageLeaveAutoTrackProperties] = [self propertiesWithViewController:viewController]; - self.timestamp[address] = properties; + SAPageLeaveObject *object = [[SAPageLeaveObject alloc] init]; + object.timestamp = [[NSDate date] timeIntervalSince1970]; + object.viewController = viewController; + NSString *currentURL; + if ([viewController conformsToProtocol:@protocol(SAScreenAutoTracker)] && [viewController respondsToSelector:@selector(getScreenUrl)]) { + UIViewController *screenAutoTrackerController = (UIViewController *)viewController; + currentURL = [screenAutoTrackerController getScreenUrl]; + } + currentURL = [currentURL isKindOfClass:NSString.class] ? currentURL : NSStringFromClass(viewController.class); + object.referrerURL = [self referrerURLWithURL:currentURL eventProperties:[SAAutoTrackUtils propertiesWithViewController:(UIViewController *)viewController]]; + self.pageLeaveObjects[address] = object; } - (void)trackPageLeave:(UIViewController *)viewController { @@ -83,18 +98,20 @@ - (void)trackPageLeave:(UIViewController *)viewController { return; } NSString *address = [NSString stringWithFormat:@"%p", viewController]; - if (!self.timestamp[address]) { + SAPageLeaveObject *object = self.pageLeaveObjects[address]; + if (!object) { return; } NSTimeInterval currentTimestamp = [[NSDate date] timeIntervalSince1970]; - NSMutableDictionary *properties = self.timestamp[address]; - NSNumber *timestamp = properties[kSAPageLeaveTimestamp]; - NSTimeInterval startTimestamp = [timestamp doubleValue]; - NSMutableDictionary *tempProperties = [[NSMutableDictionary alloc] initWithDictionary:properties[kSAPageLeaveAutoTrackProperties]]; + NSTimeInterval startTimestamp = object.timestamp; + NSMutableDictionary *tempProperties = [self propertiesWithViewController:(UIViewController *)(object.viewController)]; NSTimeInterval duration = (currentTimestamp - startTimestamp) < 24 * 60 * 60 ? (currentTimestamp - startTimestamp) : 0; tempProperties[kSAEventDurationProperty] = @([[NSString stringWithFormat:@"%.3f", duration] floatValue]); + if (object.referrerURL) { + tempProperties[kSAEventPropertyScreenReferrerUrl] = object.referrerURL; + } [self trackWithProperties:tempProperties]; - [self.timestamp removeObjectForKey:address]; + [self.pageLeaveObjects removeObjectForKey:address]; } - (void)trackWithProperties:(NSDictionary *)properties { @@ -107,37 +124,35 @@ - (void)appLifecycleStateWillChange:(NSNotification *)notification { SAAppLifecycleState newState = [userInfo[kSAAppLifecycleNewStateKey] integerValue]; // 冷(热)启动 if (newState == SAAppLifecycleStateStart) { - [self.timestamp enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSMutableDictionary * _Nonnull obj, BOOL * _Nonnull stop) { - obj[kSAPageLeaveTimestamp] = @([[NSDate date] timeIntervalSince1970]); + [self.pageLeaveObjects enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, SAPageLeaveObject * _Nonnull obj, BOOL * _Nonnull stop) { + obj.timestamp = [[NSDate date] timeIntervalSince1970]; }]; return; } - // 退出 if (newState == SAAppLifecycleStateEnd) { [self trackEvents]; } } -- (NSDictionary *)propertiesWithViewController:(UIViewController *)viewController { +- (NSMutableDictionary *)propertiesWithViewController:(UIViewController *)viewController { NSMutableDictionary *eventProperties = [[NSMutableDictionary alloc] init]; NSDictionary *autoTrackProperties = [SAAutoTrackUtils propertiesWithViewController:viewController]; [eventProperties addEntriesFromDictionary:autoTrackProperties]; - + if (eventProperties[kSAEventPropertyScreenUrl]) { + return eventProperties; + } NSString *currentURL; if ([viewController conformsToProtocol:@protocol(SAScreenAutoTracker)] && [viewController respondsToSelector:@selector(getScreenUrl)]) { UIViewController *screenAutoTrackerController = (UIViewController *)viewController; currentURL = [screenAutoTrackerController getScreenUrl]; } currentURL = [currentURL isKindOfClass:NSString.class] ? currentURL : NSStringFromClass(viewController.class); - - // 添加 $url 和 $referrer 页面浏览相关属性 - NSDictionary *newProperties = [self propertiesWithURL:currentURL eventProperties:eventProperties]; - - return newProperties; + eventProperties[kSAEventPropertyScreenUrl] = currentURL; + return eventProperties; } -- (NSDictionary *)propertiesWithURL:(NSString *)currentURL eventProperties:(NSDictionary *)eventProperties { +- (NSString *)referrerURLWithURL:(NSString *)currentURL eventProperties:(NSDictionary *)eventProperties { NSString *referrerURL = self.referrerURL; NSMutableDictionary *newProperties = [NSMutableDictionary dictionaryWithDictionary:eventProperties]; @@ -151,9 +166,8 @@ - (NSDictionary *)propertiesWithURL:(NSString *)currentURL eventProperties:(NSDi } // $referrer 内容以最终页面浏览事件中的 $url 为准 self.referrerURL = newProperties[kSAEventPropertyScreenUrl]; - self.referrerProperties = newProperties; - return newProperties; + return newProperties[kSAEventPropertyScreenReferrerUrl]; } - (BOOL)shouldTrackViewController:(UIViewController *)viewController { @@ -173,11 +187,11 @@ - (BOOL)shouldTrackViewController:(UIViewController *)viewController { return NO; } -- (NSMutableDictionary *)timestamp { - if (!_timestamp) { - _timestamp = [[NSMutableDictionary alloc] init]; +- (NSMutableDictionary *)pageLeaveObjects { + if (!_pageLeaveObjects) { + _pageLeaveObjects = [[NSMutableDictionary alloc] init]; } - return _timestamp; + return _pageLeaveObjects; } @end diff --git a/SensorsAnalyticsSDK/AutoTrack/SAAutoTrackManager.m b/SensorsAnalyticsSDK/AutoTrack/SAAutoTrackManager.m index e5e2faad..333e607d 100644 --- a/SensorsAnalyticsSDK/AutoTrack/SAAutoTrackManager.m +++ b/SensorsAnalyticsSDK/AutoTrack/SAAutoTrackManager.m @@ -111,7 +111,7 @@ - (void)setEnable:(BOOL)enable { [self registerPlugins]; return; } - [self.appPageLeaveTracker.timestamp removeAllObjects]; + [self.appPageLeaveTracker.pageLeaveObjects removeAllObjects]; [self unregisterPlugins]; } diff --git a/SensorsAnalyticsSDK/AutoTrack/SAAutoTrackUtils.h b/SensorsAnalyticsSDK/AutoTrack/SAAutoTrackUtils.h index 98dfc24c..1f6a3bbd 100644 --- a/SensorsAnalyticsSDK/AutoTrack/SAAutoTrackUtils.h +++ b/SensorsAnalyticsSDK/AutoTrack/SAAutoTrackUtils.h @@ -54,8 +54,7 @@ NS_ASSUME_NONNULL_BEGIN /** 通过响应链找到 对象的序号 - -2:nextResponder 不是父视图或同类元素,比如 controller.view,涉及路径不带序号 - -1:同级只存在一个同类元素,兼容 $element_selector 逻辑 + -1:nextResponder 不是父视图或同类元素,比如 controller.view,涉及路径不带序号 >=0:元素序号 @param responder 响应链中的对象,可以是 UIView 或者 UIViewController diff --git a/SensorsAnalyticsSDK/AutoTrack/SAAutoTrackUtils.m b/SensorsAnalyticsSDK/AutoTrack/SAAutoTrackUtils.m index 97d0c8d8..c8e1fb34 100644 --- a/SensorsAnalyticsSDK/AutoTrack/SAAutoTrackUtils.m +++ b/SensorsAnalyticsSDK/AutoTrack/SAAutoTrackUtils.m @@ -181,30 +181,24 @@ @implementation SAAutoTrackUtils (Property) + (NSInteger)itemIndexForResponder:(UIResponder *)responder { NSString *classString = NSStringFromClass(responder.class); - NSInteger count = 0; + NSInteger index = -1; NSArray *brothersResponder = [self brothersElementForResponder:responder]; for (UIResponder *res in brothersResponder) { if ([classString isEqualToString:NSStringFromClass(res.class)]) { - count++; + index ++; } if (res == responder) { - index = count - 1; + break; } } - // 单个 UIViewController(即不存在其他兄弟 viewController) 拼接路径,不需要序号 - if ([responder isKindOfClass:UIViewController.class] && ![responder isKindOfClass:UIAlertController.class] && count == 1) { - return -2; - } /* 序号说明 - -2:nextResponder 不是父视图或同类元素,比如 controller.view,涉及路径不带序号 - -1:同级只存在一个同类元素 + -1:nextResponder 不是父视图或同类元素,比如 controller.view,涉及路径不带序号 >=0:元素序号 */ - // 如果 responder 是 UIViewController.view,此时 count = 0 - return count == 0 || count == 1 ? count - 2 : index; + return index; } /// 寻找所有兄弟元素 diff --git a/SensorsAnalyticsSDK/Core/Builder/SAPresetProperty.h b/SensorsAnalyticsSDK/Core/Builder/SAPresetProperty.h index f76fc06d..ac33a75a 100644 --- a/SensorsAnalyticsSDK/Core/Builder/SAPresetProperty.h +++ b/SensorsAnalyticsSDK/Core/Builder/SAPresetProperty.h @@ -34,11 +34,10 @@ extern NSString * const kSAEventPresetPropertyIsFirstDay; 初始化方法 @param queue 一个全局队列 - @param libVersion SDK 版本 @return 初始化对象 */ -- (instancetype)initWithQueue:(dispatch_queue_t)queue libVersion:(NSString *)libVersion NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithQueue:(dispatch_queue_t)queue NS_DESIGNATED_INITIALIZER; /// 禁用 init 初始化 - (instancetype)init NS_UNAVAILABLE; diff --git a/SensorsAnalyticsSDK/Core/Builder/SAPresetProperty.m b/SensorsAnalyticsSDK/Core/Builder/SAPresetProperty.m index 6d6ffd14..66c0b242 100644 --- a/SensorsAnalyticsSDK/Core/Builder/SAPresetProperty.m +++ b/SensorsAnalyticsSDK/Core/Builder/SAPresetProperty.m @@ -22,7 +22,6 @@ #error This file must be compiled with ARC. Either turn on ARC for the project or use -fobjc-arc flag on this file. #endif -#include #import "SAPresetProperty.h" #import "SAConstants+Private.h" #import "SAIdentifier.h" @@ -36,11 +35,6 @@ #import "SAModuleManager.h" #import "SAJSONUtil.h" -#if TARGET_OS_IOS -#import -#import -#endif - #pragma mark - state /// 网络类型 NSString * const kSAEventPresetPropertyNetworkType = @"$network_type"; @@ -56,7 +50,6 @@ @interface SAPresetProperty () @property (nonatomic, strong) dispatch_queue_t queue; @property (nonatomic, copy) NSString *firstDay; -@property (nonatomic, copy) NSString *libVersion; @end @@ -64,13 +57,12 @@ @implementation SAPresetProperty #pragma mark - Life Cycle -- (instancetype)initWithQueue:(dispatch_queue_t)queue libVersion:(NSString *)libVersion { +- (instancetype)initWithQueue:(dispatch_queue_t)queue { self = [super init]; if (self) { _queue = queue; dispatch_async(self.queue, ^{ - self.libVersion = libVersion; [self unarchiveFirstDay]; }); } diff --git a/SensorsAnalyticsSDK/Core/Builder/SAPresetPropertyObject.h b/SensorsAnalyticsSDK/Core/Builder/SAPresetPropertyObject.h new file mode 100644 index 00000000..2a45524e --- /dev/null +++ b/SensorsAnalyticsSDK/Core/Builder/SAPresetPropertyObject.h @@ -0,0 +1,58 @@ +// +// SAPresetPropertyObject.h +// SensorsAnalyticsSDK +// +// Created by yuqiang on 2022/1/7. +// Copyright © 2022 Sensors Data Co., Ltd. All rights reserved. +// +// 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. +// + +#import + +NS_ASSUME_NONNULL_BEGIN +@interface SAPresetPropertyObject : NSObject + +- (NSString *)manufacturer; +- (NSString *)os; +- (NSString *)osVersion; +- (NSString *)deviceModel; +- (NSString *)lib; +- (NSInteger)screenHeight; +- (NSInteger)screenWidth; +- (NSString *)carrier; +- (NSString *)appID; +- (NSString *)appName; +- (NSInteger)timezoneOffset; + +- (NSMutableDictionary *)properties; + +@end + +#if TARGET_OS_IOS +@interface SAPhonePresetProperty : SAPresetPropertyObject + +@end + +@interface SACatalystPresetProperty : SAPresetPropertyObject + +@end +#endif + +#if TARGET_OS_OSX +@interface SAMacPresetProperty : SAPresetPropertyObject + +@end +#endif + +NS_ASSUME_NONNULL_END diff --git a/SensorsAnalyticsSDK/Core/Builder/SAPresetPropertyObject.m b/SensorsAnalyticsSDK/Core/Builder/SAPresetPropertyObject.m new file mode 100644 index 00000000..ce0bcbbe --- /dev/null +++ b/SensorsAnalyticsSDK/Core/Builder/SAPresetPropertyObject.m @@ -0,0 +1,322 @@ +// +// SAPresetPropertyObject.m +// SensorsAnalyticsSDK +// +// Created by yuqiang on 2022/1/7. +// Copyright © 2015-2022 Sensors Data Co., Ltd. All rights reserved. +// +// 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. +// + +#if ! __has_feature(objc_arc) +#error This file must be compiled with ARC. Either turn on ARC for the project or use -fobjc-arc flag on this file. +#endif + +#import "SAPresetPropertyObject.h" +#include +#import "SALog.h" +#import "SAJSONUtil.h" + +#if TARGET_OS_IOS +#import +#endif + +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST +#import +#import +#endif + +@implementation SAPresetPropertyObject + +#pragma mark - device +/// 型号 +static NSString * const kSAEventPresetPropertyPluginCarrier = @"$carrier"; +/// 型号 +static NSString * const kSAEventPresetPropertyPluginModel = @"$model"; +/// 生产商 +static NSString * const kSAEventPresetPropertyPluginManufacturer = @"$manufacturer"; +/// 屏幕高 +static NSString * const kSAEventPresetPropertyPluginScreenHeight = @"$screen_height"; +/// 屏幕宽 +static NSString * const kSAEventPresetPropertyPluginScreenWidth = @"$screen_width"; + +#pragma mark - os +/// 系统 +static NSString * const kSAEventPresetPropertyPluginOS = @"$os"; +/// 系统版本 +static NSString * const kSAEventPresetPropertyPluginOSVersion = @"$os_version"; + +#pragma mark - app +/// 应用 ID +static NSString * const SAEventPresetPropertyPluginAppID = @"$app_id"; +/// 应用名称 +static NSString * const kSAEventPresetPropertyPluginAppName = @"$app_name"; +/// 时区偏移量 +static NSString * const kSAEventPresetPropertyPluginTimezoneOffset = @"$timezone_offset"; + +#pragma mark - lib +/// SDK 类型 +NSString * const kSAEventPresetPropertyPluginLib = @"$lib"; + +#pragma mark - preset property +- (NSString *)manufacturer { + return @"Apple"; +} + +- (NSString *)os { + return nil; +} + +- (NSString *)osVersion { + return nil; +} + +- (NSString *)deviceModel { + return nil; +} + +- (NSString *)lib { + return nil; +} + +- (NSInteger)screenHeight { + return 0; +} + +- (NSInteger)screenWidth { + return 0; +} + +- (NSString *)carrier { + return nil; +} + +- (NSString *)appID { + return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; +} + +- (NSString *)appName { + NSString *displayName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; + if (displayName.length > 0) { + return displayName; + } + + NSString *bundleName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; + if (bundleName.length > 0) { + return bundleName; + } + + return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"]; +} + +- (NSInteger)timezoneOffset { + // 计算时区偏移(保持和 JS 获取时区偏移的计算结果一致,这里首先获取分钟数,然后取反) + NSInteger minutesOffsetGMT = - ([[NSTimeZone defaultTimeZone] secondsFromGMT] / 60); + return minutesOffsetGMT; +} + +- (NSMutableDictionary *)properties { + NSMutableDictionary *properties = [NSMutableDictionary dictionary]; + properties[kSAEventPresetPropertyPluginModel] = self.deviceModel; + properties[kSAEventPresetPropertyPluginManufacturer] = self.manufacturer; + properties[kSAEventPresetPropertyPluginCarrier] = self.carrier; + properties[kSAEventPresetPropertyPluginOS] = self.os; + properties[kSAEventPresetPropertyPluginOSVersion] = self.osVersion; + properties[kSAEventPresetPropertyPluginLib] = self.lib; + properties[SAEventPresetPropertyPluginAppID] = self.appID; + properties[kSAEventPresetPropertyPluginAppName] = self.appName; + properties[kSAEventPresetPropertyPluginScreenHeight] = @(self.screenHeight); + properties[kSAEventPresetPropertyPluginScreenWidth] = @(self.screenWidth); + properties[kSAEventPresetPropertyPluginTimezoneOffset] = @(self.timezoneOffset); + return properties; +} + +#pragma mark - util +- (NSString *)sysctlByName:(NSString *)name { + NSString *result = nil; + @try { + size_t size; + sysctlbyname([name UTF8String], NULL, &size, NULL, 0); + char answer[size]; + sysctlbyname([name UTF8String], answer, &size, NULL, 0); + if (size) { + result = @(answer); + } else { + SALogError(@"Failed fetch %@ from sysctl.", name); + } + } @catch (NSException *exception) { + SALogError(@"%@: %@", self, exception); + } + return result; +} + +@end + +#if TARGET_OS_IOS +@implementation SAPhonePresetProperty + +- (NSString *)deviceModel { + return [self sysctlByName:@"hw.machine"]; +} + +- (NSString *)lib { + return @"iOS"; +} + +- (NSString *)os { + return @"iOS"; +} + +- (NSString *)osVersion { + return [[UIDevice currentDevice] systemVersion]; +} + +- (NSInteger)screenHeight { + return (NSInteger)UIScreen.mainScreen.bounds.size.height; +} + +- (NSInteger)screenWidth { + return (NSInteger)UIScreen.mainScreen.bounds.size.width; +} + +#if !TARGET_OS_MACCATALYST +- (NSString *)carrier { + NSString *carrierName = nil; + + @try { + CTTelephonyNetworkInfo *telephonyInfo = [[CTTelephonyNetworkInfo alloc] init]; + CTCarrier *carrier = nil; + +#ifdef __IPHONE_12_0 + if (@available(iOS 12.1, *)) { + // 排序 + NSArray *carrierKeysArray = [telephonyInfo.serviceSubscriberCellularProviders.allKeys sortedArrayUsingSelector:@selector(compare:)]; + carrier = telephonyInfo.serviceSubscriberCellularProviders[carrierKeysArray.firstObject]; + if (!carrier.mobileNetworkCode) { + carrier = telephonyInfo.serviceSubscriberCellularProviders[carrierKeysArray.lastObject]; + } + } +#endif + if (!carrier) { + carrier = telephonyInfo.subscriberCellularProvider; + } + if (carrier != nil) { + NSString *networkCode = [carrier mobileNetworkCode]; + NSString *countryCode = [carrier mobileCountryCode]; + + // 中国运营商 mcc 标识 + NSString *carrierChinaMCC = @"460"; + + //中国运营商 + if (countryCode && [countryCode isEqualToString:carrierChinaMCC] && networkCode) { + //中国移动 + if ([networkCode isEqualToString:@"00"] || [networkCode isEqualToString:@"02"] || [networkCode isEqualToString:@"07"] || [networkCode isEqualToString:@"08"]) { + carrierName = @"中国移动"; + } + //中国联通 + if ([networkCode isEqualToString:@"01"] || [networkCode isEqualToString:@"06"] || [networkCode isEqualToString:@"09"]) { + carrierName = @"中国联通"; + } + //中国电信 + if ([networkCode isEqualToString:@"03"] || [networkCode isEqualToString:@"05"] || [networkCode isEqualToString:@"11"]) { + carrierName = @"中国电信"; + } + //中国卫通 + if ([networkCode isEqualToString:@"04"]) { + carrierName = @"中国卫通"; + } + //中国铁通 + if ([networkCode isEqualToString:@"20"]) { + carrierName = @"中国铁通"; + } + } else if (countryCode && networkCode) { //国外运营商解析 + //加载当前 bundle + NSBundle *sensorsBundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"SensorsAnalyticsSDK" ofType:@"bundle"]]; + //文件路径 + NSString *jsonPath = [sensorsBundle pathForResource:@"sa_mcc_mnc_mini.json" ofType:nil]; + NSData *jsonData = [NSData dataWithContentsOfFile:jsonPath]; + NSDictionary *dicAllMcc = [SAJSONUtil JSONObjectWithData:jsonData]; + if (dicAllMcc) { + NSString *mccMncKey = [NSString stringWithFormat:@"%@%@", countryCode, networkCode]; + carrierName = dicAllMcc[mccMncKey]; + } + } + } + } @catch (NSException *exception) { + SALogError(@"%@: %@", self, exception); + } + return carrierName; +} +#endif + +@end + +@implementation SACatalystPresetProperty + +- (NSString *)deviceModel { + return [self sysctlByName:@"hw.model"]; +} + +- (NSString *)lib { + return @"iOS"; +} + +- (NSString *)os { + return @"macOS"; +} + +- (NSString *)osVersion { + return [self sysctlByName:@"kern.osproductversion"]; +} + +- (NSInteger)screenHeight { + return (NSInteger)UIScreen.mainScreen.bounds.size.height; +} + +- (NSInteger)screenWidth { + return (NSInteger)UIScreen.mainScreen.bounds.size.width; +} + +@end +#endif + +#if TARGET_OS_OSX +@implementation SAMacPresetProperty + +- (NSString *)deviceModel { + return [self sysctlByName:@"hw.model"]; +} + +- (NSString *)lib { + return @"macOS"; +} + +- (NSString *)os { + return @"macOS"; +} + +- (NSString *)osVersion { + NSDictionary *systemVersion = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]; + return systemVersion[@"ProductVersion"]; +} + +- (NSInteger)screenHeight { + return (NSInteger)NSScreen.mainScreen.frame.size.height; +} + +- (NSInteger)screenWidth { + return (NSInteger)NSScreen.mainScreen.frame.size.width; +} + +@end +#endif diff --git a/SensorsAnalyticsSDK/Core/Network/SANetwork.m b/SensorsAnalyticsSDK/Core/Network/SANetwork.m index 37fac1f8..21ddeb41 100644 --- a/SensorsAnalyticsSDK/Core/Network/SANetwork.m +++ b/SensorsAnalyticsSDK/Core/Network/SANetwork.m @@ -34,7 +34,7 @@ #import "SAHTTPSession.h" #import "SAReachability.h" -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST #import #endif @@ -144,7 +144,7 @@ + (SensorsAnalyticsNetworkType)networkTypeOptions { } SensorsAnalyticsNetworkType networkType = SensorsAnalyticsNetworkTypeNONE; -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST networkType = [self networkTypeWWANOptionsWithString:networkTypeString]; #endif return networkType; @@ -156,7 +156,7 @@ + (NSString *)networkTypeString { if ([SAReachability sharedInstance].isReachableViaWiFi) { networkTypeString = @"WIFI"; } -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST else { networkTypeString = [self networkTypeWWANString]; } @@ -167,7 +167,7 @@ + (NSString *)networkTypeString { return networkTypeString; } -#if TARGET_OS_IOS +#if TARGET_OS_IOS && !TARGET_OS_MACCATALYST + (SensorsAnalyticsNetworkType)networkTypeWWANOptionsWithString:(NSString *)networkTypeString { if ([@"2G" isEqualToString:networkTypeString]) { return SensorsAnalyticsNetworkType2G; diff --git a/SensorsAnalyticsSDK/Core/PropertyPlugin/SAPresetPropertyPlugin.m b/SensorsAnalyticsSDK/Core/PropertyPlugin/SAPresetPropertyPlugin.m index cd24e412..a5b8d387 100644 --- a/SensorsAnalyticsSDK/Core/PropertyPlugin/SAPresetPropertyPlugin.m +++ b/SensorsAnalyticsSDK/Core/PropertyPlugin/SAPresetPropertyPlugin.m @@ -22,49 +22,9 @@ #error This file must be compiled with ARC. Either turn on ARC for the project or use -fobjc-arc flag on this file. #endif -#include #import "SAPresetPropertyPlugin.h" -#import "SAJSONUtil.h" -#import "SALog.h" +#import "SAPresetPropertyObject.h" -#if TARGET_OS_IOS -#import -#import -#import -#endif - -//中国运营商 mcc 标识 -static NSString* const SACarrierChinaMCC = @"460"; - -#pragma mark - device -/// 型号 -static NSString * const kSAEventPresetPropertyPluginCarrier = @"$carrier"; -/// 型号 -static NSString * const kSAEventPresetPropertyPluginModel = @"$model"; -/// 生产商 -static NSString * const kSAEventPresetPropertyPluginManufacturer = @"$manufacturer"; -/// 屏幕高 -static NSString * const kSAEventPresetPropertyPluginScreenHeight = @"$screen_height"; -/// 屏幕宽 -static NSString * const kSAEventPresetPropertyPluginScreenWidth = @"$screen_width"; - -#pragma mark - os -/// 系统 -static NSString * const kSAEventPresetPropertyPluginOS = @"$os"; -/// 系统版本 -static NSString * const kSAEventPresetPropertyPluginOSVersion = @"$os_version"; - -#pragma mark - app -/// 应用 ID -static NSString * const SAEventPresetPropertyPluginAppID = @"$app_id"; -/// 应用名称 -static NSString * const kSAEventPresetPropertyPluginAppName = @"$app_name"; -/// 时区偏移量 -static NSString * const kSAEventPresetPropertyPluginTimezoneOffset = @"$timezone_offset"; - -#pragma mark - lib -/// SDK 类型 -NSString * const kSAEventPresetPropertyPluginLib = @"$lib"; /// SDK 版本 NSString * const kSAEventPresetPropertyPluginLibVersion = @"$lib_version"; @@ -93,147 +53,38 @@ - (SAPropertyPluginPriority)priority { } - (void)start { - NSMutableDictionary *properties = [NSMutableDictionary dictionary]; - properties[kSAEventPresetPropertyPluginModel] = [self deviceModel]; - properties[kSAEventPresetPropertyPluginManufacturer] = @"Apple"; - + SAPresetPropertyObject *propertyObject; #if TARGET_OS_IOS - properties[kSAEventPresetPropertyPluginCarrier] = [self carrierName]; - properties[kSAEventPresetPropertyPluginOS] = @"iOS"; - properties[kSAEventPresetPropertyPluginOSVersion] = [[UIDevice currentDevice] systemVersion]; - properties[kSAEventPresetPropertyPluginLib] = @"iOS"; - - CGSize size = [UIScreen mainScreen].bounds.size; + if ([self isiOSAppOnMac]) { + propertyObject = [[SACatalystPresetProperty alloc] init]; + } else { + propertyObject = [[SAPhonePresetProperty alloc] init]; + } #elif TARGET_OS_OSX - - properties[kSAEventPresetPropertyPluginOS] = @"macOS"; - properties[kSAEventPresetPropertyPluginLib] = @"macOS"; - - NSDictionary *systemVersion = [NSDictionary dictionaryWithContentsOfFile:@"/System/Library/CoreServices/SystemVersion.plist"]; - properties[kSAEventPresetPropertyPluginOSVersion] = systemVersion[@"ProductVersion"]; - - CGSize size = [NSScreen mainScreen].frame.size; + propertyObject = [[SAMacPresetProperty alloc] init]; #endif - properties[SAEventPresetPropertyPluginAppID] = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; - properties[kSAEventPresetPropertyPluginAppName] = [self appName]; - - properties[kSAEventPresetPropertyPluginScreenHeight] = @((NSInteger)size.height); - properties[kSAEventPresetPropertyPluginScreenWidth] = @((NSInteger)size.width); - + NSMutableDictionary *properties = [NSMutableDictionary dictionary]; + [properties addEntriesFromDictionary:propertyObject.properties]; properties[kSAEventPresetPropertyPluginLibVersion] = self.libVersion; - // 计算时区偏移(保持和 JS 获取时区偏移的计算结果一致,这里首先获取分钟数,然后取反) - NSInteger minutesOffsetGMT = - ([[NSTimeZone defaultTimeZone] secondsFromGMT] / 60); - properties[kSAEventPresetPropertyPluginTimezoneOffset] = @(minutesOffsetGMT); self.properties = properties; } -- (NSString *)deviceModel { - NSString *result = nil; - @try { - NSString *hwName = @"hw.machine"; -#if TARGET_OS_OSX - hwName = @"hw.model"; -#endif - size_t size; - sysctlbyname([hwName UTF8String], NULL, &size, NULL, 0); - char answer[size]; - sysctlbyname([hwName UTF8String], answer, &size, NULL, 0); - if (size) { - result = @(answer); - } - } @catch (NSException *exception) { - - } - return result; -} - -- (NSString *)appName { - NSString *displayName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; - if (displayName.length > 0) { - return displayName; - } - - NSString *bundleName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; - if (bundleName.length > 0) { - return bundleName; - } - - NSString *executableName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"]; - if (executableName) { - return executableName; - } - - return nil; -} - #if TARGET_OS_IOS -- (NSString *)carrierName API_UNAVAILABLE(macos) { - NSString *carrierName = nil; - - @try { - CTTelephonyNetworkInfo *telephonyInfo = [[CTTelephonyNetworkInfo alloc] init]; - CTCarrier *carrier = nil; - -#ifdef __IPHONE_12_0 - if (@available(iOS 12.1, *)) { - // 排序 - NSArray *carrierKeysArray = [telephonyInfo.serviceSubscriberCellularProviders.allKeys sortedArrayUsingSelector:@selector(compare:)]; - carrier = telephonyInfo.serviceSubscriberCellularProviders[carrierKeysArray.firstObject]; - if (!carrier.mobileNetworkCode) { - carrier = telephonyInfo.serviceSubscriberCellularProviders[carrierKeysArray.lastObject]; - } +- (BOOL)isiOSAppOnMac { + if (@available(iOS 14.0, macOS 11.0, *)) { + if ([NSProcessInfo processInfo].isiOSAppOnMac) { + return YES; } -#endif - if (!carrier) { - carrier = telephonyInfo.subscriberCellularProvider; - } - if (carrier != nil) { - NSString *networkCode = [carrier mobileNetworkCode]; - NSString *countryCode = [carrier mobileCountryCode]; - - //中国运营商 - if (countryCode && [countryCode isEqualToString:SACarrierChinaMCC] && networkCode) { - //中国移动 - if ([networkCode isEqualToString:@"00"] || [networkCode isEqualToString:@"02"] || [networkCode isEqualToString:@"07"] || [networkCode isEqualToString:@"08"]) { - carrierName = @"中国移动"; - } - //中国联通 - if ([networkCode isEqualToString:@"01"] || [networkCode isEqualToString:@"06"] || [networkCode isEqualToString:@"09"]) { - carrierName = @"中国联通"; - } - //中国电信 - if ([networkCode isEqualToString:@"03"] || [networkCode isEqualToString:@"05"] || [networkCode isEqualToString:@"11"]) { - carrierName = @"中国电信"; - } - //中国卫通 - if ([networkCode isEqualToString:@"04"]) { - carrierName = @"中国卫通"; - } - //中国铁通 - if ([networkCode isEqualToString:@"20"]) { - carrierName = @"中国铁通"; - } - } else if (countryCode && networkCode) { //国外运营商解析 - //加载当前 bundle - NSBundle *sensorsBundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"SensorsAnalyticsSDK" ofType:@"bundle"]]; - //文件路径 - NSString *jsonPath = [sensorsBundle pathForResource:@"sa_mcc_mnc_mini.json" ofType:nil]; - NSData *jsonData = [NSData dataWithContentsOfFile:jsonPath]; - NSDictionary *dicAllMcc = [SAJSONUtil JSONObjectWithData:jsonData]; - if (dicAllMcc) { - NSString *mccMncKey = [NSString stringWithFormat:@"%@%@", countryCode, networkCode]; - carrierName = dicAllMcc[mccMncKey]; - } - } + } + if (@available(iOS 13.0, macOS 10.15, *)) { + if ([NSProcessInfo processInfo].isMacCatalystApp) { + return YES; } - } @catch (NSException *exception) { - SALogError(@"%@: %@", self, exception); } - return carrierName; + return NO; } #endif - @end diff --git a/SensorsAnalyticsSDK/Core/PropertyPlugin/SAPropertyPluginManager.m b/SensorsAnalyticsSDK/Core/PropertyPlugin/SAPropertyPluginManager.m index 63a34613..56a1fda3 100644 --- a/SensorsAnalyticsSDK/Core/PropertyPlugin/SAPropertyPluginManager.m +++ b/SensorsAnalyticsSDK/Core/PropertyPlugin/SAPropertyPluginManager.m @@ -101,7 +101,7 @@ - (void)registerPropertyPlugin:(id)plugin { SAPropertyPluginPriority priority = [plugin respondsToSelector:@selector(priority)] ? plugin.priority : SAPropertyPluginPriorityDefault; // 断言提示返回的优先级类型必须为 SAPropertyPluginPriority - NSAssert(priority == SAPropertyPluginPriorityLow || priority == SAPropertyPluginPriorityDefault || priority == SAPropertyPluginPriorityHight || priority == kSAPropertyPluginPrioritySuper, @"Invalid value: the `- priority` method must return `SAPropertyPluginPriority` type."); + NSAssert(priority == SAPropertyPluginPriorityLow || priority == SAPropertyPluginPriorityDefault || priority == SAPropertyPluginPriorityHigh || priority == kSAPropertyPluginPrioritySuper, @"Invalid value: the `- priority` method must return `SAPropertyPluginPriority` type."); if (priority == kSAPropertyPluginPrioritySuper) { for (id object in self.superPlugins) { diff --git a/SensorsAnalyticsSDK/Core/PropertyPlugin/SAPropertyPluginProtocol.h b/SensorsAnalyticsSDK/Core/PropertyPlugin/SAPropertyPluginProtocol.h index 97b9c478..2492701d 100644 --- a/SensorsAnalyticsSDK/Core/PropertyPlugin/SAPropertyPluginProtocol.h +++ b/SensorsAnalyticsSDK/Core/PropertyPlugin/SAPropertyPluginProtocol.h @@ -41,7 +41,7 @@ typedef NS_OPTIONS(NSUInteger, SAPropertyPluginEventTypes) { typedef NS_ENUM(NSUInteger, SAPropertyPluginPriority) { SAPropertyPluginPriorityLow = 250, SAPropertyPluginPriorityDefault = 500, - SAPropertyPluginPriorityHight = 750, + SAPropertyPluginPriorityHigh = 750, }; typedef void(^SAPropertyPluginCompletion)(NSDictionary *properties); diff --git a/SensorsAnalyticsSDK/Core/SAConstants+Private.h b/SensorsAnalyticsSDK/Core/SAConstants+Private.h index d9c6cc34..0f63df9d 100644 --- a/SensorsAnalyticsSDK/Core/SAConstants+Private.h +++ b/SensorsAnalyticsSDK/Core/SAConstants+Private.h @@ -83,7 +83,6 @@ extern NSString * const kSAEventPropertyElementId; extern NSString * const kSAEventPropertyScreenName; extern NSString * const kSAEventPropertyTitle; extern NSString * const kSAEventPropertyElementPosition; -extern NSString * const kSAEventPropertyElementSelector; extern NSString * const kSAEventPropertyElementPath; extern NSString * const kSAEventPropertyElementContent; extern NSString * const kSAEventPropertyElementType; @@ -150,8 +149,6 @@ extern NSNotificationName const SA_REMOTE_CONFIG_MODEL_CHANGED_NOTIFICATION; extern NSNotificationName const SA_VISUALIZED_H5_MESSAGE_NOTIFICATION; // page leave -extern NSString * const kSAPageLeaveTimestamp; -extern NSString * const kSAPageLeaveAutoTrackProperties; extern NSString * const kSAEventDurationProperty; extern NSString * const kSAEventNameAppPageLeave; diff --git a/SensorsAnalyticsSDK/Core/SAConstants.m b/SensorsAnalyticsSDK/Core/SAConstants.m index 8828d436..d489208f 100644 --- a/SensorsAnalyticsSDK/Core/SAConstants.m +++ b/SensorsAnalyticsSDK/Core/SAConstants.m @@ -86,7 +86,6 @@ NSString * const kSAEventPropertyScreenName = @"$screen_name"; NSString * const kSAEventPropertyTitle = @"$title"; NSString * const kSAEventPropertyElementPosition = @"$element_position"; -NSString * const kSAEventPropertyElementSelector = @"$element_selector"; NSString * const kSAEeventPropertyReferrerTitle = @"$referrer_title"; @@ -162,8 +161,6 @@ void sensorsdata_dispatch_safe_sync(dispatch_queue_t queue,DISPATCH_NOESCAPE dis NSNotificationName const SA_VISUALIZED_H5_MESSAGE_NOTIFICATION = @"SensorsAnalyticsVisualizedMessageFromH5Notification"; //page leave -NSString * const kSAPageLeaveTimestamp = @"timestamp"; -NSString * const kSAPageLeaveAutoTrackProperties = @"properties"; NSString * const kSAEventDurationProperty = @"event_duration"; NSString * const kSAEventNameAppPageLeave = @"$AppPageLeave"; diff --git a/SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m b/SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m index 70887a99..f536bf2d 100755 --- a/SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m +++ b/SensorsAnalyticsSDK/Core/SensorsAnalyticsSDK.m @@ -53,7 +53,7 @@ #import "SAUserDefaultsStorePlugin.h" #import "SASessionProperty.h" -#define VERSION @"4.2.1" +#define VERSION @"4.2.2" void *SensorsAnalyticsQueueTag = &SensorsAnalyticsQueueTag; @@ -218,7 +218,7 @@ - (instancetype)initWithConfigOptions:(nonnull SAConfigOptions *)configOptions { // 此处更新 configOptions 中的 loginIDKey 和 SAIdentifier 中保持一致 _configOptions.loginIDKey = _identifier.loginIDKey; - _presetProperty = [[SAPresetProperty alloc] initWithQueue:_readWriteQueue libVersion:[self libVersion]]; + _presetProperty = [[SAPresetProperty alloc] initWithQueue:_readWriteQueue]; _superProperty = [[SASuperProperty alloc] init]; diff --git a/SensorsAnalyticsSDK/SensorsAnalyticsSDK.bundle/sa_autotrack_viewcontroller_blacklist.json b/SensorsAnalyticsSDK/SensorsAnalyticsSDK.bundle/sa_autotrack_viewcontroller_blacklist.json index c95bffcb..01900a37 100644 --- a/SensorsAnalyticsSDK/SensorsAnalyticsSDK.bundle/sa_autotrack_viewcontroller_blacklist.json +++ b/SensorsAnalyticsSDK/SensorsAnalyticsSDK.bundle/sa_autotrack_viewcontroller_blacklist.json @@ -12,7 +12,9 @@ "UIDocumentMenuViewController", "UIActivityViewController", "SLComposeViewController", - "UISplitViewController" + "UISplitViewController", + "UIDocumentPickerViewController", + "UIDocumentBrowserViewController" ], "private": [ "UIApplicationRotationFollowingController", @@ -72,7 +74,9 @@ "_UIContextMenuActionsOnlyViewController", "UIPredictionViewController", "UISystemInputAssistantViewController", - "UICandidateViewController" + "UICandidateViewController", + "UIActivityContentViewController", + "SFAirDropViewController" ] }, "$AppClick": { @@ -141,7 +145,8 @@ "PUUIMomentsGridViewController", "SFPasswordRemoteViewController", "UIWebRotatingAlertController", - "UIEditUserWordController" + "UIEditUserWordController", + "UIActivityContentViewController" ] } } diff --git a/SensorsAnalyticsSDK/SensorsAnalyticsSDK.bundle/sa_visualized_path.json b/SensorsAnalyticsSDK/SensorsAnalyticsSDK.bundle/sa_visualized_path.json index ef127f19..752f2df6 100644 --- a/SensorsAnalyticsSDK/SensorsAnalyticsSDK.bundle/sa_visualized_path.json +++ b/SensorsAnalyticsSDK/SensorsAnalyticsSDK.bundle/sa_visualized_path.json @@ -53,12 +53,6 @@ "type": "NSString", "use_kvc": false }, - { - "name": "sensorsdata_elementSelector", - "key": "element_selector", - "type": "NSString", - "use_kvc": false - }, { "name": "sensorsdata_elementPosition", "key": "element_position", @@ -133,6 +127,12 @@ "name": "listSelector", "key": "list_selector", "type": "NSString" + }, + { + "name": "sensorsdata_elementSelector", + "key": "element_selector", + "type": "NSString", + "use_kvc": false } ] }, diff --git a/SensorsAnalyticsSDK/Visualized/Config/SAVisualPropertiesConfigSources.h b/SensorsAnalyticsSDK/Visualized/Config/SAVisualPropertiesConfigSources.h index 8f6aaa57..1edc639e 100644 --- a/SensorsAnalyticsSDK/Visualized/Config/SAVisualPropertiesConfigSources.h +++ b/SensorsAnalyticsSDK/Visualized/Config/SAVisualPropertiesConfigSources.h @@ -41,7 +41,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, assign, readonly, getter=isValid) BOOL valid; /// 配置版本 -@property (nonatomic, assign, readonly) NSString *configVersion; +@property (nonatomic, copy, readonly) NSString *configVersion; /// 配置原始 json @property (nonatomic, copy, readonly) NSDictionary *originalResponse; diff --git a/SensorsAnalyticsSDK/Visualized/ElementPath/SAVisualizedViewPathProperty.h b/SensorsAnalyticsSDK/Visualized/ElementPath/SAVisualizedViewPathProperty.h index 74460367..c9b228ca 100644 --- a/SensorsAnalyticsSDK/Visualized/ElementPath/SAVisualizedViewPathProperty.h +++ b/SensorsAnalyticsSDK/Visualized/ElementPath/SAVisualizedViewPathProperty.h @@ -24,9 +24,6 @@ #pragma mark - ViewPath @protocol SAAutoTrackViewPathProperty -/// $AppClick 某个元素的相对路径,拼接 $element_selector。单个元素不包含序号 -@property (nonatomic, copy, readonly) NSString *sensorsdata_heatMapPath; - @optional /// $AppClick 某个元素的相对路径,拼接 $element_path,单个元素包含序号 @property (nonatomic, copy, readonly) NSString *sensorsdata_itemPath; @@ -53,7 +50,7 @@ /// 当前元素的路径 @property (nonatomic, copy, readonly) NSString *sensorsdata_elementPath; -/// 当前元素的元素选择器 +/// App 内嵌 H5 元素的元素选择器 @property (nonatomic, copy, readonly) NSString *sensorsdata_elementSelector; /// 相对 keywindow 的坐标 diff --git a/SensorsAnalyticsSDK/Visualized/ElementPath/UIView+SAElementPath.m b/SensorsAnalyticsSDK/Visualized/ElementPath/UIView+SAElementPath.m index e9464045..1718573c 100644 --- a/SensorsAnalyticsSDK/Visualized/ElementPath/UIView+SAElementPath.m +++ b/SensorsAnalyticsSDK/Visualized/ElementPath/UIView+SAElementPath.m @@ -35,12 +35,19 @@ typedef BOOL (*SAClickableImplementation)(id, SEL, UIView *); +// NB If you add any more fingerprint methods, increment this. +static int kSAFingerprintVersion = 1; static void *const kSAIsDisableRNSubviewsInteractivePropertyName = (void *)&kSAIsDisableRNSubviewsInteractivePropertyName; #pragma mark - UIView @implementation UIView (SAElementPath) + +- (int)jjf_fingerprintVersion { + return kSAFingerprintVersion; +} + // 判断一个 view 是否显示 - (BOOL)sensorsdata_isVisible { /* 忽略部分 view @@ -133,14 +140,23 @@ - (BOOL)sensorsdata_isAutoTrackAppClick { if (![SAVisualizedUtils isInteractiveEnabledRNView:self]) { return NO; } - + + // 是否被忽略或黑名单屏蔽 + if (self.sensorsdata_isIgnored) { + return NO; + } + UIViewController *viewController = self.sensorsdata_viewController; + if (viewController && viewController.sensorsdata_isIgnored) { + return NO; + } + // UISegmentedControl 嵌套 UISegment 作为选项单元格,特殊处理 if ([NSStringFromClass(self.class) isEqualToString:@"UISegment"]) { UISegmentedControl *segmentedControl = (UISegmentedControl *)[self superview]; if (![segmentedControl isKindOfClass:UISegmentedControl.class]) { return NO; } - // 可能是 RN 框架 中 RCTSegmentedControl 内嵌 UISegment,再执行一次 RN 的可点击判断 + // 可能是 RN 框架 中 RCTSegmentedControl 内嵌 UISegment,如果为 NO,再执行一次 RN 的可点击判断 BOOL clickable = [SAVisualizedUtils isAutoTrackAppClickWithControl:segmentedControl]; if (clickable){ return YES; @@ -203,31 +219,12 @@ - (NSString *)sensorsdata_itemPath { NSString *className = NSStringFromClass(self.class); NSInteger index = [SAAutoTrackUtils itemIndexForResponder:self]; - if (index < -1) { // -2 - return className; - } - if (index < 0) { // -1 - index = 0; + return className; } return [NSString stringWithFormat:@"%@[%ld]", className, (long)index]; } -- (NSString *)sensorsdata_heatMapPath { - /* 忽略路径 - UITableViewWrapperView 为 iOS11 以下 UITableView 与 cell 之间的 view - */ - if ([NSStringFromClass(self.class) isEqualToString:@"UITableViewWrapperView"] || [NSStringFromClass(self.class) isEqualToString:@"UISegment"]) { - return nil; - } - - NSString *identifier = [SAVisualizedUtils viewIdentifierForView:self]; - if (identifier) { - return identifier; - } - return [SAVisualizedUtils itemHeatMapPathForResponder:self]; -} - - (NSString *)sensorsdata_similarPath { // 是否支持限定元素位置功能 BOOL enableSupportSimilarPath = [NSStringFromClass(self.class) isEqualToString:@"UITabBarButton"]; @@ -295,42 +292,11 @@ - (NSString *)sensorsdata_elementPath { if ([NSStringFromClass(self.class) isEqualToString:@"UISegment"]) { UISegmentedControl *segmentedControl = (UISegmentedControl *)[self superview]; if ([segmentedControl isKindOfClass:UISegmentedControl.class]) { - return [SAVisualizedUtils viewSimilarPathForView:segmentedControl atViewController:segmentedControl.sensorsdata_viewController shouldSimilarPath:YES]; + return [SAVisualizedUtils viewSimilarPathForView:segmentedControl atViewController:segmentedControl.sensorsdata_viewController]; } } // 支持自定义属性,可见元素均上传 elementPath - return [SAVisualizedUtils viewSimilarPathForView:self atViewController:self.sensorsdata_viewController shouldSimilarPath:YES]; -} - -- (NSString *)sensorsdata_elementSelector { - // 处理特殊控件 - // UISegmentedControl 嵌套 UISegment 作为选项单元格,特殊处理 - if ([NSStringFromClass(self.class) isEqualToString:@"UISegment"]) { - UISegmentedControl *segmentedControl = (UISegmentedControl *)[self superview]; - if ([segmentedControl isKindOfClass:UISegmentedControl.class]) { - /* 原始路径,都是类似以下结构: - UINavigationController/AutoTrackViewController/UIView/UISegmentedControl[(jjf_varB='fac459bd36d8326d9140192c7900decaf3744f5e')]/UISegment[0] - UISegment[0] 无法标识当前单元格当前显示的序号 index - */ - NSString *elementSelector = [SAVisualizedUtils viewPathForView:segmentedControl atViewController:segmentedControl.sensorsdata_viewController]; - // 解析 UISegment 的显示序号 index - NSString *postion = [self sensorsdata_elementPosition]; - // 原始路径分割后的集合 - NSMutableArray *viewPaths = [[elementSelector componentsSeparatedByString:@"/"] mutableCopy]; - // 删除最后一个原始 UISegment 路径 - [viewPaths removeLastObject]; - // 添加使用位置拼接的正确路径 - [viewPaths addObject:[NSString stringWithFormat:@"UISegment[%@]", postion]]; - // 拼接完整路径信息 - NSString *newElementSelector = [viewPaths componentsJoinedByString:@"/"]; - return newElementSelector; - } - } - if (self.sensorsdata_enableAppClick) { - return [SAVisualizedUtils viewPathForView:self atViewController:self.sensorsdata_viewController]; - } else { - return nil; - } + return [SAVisualizedUtils viewSimilarPathForView:self atViewController:self.sensorsdata_viewController]; } - (BOOL)sensorsdata_isFromWeb { @@ -556,11 +522,6 @@ - (NSString *)sensorsdata_similarPath { return [NSString stringWithFormat:@"%@/UISegment[-]", super.sensorsdata_itemPath]; } -- (NSString *)sensorsdata_heatMapPath { - NSString *subPath = [NSString stringWithFormat:@"UISegment[%ld]", (long)self.selectedSegmentIndex]; - return [NSString stringWithFormat:@"%@/%@", super.sensorsdata_heatMapPath, subPath]; -} - @end @implementation UISlider (SAElementPath) @@ -623,27 +584,6 @@ - (NSString *)sensorsdata_itemPath { return super.sensorsdata_itemPath; } -- (NSString *)sensorsdata_heatMapPath { - UIView *currentTableView = self.superview; - while (![currentTableView isKindOfClass:UITableView.class]) { - currentTableView = currentTableView.superview; - if (!currentTableView) { - return super.sensorsdata_heatMapPath; - } - } - - UITableView *tableView = (UITableView *)currentTableView; - for (NSInteger i = 0; i < tableView.numberOfSections; i++) { - if (self == [tableView headerViewForSection:i]) { - return [NSString stringWithFormat:@"[SectionHeader][%ld]", (long)i]; - } - if (self == [tableView footerViewForSection:i]) { - return [NSString stringWithFormat:@"[SectionFooter][%ld]", (long)i]; - } - } - return super.sensorsdata_heatMapPath; -} - @end @@ -698,14 +638,6 @@ - (NSString *)sensorsdata_similarPath { return self.sensorsdata_itemPath; } -- (NSString *)sensorsdata_heatMapPath { - NSIndexPath *indexPath = self.sensorsdata_IndexPath; - if (indexPath) { - return [self sensorsdata_itemPathWithIndexPath:indexPath]; - } - return [super sensorsdata_heatMapPath]; -} - - (NSString *)sensorsdata_itemPathWithIndexPath:(NSIndexPath *)indexPath { return [NSString stringWithFormat:@"%@[%ld][%ld]", NSStringFromClass(self.class), (long)indexPath.section, (long)indexPath.row]; } @@ -758,14 +690,6 @@ - (NSString *)sensorsdata_similarPath { } } -- (NSString *)sensorsdata_heatMapPath { - NSIndexPath *indexPath = self.sensorsdata_IndexPath; - if (indexPath) { - return [self sensorsdata_itemPathWithIndexPath:indexPath]; - } - return [super sensorsdata_heatMapPath]; -} - - (NSString *)sensorsdata_itemPathWithIndexPath:(NSIndexPath *)indexPath { return [NSString stringWithFormat:@"%@[%ld][%ld]", NSStringFromClass(self.class), (long)indexPath.section, (long)indexPath.item]; } diff --git a/SensorsAnalyticsSDK/Visualized/ElementPath/UIViewController+SAElementPath.m b/SensorsAnalyticsSDK/Visualized/ElementPath/UIViewController+SAElementPath.m index f1272702..c6f0fdae 100644 --- a/SensorsAnalyticsSDK/Visualized/ElementPath/UIViewController+SAElementPath.m +++ b/SensorsAnalyticsSDK/Visualized/ElementPath/UIViewController+SAElementPath.m @@ -34,10 +34,6 @@ @implementation UIViewController (SAElementPath) -- (NSString *)sensorsdata_heatMapPath { - return [SAVisualizedUtils itemHeatMapPathForResponder:self]; -} - - (NSArray *)sensorsdata_subElements { __block NSMutableArray *subElements = [NSMutableArray array]; NSArray *childViewControllers = self.childViewControllers; @@ -115,23 +111,15 @@ - (void)sensorsdata_readyEnterViewController { @implementation UIAlertController (SAElementPath) -- (NSString *)sensorsdata_itemPath { +- (NSString *)sensorsdata_similarPath { NSString *className = NSStringFromClass(self.class); NSInteger index = [SAAutoTrackUtils itemIndexForResponder:self]; - if (index < -1) { + if (index < 0) { // -1 return className; } - - if (index < 0) { - index = 0; - } return [NSString stringWithFormat:@"%@[%ld]", className, (long)index]; } -- (NSString *)sensorsdata_similarPath { - return self.sensorsdata_itemPath; -} - @end @implementation UITabBarController (SAElementPath) diff --git a/SensorsAnalyticsSDK/Visualized/SAVisualizedManager.m b/SensorsAnalyticsSDK/Visualized/SAVisualizedManager.m index 2b890075..51f7703a 100644 --- a/SensorsAnalyticsSDK/Visualized/SAVisualizedManager.m +++ b/SensorsAnalyticsSDK/Visualized/SAVisualizedManager.m @@ -45,7 +45,7 @@ @interface SAVisualizedManager() /// 当前类型 @property (nonatomic, assign) SensorsAnalyticsVisualizedType visualizedType; -/// 指定开启可视化的 viewControllers 名称 +/// 指定开启可视化/点击分析的 viewControllers 名称 @property (nonatomic, strong) NSMutableSet *visualizedViewControllers; /// 自定义属性采集 @@ -324,13 +324,10 @@ - (nullable NSDictionary *)propertiesWithView:(UIView *)view { return nil; } - // 1 获取 viewPath 相关属性 - NSString *elementSelector = [SAVisualizedUtils viewPathForView:view atViewController:viewController]; - - NSString *elementPath = [SAVisualizedUtils viewSimilarPathForView:view atViewController:viewController shouldSimilarPath:YES]; + // 获取 viewPath 相关属性 + NSString *elementPath = [SAVisualizedUtils viewSimilarPathForView:view atViewController:viewController]; NSMutableDictionary *viewPthProperties = [NSMutableDictionary dictionary]; - viewPthProperties[kSAEventPropertyElementSelector] = elementSelector; viewPthProperties[kSAEventPropertyElementPath] = elementPath; return viewPthProperties.count > 0 ? viewPthProperties : nil; diff --git a/SensorsAnalyticsSDK/Visualized/SAVisualizedUtils.h b/SensorsAnalyticsSDK/Visualized/SAVisualizedUtils.h index 99dd63c2..c00883f6 100644 --- a/SensorsAnalyticsSDK/Visualized/SAVisualizedUtils.h +++ b/SensorsAnalyticsSDK/Visualized/SAVisualizedUtils.h @@ -93,48 +93,14 @@ NS_ASSUME_NONNULL_BEGIN */ + (BOOL)isIgnoredItemPathWithView:(UIView *)view; -/** - 创建 view 的唯一标识符 - - @param view 需要创建的对象 - @return 唯一标识符 - */ -+ (nullable NSString *)viewIdentifierForView:(UIView *)view; - -/** -通过响应链找到 对象的点击图路径 - -@param responder 响应链中的对象,可以是 UIView 或者 UIViewController -@return 路径 -*/ -+ (NSString *)itemHeatMapPathForResponder:(UIResponder *)responder; - -/** - 找到 view 的路径数组 - - @param view 需要获取路径的 view - @return 路径数组 - */ -+ (NSArray *)viewPathsForView:(UIView *)view; - -/** - 获取 view 的路径字符串 - - @param view 需要获取路径的 view - @param viewController view 所在的 viewController - @return 路径字符串 - */ -+ (nullable NSString *)viewPathForView:(UIView *)view atViewController:(UIViewController *)viewController; - /** 获取 view 的模糊路径 @param view 需要获取路径的 view @param viewController view 所在的 viewController -@param shouldSimilarPath 是否需要取相似路径 @return 路径字符串 */ -+ (NSString *)viewSimilarPathForView:(UIView *)view atViewController:(UIViewController *)viewController shouldSimilarPath:(BOOL)shouldSimilarPath; ++ (NSString *)viewSimilarPathForView:(UIView *)view atViewController:(UIViewController *)viewController; /// 当前 view 所在同类页面序号 + (NSInteger)pageIndexWithView:(UIView *)view; diff --git a/SensorsAnalyticsSDK/Visualized/SAVisualizedUtils.m b/SensorsAnalyticsSDK/Visualized/SAVisualizedUtils.m index 05290851..3c6b1863 100644 --- a/SensorsAnalyticsSDK/Visualized/SAVisualizedUtils.m +++ b/SensorsAnalyticsSDK/Visualized/SAVisualizedUtils.m @@ -25,7 +25,6 @@ #import "SAVisualizedUtils.h" #import "SAWebElementView.h" #import "UIView+SAElementPath.h" -#import "UIView+SAElementSelector.h" #import "SAVisualizedViewPathProperty.h" #import "SAVisualizedObjectSerializerManager.h" #import "SAConstants+Private.h" @@ -494,47 +493,8 @@ + (BOOL)isIgnoredItemPathWithView:(UIView *)view { return [ignoredItemClassNames containsObject:className]; } -+ (NSArray *)viewPathsForViewController:(UIViewController *)viewController { - NSMutableArray *viewPaths = [NSMutableArray array]; - do { - [viewPaths addObject:viewController.sensorsdata_heatMapPath]; - viewController = (UIViewController *)viewController.parentViewController; - } while (viewController); - - UIViewController *vc = (UIViewController *)viewController.presentingViewController; - if ([vc conformsToProtocol:@protocol(SAAutoTrackViewPathProperty)]) { - [viewPaths addObjectsFromArray:[self viewPathsForViewController:vc]]; - } - return viewPaths; -} - -+ (NSArray *)viewPathsForView:(UIView *)view { - NSMutableArray *viewPathArray = [NSMutableArray array]; - do { // 遍历 view 层级 路径 - if (view.sensorsdata_heatMapPath) { - [viewPathArray addObject:view.sensorsdata_heatMapPath]; - } - } while ((view = (id)view.nextResponder) && [view isKindOfClass:UIView.class] && ![view isKindOfClass:UIWindow.class]); - - if ([view isKindOfClass:UIViewController.class] && [view conformsToProtocol:@protocol(SAAutoTrackViewPathProperty)]) { - // 遍历 controller 层 路径 - [viewPathArray addObjectsFromArray:[self viewPathsForViewController:(UIViewController *)view]]; - } - return viewPathArray; -} - -+ (NSString *)viewPathForView:(UIView *)view atViewController:(UIViewController *)viewController { - if ([self isIgnoredViewPathForViewController:viewController]) { - return nil; - } - NSArray *viewPaths = [[[self viewPathsForView:view] reverseObjectEnumerator] allObjects]; - NSString *viewPath = [viewPaths componentsJoinedByString:@"/"]; - - return viewPath; -} - /// 获取模糊路径 -+ (NSString *)viewSimilarPathForView:(UIView *)view atViewController:(UIViewController *)viewController shouldSimilarPath:(BOOL)shouldSimilarPath { ++ (NSString *)viewSimilarPathForView:(UIView *)view atViewController:(UIViewController *)viewController { if ([self isIgnoredViewPathForViewController:viewController]) { return nil; } @@ -543,7 +503,7 @@ + (NSString *)viewSimilarPathForView:(UIView *)view atViewController:(UIViewCont BOOL isContainSimilarPath = NO; do { - if (isContainSimilarPath || !shouldSimilarPath) { // 防止 cell 嵌套,被拼上多个 [-] + if (isContainSimilarPath) { // 防止 cell 等列表嵌套,被拼上多个 [-] if (view.sensorsdata_itemPath) { [viewPathArray addObject:view.sensorsdata_itemPath]; } @@ -551,7 +511,7 @@ + (NSString *)viewSimilarPathForView:(UIView *)view atViewController:(UIViewCont NSString *currentSimilarPath = view.sensorsdata_similarPath; if (currentSimilarPath) { [viewPathArray addObject:currentSimilarPath]; - if ([currentSimilarPath rangeOfString:@"[-]"].location != NSNotFound) { + if ([currentSimilarPath containsString:@"[-]"]) { isContainSimilarPath = YES; } } @@ -560,7 +520,7 @@ + (NSString *)viewSimilarPathForView:(UIView *)view atViewController:(UIViewCont if ([view isKindOfClass:UIAlertController.class]) { UIViewController *viewController = (UIViewController *)view; - [viewPathArray addObject:viewController.sensorsdata_itemPath]; + [viewPathArray addObject:viewController.sensorsdata_similarPath]; } NSString *viewPath = [[[viewPathArray reverseObjectEnumerator] allObjects] componentsJoinedByString:@"/"]; @@ -568,37 +528,6 @@ + (NSString *)viewSimilarPathForView:(UIView *)view atViewController:(UIViewCont return viewPath; } -+ (NSString *)viewIdentifierForView:(UIView *)view { - NSMutableArray *valueArray = [[NSMutableArray alloc] init]; - NSString *value = [view jjf_varE]; - if (value) { - [valueArray addObject:[NSString stringWithFormat:@"jjf_varE='%@'", value]]; - } - value = [view jjf_varC]; - if (value) { - [valueArray addObject:[NSString stringWithFormat:@"jjf_varC='%@'", value]]; - } - value = [view jjf_varB]; - if (value) { - [valueArray addObject:[NSString stringWithFormat:@"jjf_varB='%@'", value]]; - } - value = [view jjf_varA]; - if (value) { - [valueArray addObject:[NSString stringWithFormat:@"jjf_varA='%@'", value]]; - } - if (valueArray.count == 0) { - return nil; - } - NSString *viewVarString = [valueArray componentsJoinedByString:@" AND "]; - return [NSString stringWithFormat:@"%@[(%@)]", NSStringFromClass([view class]), viewVarString]; -} - -+ (NSString *)itemHeatMapPathForResponder:(UIResponder *)responder { - NSString *className = NSStringFromClass(responder.class); - NSInteger index = [SAAutoTrackUtils itemIndexForResponder:responder]; - return index < 0 ? className : [NSString stringWithFormat:@"%@[%ld]", className, (long)index]; -} - /// 当前 view 所在同类页面序号 + (NSInteger)pageIndexWithView:(UIView *)view { if (!view) { diff --git a/SensorsAnalyticsSDK/Visualized/VisualProperties/DebugLog/SAVisualizedDebugLogTracker.h b/SensorsAnalyticsSDK/Visualized/VisualProperties/DebugLog/SAVisualizedDebugLogTracker.h index 56a167c4..2aab79a4 100644 --- a/SensorsAnalyticsSDK/Visualized/VisualProperties/DebugLog/SAVisualizedDebugLogTracker.h +++ b/SensorsAnalyticsSDK/Visualized/VisualProperties/DebugLog/SAVisualizedDebugLogTracker.h @@ -1,6 +1,6 @@ // // SAVisualizedDebugLogTracker.h -// Pods-SensorsData +// SensorsAnalyticsSDK // // Created by 储强盛 on 2021/3/3. // Copyright © 2015-2022 Sensors Data Co., Ltd. All rights reserved. diff --git a/SensorsAnalyticsSDK/Visualized/VisualProperties/DebugLog/SAVisualizedDebugLogTracker.m b/SensorsAnalyticsSDK/Visualized/VisualProperties/DebugLog/SAVisualizedDebugLogTracker.m index 93587519..3b649a92 100644 --- a/SensorsAnalyticsSDK/Visualized/VisualProperties/DebugLog/SAVisualizedDebugLogTracker.m +++ b/SensorsAnalyticsSDK/Visualized/VisualProperties/DebugLog/SAVisualizedDebugLogTracker.m @@ -1,6 +1,6 @@ // // SAVisualizedDebugLogTracker.m -// Pods-SensorsData +// SensorsAnalyticsSDK // // Created by 储强盛 on 2021/3/3. // Copyright © 2015-2022 Sensors Data Co., Ltd. All rights reserved. diff --git a/SensorsAnalyticsSDK/Visualized/VisualProperties/ViewNode/SAViewNode.h b/SensorsAnalyticsSDK/Visualized/VisualProperties/ViewNode/SAViewNode.h index aed31eac..43f5117a 100644 --- a/SensorsAnalyticsSDK/Visualized/VisualProperties/ViewNode/SAViewNode.h +++ b/SensorsAnalyticsSDK/Visualized/VisualProperties/ViewNode/SAViewNode.h @@ -40,10 +40,12 @@ NS_ASSUME_NONNULL_BEGIN /// 元素名称 @property (nonatomic, copy, readonly) NSString *viewName; -/// 同级同类元素序号 -/* -2:nextResponder 不是父视图或同类元素,比如 controller.view,涉及路径不带序号 - 其他:elementPath 包含序号 - */ +/** + * 同级同类元素序号 + * + * -1:nextResponder 不是父视图或同类元素,比如 controller.view,涉及路径不带序号 + * >= 0:elementPath 包含序号 +*/ @property (nonatomic, assign) NSInteger index; #pragma mark view diff --git a/SensorsAnalyticsSDK/Visualized/VisualProperties/ViewNode/SAViewNode.m b/SensorsAnalyticsSDK/Visualized/VisualProperties/ViewNode/SAViewNode.m index 66407204..dbe3c30e 100644 --- a/SensorsAnalyticsSDK/Visualized/VisualProperties/ViewNode/SAViewNode.m +++ b/SensorsAnalyticsSDK/Visualized/VisualProperties/ViewNode/SAViewNode.m @@ -60,8 +60,7 @@ - (instancetype)initWithView:(UIView *)view { self = [super initWithView:view]; if (self) { /* 元素序号 - -2:nextResponder 不是父视图或同类元素,比如 controller.view,涉及路径不带序号 - -1:同级只存在一个同类元素,只涉及 $element_selector 不同,$element_path 照常拼接序号 + -1:nextResponder 不是父视图或同类元素,比如 controller.view,涉及路径不带序号 >=0:元素序号 */ _index = 0; @@ -124,7 +123,7 @@ - (void)buildNodeRelation { // nextResponder 非 UIView,一般为 ViewController.view,路径拼接需要单独区分 if (!nextResponder || ![nextResponder isKindOfClass:UIView.class]) { self.stopJoinPath = YES; - self.index = -2; + self.index = -1; } } @@ -186,7 +185,7 @@ - (void)refreshBrotherNodeIndex { UIResponder *nextResponder = node.view.nextResponder; if (!nextResponder || ![nextResponder isKindOfClass:UIView.class]) { - node.index = -2; + node.index = -1; } } } @@ -237,7 +236,7 @@ - (NSString *)similarPath { - (NSString *)elementPath { /* 递归 nextNode 构建 viewPath 可以在子线程执行 - 实现参考 [SAVisualizedUtils viewSimilarPathForView: atViewController: shouldSimilarPath:] + 实现参考 [SAVisualizedUtils viewSimilarPathForView: atViewController:] */ SAViewNode *currentNode = self; NSMutableArray *viewPathArray = [NSMutableArray array]; diff --git a/SensorsAnalyticsSDK/Visualized/VisualProperties/ViewNode/UIView+SAVisualProperties.m b/SensorsAnalyticsSDK/Visualized/VisualProperties/ViewNode/UIView+SAVisualProperties.m index 20f61ae5..b35fce63 100644 --- a/SensorsAnalyticsSDK/Visualized/VisualProperties/ViewNode/UIView+SAVisualProperties.m +++ b/SensorsAnalyticsSDK/Visualized/VisualProperties/ViewNode/UIView+SAVisualProperties.m @@ -212,14 +212,14 @@ - (NSString *)sensorsdata_propertyContent { 层级结构如下 UITextField _UITextFieldRoundedRectBackgroundViewNeue - UIFieldEditor(UIScrollView 的子类,只有编辑状态才包含此层) - _UITextFieldCanvasView 或 _UISearchTextFieldCanvasView (UIView 的子类) + UIFieldEditor(UIScrollView 的子类,只有编辑状态才包含此层,非编辑状态直接包含下面层级) + _UITextFieldCanvasView 或 _UISearchTextFieldCanvasView 或 _UITextLayoutCanvasView(模拟器出现) (UIView 的子类) _UITextFieldClearButton (可能存在) */ UITextField *textField = (UITextField *)[self nextResponder]; return [textField sensorsdata_propertyContent]; } - if ([NSStringFromClass(self.class) isEqualToString:@"_UITextFieldCanvasView"] || [NSStringFromClass(self.class) isEqualToString:@"_UISearchTextFieldCanvasView"]) { + if ([NSStringFromClass(self.class) isEqualToString:@"_UITextFieldCanvasView"] || [NSStringFromClass(self.class) isEqualToString:@"_UISearchTextFieldCanvasView"] || [NSStringFromClass(self.class) isEqualToString:@"_UITextLayoutCanvasView"]) { UITextField *textField = (UITextField *)[self nextResponder]; do { @@ -275,12 +275,17 @@ - (NSString *)sensorsdata_propertyContent { @implementation UITextField (PropertiesContent) - (NSString *)sensorsdata_propertyContent { - if (self.text) { + /* 兼容 RN 中输入框 placeholder 采集 + RCTUITextField,未输入元素内容, text 为 @"",而非 nil + */ + if (self.text.length > 0) { return self.text; - } else if (self.placeholder) { - return self.placeholder; } - return super.sensorsdata_propertyContent; + return self.placeholder; + /* + 针对 UITextField,因为子元素最终仍会尝试向上遍历 nextResponder 使用 UITextField本身获取内容 + 如果再遍历子元素获取内容,会造成死循环调用而异常 + */ } @end diff --git a/SensorsAnalyticsSDK/Visualized/WebElementInfo/SAWebElementView.h b/SensorsAnalyticsSDK/Visualized/WebElementInfo/SAWebElementView.h index b0205325..12cd9238 100644 --- a/SensorsAnalyticsSDK/Visualized/WebElementInfo/SAWebElementView.h +++ b/SensorsAnalyticsSDK/Visualized/WebElementInfo/SAWebElementView.h @@ -35,7 +35,7 @@ NS_ASSUME_NONNULL_BEGIN /// 是否为 H5 元素 @property (nonatomic, assign) BOOL isFromH5; -/// 元素选择器,老版使用 +/// 元素选择器,H5 元素不支持限定位置时匹配 @property (nonatomic, copy) NSString *elementSelector; /// 元素内容 diff --git a/SensorsAnalyticsTests/Builder/SACatalystPresetPropertyTest.m b/SensorsAnalyticsTests/Builder/SACatalystPresetPropertyTest.m new file mode 100644 index 00000000..5d423b23 --- /dev/null +++ b/SensorsAnalyticsTests/Builder/SACatalystPresetPropertyTest.m @@ -0,0 +1,82 @@ +// +// SACatalystPresetPropertyTest.m +// SensorsAnalyticsTests +// +// Created by yuqiang on 2022/1/18. +// Copyright © 2015-2022 Sensors Data Co., Ltd. All rights reserved. +// +// 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. +// + +#import +#import "SAPresetPropertyObject.h" + +@interface SAPresetPropertyObject () + +- (NSString *)sysctlByName:(NSString *)name; + +@end + +@interface SACatalystPresetPropertyTest : XCTestCase + +@property (nonatomic, strong) SACatalystPresetProperty *property; + +@end + +@implementation SACatalystPresetPropertyTest + +- (void)setUp { + _property = [[SACatalystPresetProperty alloc] init]; +} + +- (void)tearDown { + _property = nil; +} + +- (void)testOS { + NSString *os = @"macOS"; + XCTAssertTrue([_property.properties[@"$os"] isEqualToString:os]); +} + +- (void)testOSVersion { + NSString *osVersion = [_property sysctlByName:@"kern.osproductversion"]; + XCTAssertTrue([_property.properties[@"$os_version"] isEqualToString:osVersion]); +} + +- (void)testDeviceModel { + NSString *model = [_property sysctlByName:@"hw.model"]; + XCTAssertTrue([_property.properties[@"$model"] isEqualToString:model]); +} + +- (void)testLib { + NSString *lib = @"iOS"; + XCTAssertTrue([_property.properties[@"$lib"] isEqualToString:lib]); +} + +- (void)testScreenHeight { + NSInteger height = UIScreen.mainScreen.bounds.size.height; + XCTAssertEqual(_property.properties[@"$screen_height"], @(height)); +} + +- (void)testScreenWidth { + NSInteger width = UIScreen.mainScreen.bounds.size.width; + XCTAssertEqual(_property.properties[@"$screen_width"], @(width)); +} + +- (void)testPerformanceProperties { + [self measureBlock:^{ + [_property properties]; + }]; +} + +@end diff --git a/SensorsAnalyticsTests/Builder/SAPhonePresetPropertyTest.m b/SensorsAnalyticsTests/Builder/SAPhonePresetPropertyTest.m new file mode 100644 index 00000000..22dab0c6 --- /dev/null +++ b/SensorsAnalyticsTests/Builder/SAPhonePresetPropertyTest.m @@ -0,0 +1,86 @@ +// +// SAPhonePresetPropertyTest.m +// SensorsAnalyticsTests +// +// Created by yuqiang on 2022/1/18. +// Copyright © 2015-2022 Sensors Data Co., Ltd. All rights reserved. +// +// 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. +// + +#import +#import "SAPresetPropertyObject.h" + +@interface SAPresetPropertyObject () + +- (NSString *)sysctlByName:(NSString *)name; + +@end + +@interface SAPhonePresetPropertyTest : XCTestCase + +@property (nonatomic, strong) SAPhonePresetProperty *property; + +@end + +@implementation SAPhonePresetPropertyTest + +- (void)setUp { + _property = [[SAPhonePresetProperty alloc] init]; +} + +- (void)tearDown { + _property = nil; +} + +- (void)testOS { + NSString *os = @"iOS"; + XCTAssertTrue([_property.properties[@"$os"] isEqualToString:os]); +} + +- (void)testOSVersion { + NSString *osVersion = [[UIDevice currentDevice] systemVersion]; + XCTAssertTrue([_property.properties[@"$os_version"] isEqualToString:osVersion]); +} + +- (void)testDeviceModel { + NSString *model = [_property sysctlByName:@"hw.machine"]; + XCTAssertTrue([_property.properties[@"$model"] isEqualToString:model]); +} + +- (void)testLib { + NSString *lib = @"iOS"; + XCTAssertTrue([_property.properties[@"$lib"] isEqualToString:lib]); +} + +- (void)testScreenHeight { + NSInteger height = UIScreen.mainScreen.bounds.size.height; + XCTAssertEqual(_property.properties[@"$screen_height"], @(height)); +} + +- (void)testScreenWidth { + NSInteger width = UIScreen.mainScreen.bounds.size.width; + XCTAssertEqual(_property.properties[@"$screen_width"], @(width)); +} + +- (void)testCarrier { + XCTAssertNil(_property.properties[@"$carrier"]); +} + +- (void)testPerformanceProperties { + [self measureBlock:^{ + [_property properties]; + }]; +} + +@end diff --git a/SensorsAnalyticsTests/Builder/SAPresetPropertyObjectTest.m b/SensorsAnalyticsTests/Builder/SAPresetPropertyObjectTest.m new file mode 100644 index 00000000..f8b24d88 --- /dev/null +++ b/SensorsAnalyticsTests/Builder/SAPresetPropertyObjectTest.m @@ -0,0 +1,99 @@ +// +// SAPresetPropertyObjectTest.m +// SensorsAnalyticsTests +// +// Created by yuqiang on 2022/1/18. +// Copyright © 2015-2022 Sensors Data Co., Ltd. All rights reserved. +// +// 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. +// + +#import +#import "SAPresetPropertyObject.h" + +@interface SAPresetPropertyObjectTest : XCTestCase + +@property (nonatomic, strong) SAPresetPropertyObject *property; + +@end + +@implementation SAPresetPropertyObjectTest + +- (void)setUp { + _property = [[SAPresetPropertyObject alloc] init]; +} + +- (void)tearDown { + _property = nil; +} + +- (void)testManufacturer { + XCTAssertTrue([_property.properties[@"$manufacturer"] isEqualToString:@"Apple"]); +} + +- (void)testOS { + XCTAssertNil(_property.properties[@"$os"]); +} + +- (void)testOSVersion { + XCTAssertNil(_property.properties[@"$os_version"]); +} + +- (void)testDeviceModel { + XCTAssertNil(_property.properties[@"$model"]); +} + +- (void)testLib { + XCTAssertNil(_property.properties[@"$lib"]); +} + +- (void)testScreenHeight { + XCTAssertEqual(_property.properties[@"$screen_height"], @((NSInteger)0)); +} + +- (void)testScreenWidth { + XCTAssertEqual(_property.properties[@"$screen_width"], @((NSInteger)0)); +} + +- (void)testCarrier { + XCTAssertNil(_property.properties[@"$carrier"]); +} + +- (void)testAppID { + NSString *appID = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; + XCTAssertEqual(_property.properties[@"$app_id"], appID); +} + +- (void)testAppName { + NSString *displayName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"]; + if (!displayName) { + displayName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]; + } + if (!displayName) { + displayName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleExecutable"]; + } + XCTAssertEqual(_property.properties[@"$app_name"], displayName); +} + +- (void)testTimezoneOffset { + NSInteger minutesOffsetGMT = - ([[NSTimeZone defaultTimeZone] secondsFromGMT] / 60); + XCTAssertEqual(_property.properties[@"$timezone_offset"], @(minutesOffsetGMT)); +} + +- (void)testPerformanceProperties { + [self measureBlock:^{ + [_property properties]; + }]; +} + +@end