├── .gitignore ├── .travis.yml ├── EventTracing-iOS ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── AOP │ ├── EventObserver │ │ └── NEEventTracingClickMonitor.m │ ├── NEEventTracingAOPManager.h │ ├── NEEventTracingAOPManager.m │ ├── NEEventTracingAOPProtocol.h │ ├── NEEventTracingDelegateChain.h │ ├── NEEventTracingDelegateChain.m │ └── ui │ │ ├── NEEventTracingAppLicycleAOP.h │ │ ├── NEEventTracingAppLicycleAOP.m │ │ ├── NEEventTracingUIAlertControllerAOP.h │ │ ├── NEEventTracingUIAlertControllerAOP.m │ │ ├── NEEventTracingUIControlAOP.h │ │ ├── NEEventTracingUIControlAOP.m │ │ ├── NEEventTracingUIScrollViewAOP.h │ │ ├── NEEventTracingUIScrollViewAOP.m │ │ ├── NEEventTracingUITabbarAOP.h │ │ ├── NEEventTracingUITabbarAOP.m │ │ ├── NEEventTracingUIViewAOP.h │ │ ├── NEEventTracingUIViewAOP.m │ │ ├── NEEventTracingUIViewControllerAOP.h │ │ └── NEEventTracingUIViewControllerAOP.m │ ├── Categorys │ ├── NEEventTracingEventActionConfig+Private.h │ ├── NEEventTracingReferFuncs.m │ ├── Props │ │ ├── NEEventTracingAssociatedPros.h │ │ ├── NEEventTracingAssociatedPros.m │ │ ├── NEEventTracingWeakObjectContainer.h │ │ └── NEEventTracingWeakObjectContainer.m │ ├── UIAlertAction+EventTracing.m │ ├── UIAlertController+EventTracing.m │ ├── UIView+EventTracing.m │ ├── UIView+EventTracingPipEvent.m │ ├── UIView+EventTracingPrivate.h │ ├── UIView+EventTracingRefer.m │ ├── UIView+EventTracingReuse.m │ └── UIView+EventTracingVTree.m │ ├── Core │ ├── BILogBuilder │ │ ├── NEEventTracingBuilder.m │ │ └── NEEventTracingMultiReferPatch.m │ ├── NEEventTracingContext+Private.h │ ├── NEEventTracingContext.m │ ├── NEEventTracingEngine+Action.h │ ├── NEEventTracingEngine+Action.m │ ├── NEEventTracingEngine+Private.h │ ├── NEEventTracingEngine+TraverseAction.h │ ├── NEEventTracingEngine+TraverseAction.m │ └── NEEventTracingEngine.m │ ├── Diff │ ├── NEEventTracingDiff.h │ ├── NEEventTracingDiff.mm │ └── NEEventTracingDiffable.h │ ├── Exceptions │ └── NEEventTracingExceptionDelegate.h │ ├── Log │ ├── NEEventTracingInternalLog.h │ └── NEEventTracingInternalLog.m │ ├── Output │ ├── NEEventTracingEventOutput.h │ ├── NEEventTracingEventOutput.m │ ├── NEEventTracingEventOutputChannel.h │ ├── NEEventTracingOutputFlattenFormatter.h │ ├── NEEventTracingOutputFlattenFormatter.m │ ├── NEEventTracingReferNodeSCMDefaultFormatter.h │ ├── NEEventTracingReferNodeSCMDefaultFormatter.m │ └── Private │ │ └── NEEventTracingEventOutput+Private.h │ ├── ParamGuard │ ├── NEEventTracingParamGuardConfiguration.h │ └── Private │ │ ├── NEEventTracingParamGuardExector.h │ │ └── NEEventTracingParamGuardExector.m │ ├── Public │ ├── BILogBuilder │ │ ├── NEEventTracingBuilder.h │ │ └── NEEventTracingMultiReferPatch.h │ ├── NEEventTracing.h │ ├── NEEventTracingAppLifecycleProcotol.h │ ├── NEEventTracingClickMonitor.h │ ├── NEEventTracingContext.h │ ├── NEEventTracingDefines.h │ ├── NEEventTracingEngine.h │ ├── NEEventTracingEventActionConfig.h │ ├── NEEventTracingInternalLogOutputInterface.h │ ├── NEEventTracingOutputFormatter.h │ ├── NEEventTracingReferFuncs.h │ ├── NEEventTracingReferObserver.h │ ├── NEEventTracingVTreeNodeExtraConfigProtocol.h │ ├── UIAlertController+EventTracingParams.h │ ├── UIScrollView+EventTracingES.h │ ├── UIView+EventTracing.h │ ├── UIView+EventTracingNodeImpressObserver.h │ └── UIView+EventTracingPipEvent.h │ ├── Refer │ ├── NEEventTracingEventRefer.h │ ├── NEEventTracingFormattedRefer.h │ └── Private │ │ ├── NEEventTracingEventRefer+Private.h │ │ ├── NEEventTracingEventRefer.m │ │ ├── NEEventTracingEventReferCollector.h │ │ ├── NEEventTracingEventReferCollector.m │ │ ├── NEEventTracingEventReferQueue+Query.h │ │ ├── NEEventTracingEventReferQueue+Query.m │ │ ├── NEEventTracingEventReferQueue.h │ │ ├── NEEventTracingEventReferQueue.m │ │ ├── NEEventTracingFormattedReferBuilder.h │ │ └── NEEventTracingFormattedReferBuilder.m │ ├── Throttle │ ├── NEEventTracingTraversalRunnerDurationThrottle.h │ ├── NEEventTracingTraversalRunnerDurationThrottle.m │ ├── NEEventTracingTraversalRunnerScrollViewOffsetThrottle.h │ ├── NEEventTracingTraversalRunnerScrollViewOffsetThrottle.m │ └── NEEventTracingTraversalRunnerThrottle.h │ ├── Traverser │ ├── NEEventTracingEventAction.h │ ├── NEEventTracingEventAction.m │ ├── NEEventTracingEventEmitter.h │ ├── NEEventTracingEventEmitter.m │ ├── NEEventTracingTraversalRunner.h │ ├── NEEventTracingTraversalRunner.m │ ├── NEEventTracingTraverser.h │ └── NEEventTracingTraverser.mm │ ├── Utils │ ├── NSArray+ETEnumerator.h │ ├── NSArray+ETEnumerator.mm │ └── Private │ │ ├── EventTracingConfuseMacro.h │ │ ├── NEEventTracingConstData.h │ │ ├── NEEventTracingConstData.m │ │ ├── NEEventTracingDefines.m │ │ ├── NEEventTracingSentinel.h │ │ ├── NEEventTracingSentinel.m │ │ ├── NSString+EventTracingUtil.h │ │ └── NSString+EventTracingUtil.m │ └── VTree │ ├── NEEventTracingVTree.h │ ├── NEEventTracingVTree.m │ ├── NEEventTracingVTreeNode.h │ ├── NEEventTracingVTreeNode.m │ ├── Private │ ├── NEEventTracingVTree+Private.h │ └── NEEventTracingVTreeNode+Private.h │ ├── Sync │ ├── NEEventTracingVTree+Sync.h │ └── NEEventTracingVTree+Sync.mm │ └── Visible │ ├── NEEventTracingVTree+Visible.h │ ├── NEEventTracingVTree+Visible.m │ ├── NEEventTracingVTreeNode+Visible.h │ └── NEEventTracingVTreeNode+Visible.m ├── EventTracing.podspec ├── Example ├── EventTracing-iOS.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── NMTest-Example.xcscheme ├── EventTracing-iOS │ ├── Base.lproj │ │ ├── LaunchScreen.storyboard │ │ └── Main.storyboard │ ├── ETCommonDefines.h │ ├── ETTabBarViewController.h │ ├── ETTabBarViewController.m │ ├── EventTracing-iOS-Info.plist │ ├── EventTracing-iOS-Prefix.pch │ ├── H5 │ │ ├── ETH5ViewController.h │ │ ├── ETH5ViewController.m │ │ ├── ETJSBEventTracing.m │ │ ├── Jsb │ │ │ ├── ETJSBInternalBridgeAvaiable.m │ │ │ ├── ETWebUtility.h │ │ │ ├── ETWebUtility.m │ │ │ ├── ETWebView.h │ │ │ ├── ETWebView.m │ │ │ ├── ETWebViewBridge.h │ │ │ ├── ETWebViewBridge.m │ │ │ ├── ETWebViewBridgeManager.h │ │ │ ├── ETWebViewBridgeManager.m │ │ │ ├── ETWebViewBridgeModuleContext.h │ │ │ ├── Message │ │ │ │ ├── ETWebViewBridgeMessage.h │ │ │ │ └── ETWebViewBridgeMessage.m │ │ │ ├── NSError+ETWebViewBridge.h │ │ │ ├── NSError+ETWebViewBridge.m │ │ │ ├── inject.js │ │ │ └── smulate_click.js │ │ └── h5.html │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ └── close.imageset │ │ │ ├── Contents.json │ │ │ └── close@3x.png │ ├── NEAppDelegate.h │ ├── NEAppDelegate.m │ ├── Native │ │ ├── Base │ │ │ ├── ETBaseViewController.h │ │ │ └── ETBaseViewController.m │ │ ├── Tip │ │ │ ├── ETTipViewController.h │ │ │ └── ETTipViewController.m │ │ ├── categories │ │ │ ├── UICollectionView+ETDemo.h │ │ │ ├── UICollectionView+ETDemo.m │ │ │ ├── UIColor+ET.h │ │ │ ├── UIColor+ET.m │ │ │ ├── UITableView+ETDemo.h │ │ │ └── UITableView+ETDemo.m │ │ ├── tab_page_1 │ │ │ ├── Alert │ │ │ │ ├── ETAlertViewController.h │ │ │ │ └── ETAlertViewController.m │ │ │ ├── Cell │ │ │ │ ├── ETMainTestCell.h │ │ │ │ ├── ETMainTestCell.m │ │ │ │ ├── ETMainTestCellItem.h │ │ │ │ ├── ETMainTestCellItem.m │ │ │ │ ├── ETMainTestInputCell.h │ │ │ │ └── ETMainTestInputCell.m │ │ │ ├── ETHomeTableViewController.h │ │ │ ├── ETHomeTableViewController.m │ │ │ ├── ETTestLogicMountViewController.h │ │ │ ├── ETTestLogicMountViewController.m │ │ │ ├── ETTestLoginViewController.h │ │ │ ├── ETTestLoginViewController.m │ │ │ ├── Event │ │ │ │ ├── ETEventViewController.h │ │ │ │ └── ETEventViewController.m │ │ │ ├── Impress │ │ │ │ ├── ETAutoImpressController.h │ │ │ │ └── ETAutoImpressController.m │ │ │ ├── Logout │ │ │ │ ├── ETLogoutViewController.h │ │ │ │ └── ETLogoutViewController.m │ │ │ ├── Mount │ │ │ │ ├── ETMountViewController.h │ │ │ │ └── ETMountViewController.m │ │ │ ├── Params │ │ │ │ ├── ETHomeParamsViewController.h │ │ │ │ └── ETHomeParamsViewController.m │ │ │ ├── QRCode │ │ │ │ ├── ETQRCodeScanViewController.h │ │ │ │ └── ETQRCodeScanViewController.m │ │ │ ├── Refer │ │ │ │ ├── ETBridgeViewController.h │ │ │ │ ├── ETBridgeViewController.m │ │ │ │ ├── ETReferViewController.h │ │ │ │ └── ETReferViewController.m │ │ │ └── Visible │ │ │ │ ├── ETVisibleViewController.h │ │ │ │ └── ETVisibleViewController.m │ │ └── tab_page_2 │ │ │ ├── ETHomeCollectionViewCell.h │ │ │ ├── ETHomeCollectionViewCell.m │ │ │ ├── ETHomeCollectionViewController.h │ │ │ └── ETHomeCollectionViewController.m │ ├── TestUtils │ │ ├── EventTracingTestLogComing.h │ │ └── EventTracingTestLogComing.m │ ├── en.lproj │ │ └── InfoPlist.strings │ └── main.m ├── Gemfile ├── Gemfile.lock ├── Podfile └── Tests │ ├── ETAlertTests.m │ ├── ETAutoImpressTests.m │ ├── ETDiffTests.m │ ├── ETEventTests.m │ ├── ETH5Tests.m │ ├── ETMountTests.m │ ├── ETParamsTests.m │ ├── ETReferTests.m │ ├── ETVisibleTests.m │ ├── EventTracingDefines.h │ ├── EventTracingTestUsefullFuncs.h │ ├── EventTracingTestUsefullFuncs.m │ ├── KIFUITestActor+ET_Extra.h │ ├── KIFUITestActor+ET_Extra.m │ ├── NSMutableArray+ET_Extra.h │ ├── NSMutableArray+ET_Extra.m │ ├── Tests-Info.plist │ ├── Tests-Prefix.pch │ └── en.lproj │ └── InfoPlist.strings ├── LICENSE ├── README.md └── _Pods.xcodeproj /.gitignore: -------------------------------------------------------------------------------- 1 | # macOS 2 | .DS_Store 3 | 4 | # Xcode 5 | build/ 6 | *.pbxuser 7 | !default.pbxuser 8 | *.mode1v3 9 | !default.mode1v3 10 | *.mode2v3 11 | !default.mode2v3 12 | *.perspectivev3 13 | !default.perspectivev3 14 | xcuserdata/ 15 | *.xccheckout 16 | profile 17 | *.moved-aside 18 | DerivedData 19 | *.hmap 20 | *.ipa 21 | 22 | # Bundler 23 | .bundle 24 | 25 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 26 | # Carthage/Checkouts 27 | 28 | Carthage/Build 29 | 30 | # We recommend against adding the Pods directory to your .gitignore. However 31 | # you should judge for yourself, the pros and cons are mentioned at: 32 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 33 | # 34 | # Note: if you ignore the Pods directory, make sure to uncomment 35 | # `pod install` in .travis.yml 36 | # 37 | Pods/ 38 | Podfile.lock -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * https://www.objc.io/issues/6-build-tools/travis-ci/ 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode7.3 6 | language: objective-c 7 | # cache: cocoapods 8 | # podfile: Example/Podfile 9 | # before_install: 10 | # - gem install cocoapods # Since Travis is not always on latest version 11 | # - pod install --project-directory=Example 12 | script: 13 | - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/EventTracing-iOS.xcworkspace -scheme EventTracing-iOS-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty 14 | - pod lib lint 15 | -------------------------------------------------------------------------------- /EventTracing-iOS/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eventtracing/EventTracing-iOS/afa6706b719590e7ebe9ade85cc2dcf782873faa/EventTracing-iOS/Assets/.gitkeep -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eventtracing/EventTracing-iOS/afa6706b719590e7ebe9ade85cc2dcf782873faa/EventTracing-iOS/Classes/.gitkeep -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/NEEventTracingAOPManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingAOPManager.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/24. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingAOPProtocol.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingAOPManager : NSObject 14 | 15 | + (instancetype) defaultManager; 16 | 17 | - (void) registeAOPCls:(Class)AOPCls; 18 | - (void) fire; 19 | 20 | @end 21 | 22 | NS_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/NEEventTracingAOPManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingAOPManager.m 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/24. 6 | // 7 | 8 | #import "NEEventTracingAOPManager.h" 9 | 10 | @interface NEEventTracingAOPManager () 11 | @property (nonatomic, strong) NSMutableArray> *AOPClses; 12 | @end 13 | 14 | @implementation NEEventTracingAOPManager 15 | 16 | + (instancetype)defaultManager { 17 | static NEEventTracingAOPManager *instance; 18 | static dispatch_once_t onceToken; 19 | dispatch_once(&onceToken, ^{ 20 | instance = [[NEEventTracingAOPManager alloc] init]; 21 | instance.AOPClses = [@[] mutableCopy]; 22 | }); 23 | return instance; 24 | } 25 | 26 | - (void)registeAOPCls:(Class)AOPCls { 27 | if (![AOPCls conformsToProtocol:@protocol(NEEventTracingAOPProtocol)]) { 28 | return; 29 | } 30 | [self.AOPClses addObject:AOPCls]; 31 | } 32 | 33 | - (void)fire { 34 | [self.AOPClses enumerateObjectsUsingBlock:^(Class clz, NSUInteger idx, BOOL * _Nonnull stop) { 35 | id AOPInstance = [clz AOPInstance]; 36 | if ([AOPInstance respondsToSelector:@selector(inject)]) { 37 | [AOPInstance inject]; 38 | } 39 | 40 | dispatch_async(dispatch_get_main_queue(), ^{ 41 | if ([AOPInstance respondsToSelector:@selector(asyncInject)]) { 42 | [AOPInstance asyncInject]; 43 | } 44 | }); 45 | }]; 46 | } 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/NEEventTracingAOPProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingAOPProtocol.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/24. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | #define NEEventTracingAOPInstanceImp \ 13 | + (instancetype)AOPInstance {\ 14 | static id sharedInstance = nil;\ 15 | static dispatch_once_t onceToken;\ 16 | dispatch_once(&onceToken, ^{\ 17 | sharedInstance = [self new];\ 18 | });\ 19 | return sharedInstance;\ 20 | } 21 | 22 | @protocol NEEventTracingAOPProtocol 23 | 24 | + (instancetype) AOPInstance; 25 | 26 | @optional 27 | - (void)inject; 28 | - (void)asyncInject; 29 | 30 | @end 31 | 32 | NS_ASSUME_NONNULL_END 33 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/NEEventTracingDelegateChain.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingDelegateChain.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/24. 6 | // 7 | 8 | #import 9 | 10 | typedef BOOL(^NE_ET_DelegateChainBlocklistBlock)(id _Nonnull object); 11 | 12 | #define NE_ET_DelegateChainHock(mPrefix, P, propName, AOPCls, preSelectorNames, hockProtocols) \ 13 | NE_ET_DelegateChainHockBlacklist(mPrefix, P, propName, AOPCls, preSelectorNames, hockProtocols, @[]) 14 | 15 | #define NE_ET_DelegateChainHockBlacklist(mPrefix, P, propName, AOPCls, preSelectorNames, hockProtocols, blacklist) \ 16 | - (void)ne_et_ ## mPrefix ## _setDelegate:(id)delegate {\ 17 | BOOL shouldReject = [blacklist bk_any:^BOOL(id obj) { \ 18 | Class cls = NSClassFromString(obj); \ 19 | if (!cls) return NO; \ 20 | return [self.class isSubclassOfClass:cls] || [self isKindOfClass:cls]; \ 21 | }]; \ 22 | if (!delegate || shouldReject) { \ 23 | self.propName = nil; \ 24 | [self ne_et_ ## mPrefix ## _setDelegate:delegate]; \ 25 | return; \ 26 | } \ 27 | if (self.propName != nil && [self.propName checkIfChainedToSelfInDelegate:delegate]) { \ 28 | [self ne_et_ ## mPrefix ## _setDelegate:delegate]; \ 29 | } else { \ 30 | id interceptorObject = [AOPCls AOPInstance];\ 31 | NEEventTracingDelegateChain *delegateChain = [NEEventTracingDelegateChain delegateChainWithOriginalDelegate:delegate protocols:(hockProtocols ?: @[@protocol(P)]) interceptorObjects:interceptorObject, nil]; \ 32 | [preSelectorNames enumerateObjectsUsingBlock:^(NSString *selectorName, NSUInteger idx, BOOL * _Nonnull stop) {\ 33 | SEL selector = NSSelectorFromString(selectorName);\ 34 | if (!selector) return;\ 35 | NSString *selectorString = NSStringFromSelector(selector);\ 36 | selectorString = [selectorString stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[selectorString substringToIndex:1] capitalizedString]];\ 37 | SEL preSelector = NSSelectorFromString([NSString stringWithFormat:@"preCall%@", selectorString]);\ 38 | [delegateChain registePreCallSelector:preSelector forSelector:selector forInterceptor:interceptorObject];\ 39 | }];\ 40 | [self ne_et_ ## mPrefix ## _setDelegate:(id)delegateChain]; \ 41 | self.propName = delegateChain; \ 42 | } \ 43 | } 44 | 45 | NS_ASSUME_NONNULL_BEGIN 46 | 47 | @interface NEEventTracingDelegateChain : NSProxy 48 | 49 | @property(nonatomic, weak, readonly) id originalDelegate; 50 | @property(nonatomic, weak, readonly) NSArray *interceptorObjects; 51 | 52 | + (instancetype)delegateChainWithOriginalDelegate:(id)originalDelegate 53 | protocols:(NSArray *)protocols 54 | interceptorObjects:(id)firstInterceptor, ... NS_REQUIRES_NIL_TERMINATION; 55 | - (BOOL)containsObject:(id)object; 56 | - (BOOL)checkIfChainedToSelfInDelegate:(id)delegate; 57 | 58 | - (void)registePreCallSelector:(SEL)preCallSelector forSelector:(SEL)selector forInterceptor:(id)interceptor; 59 | 60 | @end 61 | 62 | NS_ASSUME_NONNULL_END 63 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/ui/NEEventTracingAppLicycleAOP.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingAppLicycleAOP.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/2/25. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingAOPProtocol.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingAppLicycleAOP : NSObject 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/ui/NEEventTracingAppLicycleAOP.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingAppLicycleAOP.m 3 | // NEEventTracingEngine 4 | // 5 | // Created by dl on 2021/2/25. 6 | // 7 | 8 | #import "NEEventTracingAppLicycleAOP.h" 9 | #import "NEEventTracingEngine+Private.h" 10 | #import 11 | 12 | @interface NEEventTracingAppLicycleAOP () 13 | @end 14 | 15 | 16 | @implementation NEEventTracingAppLicycleAOP 17 | 18 | NEEventTracingAOPInstanceImp 19 | 20 | - (void)inject { 21 | static dispatch_once_t onceToken; 22 | dispatch_once(&onceToken, ^{ 23 | if ([NEEventTracingEngine sharedInstance].context.isUseCustomAppLifeCycle) { 24 | // 使用外部的生命周期事件 25 | } else { 26 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ne_et_appDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil]; 27 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ne_et_appWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil]; 28 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ne_et_appDidEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil]; 29 | } 30 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(ne_et_appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; 31 | }); 32 | [[NEEventTracingEngine sharedInstance] refreshAppInActiveState]; 33 | } 34 | 35 | - (void)ne_et_appDidBecomeActive:(NSNotification *)noti { 36 | [[NEEventTracingEngine sharedInstance] appDidBecomeActive]; 37 | } 38 | 39 | - (void)ne_et_appWillEnterForeground:(NSNotification *)noti { 40 | [[NEEventTracingEngine sharedInstance] appWillEnterForeground]; 41 | } 42 | 43 | - (void)ne_et_appDidEnterBackground:(NSNotification *)noti { 44 | [[NEEventTracingEngine sharedInstance] appDidEnterBackground]; 45 | } 46 | 47 | - (void)ne_et_appWillTerminate:(NSNotification *)noti { 48 | [[NEEventTracingEngine sharedInstance] appDidTerminate]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/ui/NEEventTracingUIAlertControllerAOP.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingUIAlertControllerAOP.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/4/7. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingAOPProtocol.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingUIAlertControllerAOP : NSObject 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/ui/NEEventTracingUIControlAOP.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingUIControlAOP.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/24. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingAOPProtocol.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingUIControlAOP : NSObject 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/ui/NEEventTracingUIScrollViewAOP.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingUIScrollViewAOP.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/24. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingAOPProtocol.h" 10 | #import "UIView+EventTracingNodeImpressObserver.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface NEEventTracingUIScrollViewAOP : NSObject 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/ui/NEEventTracingUITabbarAOP.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingUITabbarAOP.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/24. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingAOPProtocol.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingUITabbarAOP : NSObject 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/ui/NEEventTracingUITabbarAOP.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingUITabbarAOP.m 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/24. 6 | // 7 | 8 | #import "NEEventTracingUITabbarAOP.h" 9 | #import "NEEventTracingDelegateChain.h" 10 | #import "NEEventTracingEngine+Private.h" 11 | 12 | #import 13 | #import 14 | #import 15 | 16 | @interface UITabBar (EventTracingAOP) 17 | @property(nonatomic, strong, setter=ne_et_setTabbarDelegateChain:) NEEventTracingDelegateChain *ne_et_tabbarDelegateChain; 18 | @end 19 | 20 | @implementation UITabBar (EventTracingAOP) 21 | 22 | NE_ET_DelegateChainHock(tabbar, UITabBarDelegate, ne_et_tabbarDelegateChain, NEEventTracingUITabbarAOP, @[NSStringFromSelector(@selector(tabBar:didSelectItem:))], nil) 23 | 24 | - (void)ne_et_setTabbarDelegateChain:(NEEventTracingDelegateChain *)ne_et_tabbarDelegateChain { 25 | objc_setAssociatedObject(self, @selector(ne_et_tabbarDelegateChain), ne_et_tabbarDelegateChain, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 26 | } 27 | - (NEEventTracingDelegateChain *)ne_et_tabbarDelegateChain { 28 | return objc_getAssociatedObject(self, _cmd); 29 | } 30 | 31 | @end 32 | 33 | //@interface NEEventTracingUITabbarAOP (EventTracingAOP) 34 | //@end 35 | @implementation NEEventTracingUITabbarAOP 36 | 37 | NEEventTracingAOPInstanceImp 38 | 39 | - (void)inject { 40 | static dispatch_once_t onceToken; 41 | dispatch_once(&onceToken, ^{ 42 | [UITabBar jr_swizzleMethod:@selector(setDelegate:) withMethod:@selector(ne_et_tabbar_setDelegate:) error:nil]; 43 | }); 44 | } 45 | 46 | - (void)preCallTabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item { 47 | [[NEEventTracingEngine sharedInstance] AOP_preLogWithEvent:NE_ET_EVENT_ID_E_CLCK view:tabBar eventAction:^(NEEventTracingEventActionConfig * _Nonnull config) { 48 | config.useForRefer = YES; 49 | }]; 50 | } 51 | 52 | - (void)tabBar:(UITabBar *)tabBar didSelectItem:(UITabBarItem *)item { 53 | [[NEEventTracingEngine sharedInstance] AOP_logWithEvent:NE_ET_EVENT_ID_E_CLCK view:tabBar params:@{ 54 | @"_baritem_idx": @([tabBar.items indexOfObject:item]).stringValue, 55 | @"_baritem_title": (item.title ?: @"") 56 | } eventAction:^(NEEventTracingEventActionConfig * _Nonnull config) { 57 | config.useForRefer = YES; 58 | }]; 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/ui/NEEventTracingUIViewAOP.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingUIViewAOP.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/24. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingAOPProtocol.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingUIViewAOP : NSObject 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/ui/NEEventTracingUIViewControllerAOP.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingUIViewControllerAOP.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/24. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingAOPProtocol.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingUIViewControllerAOP : NSObject 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/AOP/ui/NEEventTracingUIViewControllerAOP.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingUIViewControllerAOP.m 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/24. 6 | // 7 | 8 | #import "NEEventTracingUIViewControllerAOP.h" 9 | #import "NEEventTracingEngine+Private.h" 10 | #import "UIView+EventTracingPrivate.h" 11 | 12 | #import 13 | 14 | @interface UIViewController (EventTracingAOP) 15 | 16 | @end 17 | @implementation UIViewController (EventTracingAOP) 18 | 19 | - (void)ne_et_viewController_viewWillAppear:(BOOL)animated { 20 | self.ne_et_transitioning = YES; 21 | 22 | [self ne_et_viewController_viewWillAppear:animated]; 23 | 24 | // 将导航栏上的节点,逻辑挂载到 从`NavigationController.view` '向下查找' 找到的第一个page节点上 25 | // 最内层的vc,这个时候发现会不在view树中,dispatch async 之后是OK的(放在下一个runloop中) 26 | dispatch_async(dispatch_get_main_queue(), ^{ 27 | if (self.navigationController.navigationBar) { 28 | self.navigationController.navigationBar.ne_et_logicalParentView = NE_ET_FindSubNodeViewAt(self.navigationController.view, YES); 29 | } 30 | }); 31 | } 32 | 33 | - (void)ne_et_viewController_viewDidAppear:(BOOL)animated { 34 | [self ne_et_viewController_viewDidAppear:animated]; 35 | 36 | self.ne_et_transitioning = NO; 37 | [[NEEventTracingEngine sharedInstance] appViewController:self changedToAppear:YES]; 38 | } 39 | 40 | - (void)ne_et_viewController_viewWillDisappear:(BOOL)animated { 41 | self.ne_et_transitioning = YES; 42 | 43 | [self ne_et_viewController_viewWillDisappear:animated]; 44 | } 45 | 46 | - (void)ne_et_viewController_viewDidDisappear:(BOOL)animated { 47 | [self.view ne_et_tryRefreshDynamicParamsCascadeSubViews]; 48 | [[NEEventTracingEngine sharedInstance] appViewController:self changedToAppear:NO]; 49 | 50 | [self ne_et_viewController_viewDidDisappear:animated]; 51 | 52 | self.ne_et_transitioning = NO; 53 | } 54 | 55 | @end 56 | 57 | @implementation NEEventTracingUIViewControllerAOP 58 | 59 | NEEventTracingAOPInstanceImp 60 | 61 | - (void)inject { 62 | static dispatch_once_t onceToken; 63 | dispatch_once(&onceToken, ^{ 64 | [UIViewController jr_swizzleMethod:@selector(viewWillAppear:) withMethod:@selector(ne_et_viewController_viewWillAppear:) error:nil]; 65 | }); 66 | } 67 | 68 | - (void)asyncInject { 69 | static dispatch_once_t onceToken; 70 | dispatch_once(&onceToken, ^{ 71 | [UIViewController jr_swizzleMethod:@selector(viewDidAppear:) withMethod:@selector(ne_et_viewController_viewDidAppear:) error:nil]; 72 | [UIViewController jr_swizzleMethod:@selector(viewWillDisappear:) withMethod:@selector(ne_et_viewController_viewWillDisappear:) error:nil]; 73 | [UIViewController jr_swizzleMethod:@selector(viewDidDisappear:) withMethod:@selector(ne_et_viewController_viewDidDisappear:) error:nil]; 74 | }); 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Categorys/NEEventTracingEventActionConfig+Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventActionConfig+Private.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/25. 6 | // 7 | 8 | #import "NEEventTracingEventActionConfig.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface NEEventTracingEventActionConfig () 13 | 14 | + (instancetype)configWithEvent:(NSString *)event; 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Categorys/Props/NEEventTracingWeakObjectContainer.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingWeakObjectContainer.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/7/27. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface NEEventTracingWeakObjectContainer<__covariant ObjectType> : NSObject 13 | @property(nonatomic, readonly, weak, nullable) ObjectType target; 14 | @property(nonatomic, readonly, weak) ObjectType object; 15 | 16 | - (instancetype)initWithObject:(id)object; 17 | - (instancetype)initWithTarget:(id _Nullable)target object:(id)object; 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Categorys/Props/NEEventTracingWeakObjectContainer.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingWeakObjectContainer.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/7/27. 6 | // 7 | 8 | #import "NEEventTracingWeakObjectContainer.h" 9 | 10 | @implementation NEEventTracingWeakObjectContainer 11 | - (instancetype)initWithObject:(id)object { 12 | return [self initWithTarget:nil object:object]; 13 | } 14 | 15 | - (instancetype)initWithTarget:(id _Nullable)target object:(id)object { 16 | if (!(self = [super init])) 17 | return nil; 18 | 19 | _target = target; 20 | _object = object; 21 | 22 | return self; 23 | } 24 | @end 25 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Categorys/UIAlertAction+EventTracing.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIAlertAction+EventTracing.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/7. 6 | // 7 | 8 | #import 9 | #import "UIView+EventTracingPrivate.h" 10 | #import "NEEventTracingEngine+Private.h" 11 | #import "NEEventTracingEventActionConfig+Private.h" 12 | #import 13 | 14 | @implementation UIAlertAction (EventTracingParams) 15 | 16 | - (UIAlertController *)ne_et_alertController { 17 | return [self bk_associatedValueForKey:_cmd]; 18 | } 19 | - (void)ne_et_setAlertController:(UIAlertController *)ne_et_alertController { 20 | [self bk_weaklyAssociateValue:ne_et_alertController withKey:@selector(ne_et_alertController)]; 21 | } 22 | - (NSMutableDictionary *)ne_et_innerParams { 23 | NSMutableDictionary *params = objc_getAssociatedObject(self, _cmd); 24 | if (!params) { 25 | params = [@{} mutableCopy]; 26 | objc_setAssociatedObject(self, _cmd, params, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 27 | } 28 | return params; 29 | } 30 | - (NSString *)ne_et_elementId { 31 | return objc_getAssociatedObject(self, _cmd); 32 | } 33 | - (NSUInteger)ne_et_position { 34 | return [objc_getAssociatedObject(self, _cmd) unsignedIntegerValue]; 35 | } 36 | - (BOOL)ne_et_isElement { 37 | return self.ne_et_elementId.length > 0; 38 | } 39 | - (NEEventTracingEventActionConfig *)ne_et_logEventActionConfig { 40 | return objc_getAssociatedObject(self, _cmd); 41 | } 42 | 43 | - (void)ne_et_setElementId:(NSString *)elementId 44 | params:(NSDictionary *)params { 45 | [self ne_et_setElementId:elementId position:0 params:params]; 46 | } 47 | 48 | - (void)ne_et_setElementId:(NSString *)elementId 49 | position:(NSUInteger)position 50 | params:(NSDictionary *)params { 51 | [self ne_et_setElementId:elementId position:position params:params eventAction:nil]; 52 | } 53 | 54 | - (void)ne_et_setElementId:(NSString *)elementId 55 | params:(NSDictionary *)params 56 | eventAction:(void(^ NS_NOESCAPE _Nullable)(NEEventTracingEventActionConfig *config))block { 57 | [self ne_et_setElementId:elementId position:0 params:params eventAction:block]; 58 | } 59 | 60 | - (void)ne_et_setElementId:(NSString *)elementId 61 | position:(NSUInteger)position 62 | params:(NSDictionary *)params 63 | eventAction:(void(^ NS_NOESCAPE _Nullable)(NEEventTracingEventActionConfig *config))block { 64 | if (![elementId isKindOfClass:NSString.class] || !elementId.length) { 65 | return; 66 | } 67 | 68 | objc_setAssociatedObject(self, @selector(ne_et_elementId), elementId, OBJC_ASSOCIATION_COPY_NONATOMIC); 69 | objc_setAssociatedObject(self, @selector(ne_et_position), @(position), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 70 | 71 | NSMutableDictionary *innerParams = [self ne_et_innerParams]; 72 | 73 | if ([params isKindOfClass:NSDictionary.class] && params.count) { 74 | [innerParams addEntriesFromDictionary:params]; 75 | } 76 | if (position > 0) { 77 | [innerParams setObject:@(position).stringValue forKey:NE_ET_PARAM_CONST_KEY_POSITION]; 78 | } 79 | 80 | NEEventTracingEventActionConfig *actionConfig = [NEEventTracingEventActionConfig configWithEvent:NE_ET_EVENT_ID_E_CLCK]; 81 | // UIAlertControler中的点击事件,默认 useForRefer == NO 82 | actionConfig.useForRefer = NO; 83 | !block ?: block(actionConfig); 84 | 85 | objc_setAssociatedObject(self, @selector(ne_et_logEventActionConfig), actionConfig, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 86 | } 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Categorys/UIAlertController+EventTracing.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIAlertController+EventTracing.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/7. 6 | // 7 | 8 | #import "UIAlertController+EventTracingParams.h" 9 | #import "UIView+EventTracing.h" 10 | 11 | @implementation UIAlertController (EventTracing) 12 | 13 | - (BOOL)ne_et_isIgnoreReferCascade { 14 | return self.view.ne_et_ignoreReferCascade; 15 | } 16 | 17 | - (void)ne_et_setIgnoreReferCascade:(BOOL)ne_et_ignoreReferCascade { 18 | self.view.ne_et_ignoreReferCascade = ne_et_ignoreReferCascade; 19 | } 20 | 21 | - (BOOL)ne_et_psreferMute { 22 | return self.view.ne_et_psreferMute; 23 | } 24 | - (void)ne_et_setPsreferMute:(BOOL)ne_et_psreferMute { 25 | self.view.ne_et_psreferMute = ne_et_psreferMute; 26 | } 27 | 28 | - (BOOL)ne_et_subpagePvToReferEnable { 29 | return self.view.ne_et_subpagePvToReferEnable; 30 | } 31 | - (void)ne_et_setSubpagePvToReferEnable:(BOOL)ne_et_subpagePvToReferEnable { 32 | self.view.ne_et_subpagePvToReferEnable = ne_et_subpagePvToReferEnable; 33 | } 34 | - (NEEventTracingPageReferConsumeOption)ne_et_subpageConsumeOption { 35 | return self.view.ne_et_subpageConsumeOption; 36 | } 37 | - (void)ne_et_setSubpageConsumeOption:(NEEventTracingPageReferConsumeOption)ne_et_subpageConsumeOption { 38 | self.view.ne_et_subpageConsumeOption = ne_et_subpageConsumeOption; 39 | } 40 | - (void)ne_et_clearSubpageConsumeReferOption { 41 | [self.view ne_et_clearSubpageConsumeReferOption]; 42 | } 43 | - (void)ne_et_makeSubpageConsumeAllRefer { 44 | [self.view ne_et_makeSubpageConsumeAllRefer]; 45 | } 46 | - (void)ne_et_makeSubpageConsumeEventRefer { 47 | [self.view ne_et_makeSubpageConsumeEventRefer]; 48 | } 49 | 50 | - (void)ne_et_configLastestActionWithElementId:(NSString *)elementId 51 | params:(NSDictionary *)params { 52 | [self ne_et_configLastestActionWithElementId:elementId position:0 params:params]; 53 | } 54 | 55 | - (void)ne_et_configLastestActionWithElementId:(NSString *)elementId 56 | position:(NSUInteger)position 57 | params:(NSDictionary *)params { 58 | [self ne_et_configLastestActionWithElementId:elementId position:position params:params eventAction:nil]; 59 | } 60 | 61 | - (void)ne_et_configLastestActionWithElementId:(NSString *)elementId 62 | params:(NSDictionary *)params 63 | eventAction:(void (^ NS_NOESCAPE _Nullable)(NEEventTracingEventActionConfig *))block { 64 | [self ne_et_configLastestActionWithElementId:elementId position:0 params:params eventAction:block]; 65 | } 66 | 67 | - (void)ne_et_configLastestActionWithElementId:(NSString *)elementId 68 | position:(NSUInteger)position 69 | params:(NSDictionary *)params 70 | eventAction:(void (^ NS_NOESCAPE _Nullable)(NEEventTracingEventActionConfig *))block { 71 | UIAlertAction *alertAction = [self.actions lastObject]; 72 | 73 | [alertAction ne_et_setElementId:elementId position:position params:params eventAction:block]; 74 | } 75 | @end 76 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Categorys/UIView+EventTracingRefer.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+EventTracingRefer.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/1. 6 | // 7 | 8 | #import "UIView+EventTracingPrivate.h" 9 | #import 10 | 11 | @implementation UIView (EventTracingRefer) 12 | 13 | - (void)ne_et_makeReferToid:(NSString *)toid {/*已废弃*/} 14 | 15 | - (void)ne_et_makeReferToids:(NSString *)toid, ... {/*已废弃*/} 16 | 17 | - (void)ne_et_remakeReferToid:(NSString *)toid {/*已废弃*/} 18 | 19 | - (void)ne_et_remakeReferToids:(NSString *)toid, ... {/*已废弃*/} 20 | 21 | - (void)_et_makeReferToids:(NSArray *)toids reset:(BOOL)reset __attribute__((objc_direct)) {/*已废弃*/} 22 | 23 | - (void)ne_et_clearReferToids {/*已废弃*/} 24 | 25 | #pragma mark - getters & setters 26 | - (NSArray *)ne_et_toids {/*已废弃*/ return nil;} 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Categorys/UIView+EventTracingReuse.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+EventTracingReuse.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/3/18. 6 | // 7 | 8 | #import "UIView+EventTracing.h" 9 | #import "NEEventTracingDefines.h" 10 | #import "NEEventTracingSentinel.h" 11 | #import "NEEventTracingEngine+Private.h" 12 | #import "UIView+EventTracingPrivate.h" 13 | 14 | #import 15 | 16 | @implementation UIViewController (EventTracingReuse) 17 | - (NSString *)ne_et_reuseIdentifier { 18 | return self.p_ne_et_view.ne_et_reuseIdentifier; 19 | } 20 | - (NSString *)ne_et_bizLeafIdentifier { 21 | return self.p_ne_et_view.ne_et_bizLeafIdentifier; 22 | } 23 | - (NSString * _Nonnull (^)(NSString * _Nonnull))ne_et_autoClassifyIdAppend { 24 | return self.p_ne_et_view.ne_et_autoClassifyIdAppend; 25 | } 26 | - (void)ne_et_bindDataForReuse:(id)data { 27 | [self.p_ne_et_view ne_et_bindDataForReuse:data]; 28 | } 29 | - (void)ne_et_setNeedsImpress { 30 | [self.p_ne_et_view ne_et_setNeedsImpress]; 31 | } 32 | @end 33 | 34 | @implementation UIView (EventTracingReuse) 35 | 36 | - (NSString *)ne_et_reuseIdentifier { 37 | return self.ne_et_props.reuseIdentifier; 38 | } 39 | - (NSString *)ne_et_bizLeafIdentifier { 40 | return self.ne_et_props.bizLeafIdentifier; 41 | } 42 | - (NSString * _Nonnull (^)(NSString * _Nonnull))ne_et_autoClassifyIdAppend { 43 | return self.ne_et_props.autoClassifyIdAppend; 44 | } 45 | - (void)ne_et_bindDataForReuse:(id)data { 46 | [self.ne_et_props bindDataForReuse:data]; 47 | } 48 | 49 | - (void)ne_et_setNeedsImpress { 50 | void(^block)(void) = ^() { 51 | [self.ne_et_props.reuseSEQ increase]; 52 | [self.ne_et_props setResueIdentifierNeedsUpdate]; 53 | 54 | [[NEEventTracingEngine sharedInstance] traverse:self]; 55 | }; 56 | 57 | NEETDispatchMainAsyncSafe(block); 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Core/NEEventTracingContext+Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingContext+Private.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/2/25. 6 | // 7 | 8 | #import "NEEventTracingContext.h" 9 | #import "NEEventTracingTraversalRunner.h" 10 | #import "NEEventTracingVTree.h" 11 | #import "NEEventTracingAppLifecycleProcotol.h" 12 | #import "NEEventTracingEngine+Action.h" 13 | #import "NEEventTracingSentinel.h" 14 | 15 | #import "NEEventTracingTraverser.h" 16 | #import "NEEventTracingTraversalRunner.h" 17 | #import "NEEventTracingEventEmitter.h" 18 | #import "NEEventTracingEventOutput.h" 19 | #import "NEEventTracingParamGuardExector.h" 20 | #import "NEEventTracingReferFuncs.h" 21 | 22 | NS_ASSUME_NONNULL_BEGIN 23 | 24 | @class NEEventTracingEngine; 25 | @interface NEEventTracingContext : NSObject { 26 | BOOL _started; 27 | NEEventTracingSentinel *_pgstepSentinel; 28 | NEEventTracingSentinel *_actseqSentinel; 29 | 30 | NSTimeInterval _appStartedTime; 31 | NSTimeInterval _appLastAtForegroundTime; 32 | NSTimeInterval _appLastEnterBackgroundTime; 33 | 34 | __weak id _extraConfigurationProvider; 35 | NSHashTable> *_innerReferObservers; 36 | } 37 | 38 | @property(nonatomic, weak) NEEventTracingEngine *engine; 39 | 40 | @property(nonatomic, copy) dispatch_semaphore_t lock; 41 | 42 | @property(nonatomic, assign, getter=isFirstViewControllerAppeared) BOOL firstViewControllerAppeared; 43 | @property(nonatomic, assign, readonly) NSInteger appEnterBackgroundSeq; 44 | 45 | @property(nonatomic, strong) NEEventTracingTraverser *traverser; 46 | @property(nonatomic, strong) NEEventTracingTraversalRunner *traversalRunner; 47 | @property(nonatomic, strong) NEEventTracingEventEmitter *eventEmitter; 48 | @property(nonatomic, strong) NEEventTracingEventOutput *eventOutput; 49 | @property(nonatomic, strong, readonly) NEEventTracingParamGuardExector *paramGuardExector; 50 | 51 | @property(nonatomic, strong) NSArray *needIncreaseActseqLogEvents; 52 | @property(nonatomic, strong) NSMutableArray *stockedEventActions; 53 | @property(nonatomic, strong) NSArray *needStartHsreferOids; 54 | 55 | - (void)refreshAppInActiveState; 56 | - (void)markRunState:(BOOL)started; 57 | 58 | @end 59 | 60 | @interface NEEventTracingContext (Refer) 61 | 62 | // pgstep 63 | - (NSUInteger)pgstepIncreased; 64 | - (NSUInteger)actseqIncreased; 65 | 66 | @end 67 | 68 | NS_ASSUME_NONNULL_END 69 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Core/NEEventTracingEngine+Action.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEngine+Action.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/3/23. 6 | // 7 | 8 | #import "NEEventTracingEngine.h" 9 | #import "NEEventTracingEventEmitter.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingEngine (ActionPrivate) 14 | 15 | - (void)flushStockedActionsIfNeeded:(NEEventTracingVTree *)VTree; 16 | 17 | - (void)AOP_preLogWithEvent:(NSString *)event view:(UIView *)view; 18 | - (void)AOP_preLogWithEvent:(NSString *)event 19 | view:(UIView *)view 20 | eventAction:(void(^ NS_NOESCAPE _Nullable)(NEEventTracingEventActionConfig *config))block; 21 | 22 | - (void)AOP_logWithEvent:(NSString *)event 23 | view:(UIView *)view 24 | params:(NSDictionary * _Nullable)params; 25 | 26 | - (void)AOP_logWithEvent:(NSString *)event 27 | view:(UIView *)view 28 | params:(NSDictionary * _Nullable)params 29 | eventAction:(void(^ NS_NOESCAPE _Nullable)(NEEventTracingEventActionConfig *config))block; 30 | 31 | @end 32 | 33 | NS_ASSUME_NONNULL_END 34 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Core/NEEventTracingEngine+Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEngine+Private.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/4. 6 | // 7 | 8 | 9 | #import "NEEventTracingEngine.h" 10 | #import "NEEventTracingContext+Private.h" 11 | #import "NEEventTracingDefines.h" 12 | #import "NEEventTracingEngine+Action.h" 13 | #import "NEEventTracingEngine+TraverseAction.h" 14 | #import "NEEventTracingAppLifecycleProcotol.h" 15 | 16 | NS_ASSUME_NONNULL_BEGIN 17 | 18 | @interface NEEventTracingEngine () 19 | 20 | @property(nonatomic, strong, readonly) NEEventTracingContext *ctx; 21 | 22 | @property(nonatomic, strong) NEEventTracingStockedTraverseActionRecord *stockedTraverseActionRecord; 23 | 24 | // 列表滚动 25 | @property(nonatomic, strong) NSHashTable *stockedTraverseScrollViews; 26 | 27 | - (NSUInteger)pgstepIncreased; 28 | - (NSUInteger)actseqIncreased; 29 | - (void)refreshAppInActiveState; 30 | 31 | @end 32 | 33 | @interface NEEventTracingEngine (InnerLifecycle) 34 | @end 35 | 36 | @interface NEEventTracingEngine (InnerTraverse) 37 | 38 | - (void)traverseImmediatelyIfNeeded; 39 | 40 | @end 41 | 42 | NS_ASSUME_NONNULL_END 43 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Core/NEEventTracingEngine+TraverseAction.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEngine+Traverse.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/13. 6 | // 7 | 8 | #import "NEEventTracingEngine.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface NEEventTracingTraverseAction : NSObject 13 | @property(nonatomic, weak, readonly) UIView *view; 14 | @property(nonatomic, assign, readonly) BOOL viewIsNil; 15 | 16 | @property(nonatomic, assign) BOOL ignoreViewInvisible; 17 | 18 | + (instancetype)actionWithView:(UIView * _Nullable)view; 19 | @end 20 | 21 | // 1. 如果存在 action.view 为 nil 的UI变动事件,则直接表明需要 `traverse`,忽略后面的所有UI变动事件; 否则 => 2 22 | // 2. 将action添加进来,供后面CPU空闲时,判断是否需要真正的 `traverse` 使用 23 | @interface NEEventTracingStockedTraverseActionRecord : NSObject 24 | @property(nonatomic, assign, readonly) BOOL passthrough; // 如果存在 action.view 等于nil的,即为 yes 25 | @property(nonatomic, strong, readonly) NSArray *actions; 26 | 27 | - (void)actionDidOccured:(NEEventTracingTraverseAction *)action; 28 | - (void)reset; 29 | @end 30 | 31 | @interface NEEventTracingEngine (TraverseAction) 32 | 33 | /*! 34 | 打一个遍历标识,在合适的时候会进行遍历 35 | @discussion 有条件的遍历,如果该view的变动,不应该引起 traverse, 则不再打遍历标识 36 | 以下几个情况不会打遍历标识: 37 | 1. view自身及其subViews都不是节点(page/element) 38 | */ 39 | - (void)traverse:(UIView * _Nullable)view; 40 | - (void)traverse:(UIView * _Nullable)view 41 | traverseAction:(void(^ NS_NOESCAPE _Nullable)(NEEventTracingTraverseAction *action))block; 42 | 43 | - (void)traverseForScrollView:(UIScrollView *)scrollView; 44 | 45 | @end 46 | 47 | NS_ASSUME_NONNULL_END 48 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Core/NEEventTracingEngine+TraverseAction.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEngine+Traverse.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/13. 6 | // 7 | 8 | #import "NEEventTracingEngine+TraverseAction.h" 9 | #import "NEEventTracingEngine+Private.h" 10 | #import 11 | 12 | @implementation NEEventTracingTraverseAction 13 | @synthesize view = _view; 14 | @synthesize viewIsNil = _viewIsNil; 15 | 16 | + (instancetype)actionWithView:(UIView * _Nullable)view { 17 | NEEventTracingTraverseAction *action = [[NEEventTracingTraverseAction alloc] init]; 18 | action->_view = view; 19 | action->_viewIsNil = view == nil; 20 | return action; 21 | } 22 | @end 23 | 24 | @interface NEEventTracingStockedTraverseActionRecord() 25 | @property(nonatomic, strong) NSMutableArray *innerActions; 26 | @end 27 | @implementation NEEventTracingStockedTraverseActionRecord 28 | @synthesize passthrough = _passthrough; 29 | 30 | - (instancetype)init { 31 | self = [super init]; 32 | if (self) { 33 | _innerActions = [NSMutableArray array]; 34 | } 35 | return self; 36 | } 37 | 38 | - (void)actionDidOccured:(NEEventTracingTraverseAction *)action { 39 | if (_passthrough) { 40 | return; 41 | } 42 | 43 | if (action.viewIsNil) { 44 | _passthrough = YES; 45 | [_innerActions removeAllObjects]; 46 | 47 | return; 48 | } 49 | 50 | [_innerActions addObject:action]; 51 | } 52 | 53 | - (void)reset { 54 | _passthrough = NO; 55 | [_innerActions removeAllObjects]; 56 | } 57 | 58 | - (NSArray *)actions { 59 | return _innerActions.copy; 60 | } 61 | 62 | @end 63 | 64 | @implementation NEEventTracingEngine (TraverseAction) 65 | 66 | - (void)traverse:(UIView * _Nullable)view { 67 | [self traverse:view traverseAction:nil]; 68 | } 69 | 70 | - (void)traverse:(UIView *)view traverseAction:(void (^ NS_NOESCAPE _Nullable)(NEEventTracingTraverseAction * _Nonnull))block { 71 | /// MARK: 后台情况下,直接忽略树的构建 72 | if (!self.context.isAppInActive) { 73 | return; 74 | } 75 | 76 | NEEventTracingTraverseAction *action = [NEEventTracingTraverseAction actionWithView:view]; 77 | !block ?: block(action); 78 | 79 | void(^insertToStockedActions)(void) = ^() { 80 | if (!self.stockedTraverseActionRecord) { 81 | self.stockedTraverseActionRecord = [[NEEventTracingStockedTraverseActionRecord alloc] init]; 82 | } 83 | 84 | [self.stockedTraverseActionRecord actionDidOccured:action]; 85 | }; 86 | 87 | NEETDispatchMainAsyncSafe(insertToStockedActions); 88 | } 89 | 90 | - (void)traverseForScrollView:(UIScrollView *)scrollView { 91 | if (![scrollView isKindOfClass:UIScrollView.class] || [self.stockedTraverseScrollViews containsObject:scrollView]) { 92 | return; 93 | } 94 | 95 | if (!self.stockedTraverseScrollViews) { 96 | self.stockedTraverseScrollViews = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory]; 97 | } 98 | 99 | [self.stockedTraverseScrollViews addObject:scrollView]; 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Diff/NEEventTracingDiff.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingDiff.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/3/16. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingDiffable.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingDiffResults : NSObject 14 | 15 | /// 是否结果一致 16 | @property (nonatomic, assign, readonly) BOOL hasDiffs; 17 | 18 | /// 第二个数组跟第一个比,多了哪些节点 19 | @property(nonatomic, strong, readonly) NSArray> *inserts; 20 | 21 | /// 第二个数组跟第一个比,少了哪些节点 22 | @property(nonatomic, strong, readonly) NSArray> *deletes; 23 | 24 | - (instancetype)init NS_UNAVAILABLE; 25 | + (instancetype)new NS_UNAVAILABLE; 26 | 27 | @end 28 | 29 | FOUNDATION_EXPORT NEEventTracingDiffResults *NE_ET_DiffBetweenArray(NSArray> *_Nullable newArray, 30 | NSArray> *_Nullable oldArray); 31 | 32 | NS_ASSUME_NONNULL_END 33 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Diff/NEEventTracingDiffable.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingDiffable.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/3/16. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @protocol NEEventTracingDiffable 13 | 14 | // 节点的id 15 | - (nonnull id)ne_et_diffIdentifier; 16 | 17 | // 节点是否相等 18 | - (BOOL)ne_et_isEqualToDiffableObject:(nullable id)object; 19 | 20 | @end 21 | 22 | NS_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Exceptions/NEEventTracingExceptionDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingExceptionDelegate.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/5/20. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @protocol NEEventTracingExceptionDelegate 13 | 14 | @optional 15 | // param guard invalid exceptions 16 | - (void)paramGuardExceptionKey:(NSString *)key 17 | code:(NSInteger)code 18 | paramKey:(NSString *)paramKey 19 | regex:(NSString *)regex 20 | error:(NSError *)error; 21 | 22 | - (void)internalExceptionKey:(NSString *)key 23 | code:(NSInteger)code 24 | message:(NSString *)message 25 | node:(NEEventTracingVTreeNode *)node 26 | shouldNotEqualToOther:(NEEventTracingVTreeNode *)otherNode; 27 | 28 | - (void)internalExceptionKey:(NSString *)key 29 | code:(NSInteger)code 30 | message:(NSString *)message 31 | node:(NEEventTracingVTreeNode *)node 32 | spmShouldNotEqualToOther:(NEEventTracingVTreeNode *)otherNode; 33 | 34 | - (void)logicalMountEndlessLoopExceptionKey:(NSString *)key 35 | code:(NSInteger)code 36 | message:(NSString *)message 37 | view:(UIView *)view 38 | viewToMount:(UIView *)viewToMount; 39 | 40 | - (void)viewControllerDidNotLoadView:(UIViewController *)viewController message:(NSString *)message; 41 | 42 | @end 43 | 44 | NS_ASSUME_NONNULL_END 45 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Log/NEEventTracingInternalLog.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingInternalLog.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/3/9. 6 | // 7 | #ifndef NEEventTracingInternalLog_h 8 | #define NEEventTracingInternalLog_h 9 | 10 | #import "NEEventTracingDefines.h" 11 | 12 | FOUNDATION_EXPORT void _ETLog(ETLogLevel level, NSString *levelStr, NSString *tag, const char *file, const char *function, NSUInteger line, NSString *format, ...); 13 | 14 | #define _ETLog_(level, tag, FORMAT, ...) \ 15 | do { \ 16 | _ETLog(ETLogLevel ## level, @# level, tag, __FILE__, __PRETTY_FUNCTION__, __LINE__, FORMAT, ## __VA_ARGS__); \ 17 | } while(0); 18 | 19 | #define ETLogV(tag, format, ...) _ETLog_(Verbose, tag, format, ## __VA_ARGS__) 20 | #define ETLogE(tag, format, ...) _ETLog_(Error, tag, format, ## __VA_ARGS__) 21 | #define ETLogI(tag, format, ...) _ETLog_(Info, tag, format, ## __VA_ARGS__) 22 | #define ETLogD(tag, format, ...) _ETLog_(Debug, tag, format, ## __VA_ARGS__) 23 | #define ETLogS(tag, format, ...) _ETLog_(System, tag, format, ## __VA_ARGS__) 24 | #define ETLogW(tag, format, ...) _ETLog_(Warning, tag, format, ## __VA_ARGS__) 25 | 26 | #endif /* NEEventTracingInternalLog_h */ 27 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Log/NEEventTracingInternalLog.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingInternalLog.m 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/3/9. 6 | // 7 | 8 | #import "NEEventTracingInternalLog.h" 9 | #import "NEEventTracingEngine+Private.h" 10 | 11 | void _ETLog(ETLogLevel level, NSString *levelStr, NSString *tag, const char *file, const char *function, NSUInteger line, NSString *format, ...) { 12 | va_list arglist; 13 | va_start(arglist, format); 14 | 15 | NSString *message = [[NSString alloc] initWithFormat:format arguments:arglist]; 16 | NSString *outContent = [NSString stringWithFormat:@"[NEEventTracing][%@]: %@, %@", levelStr, tag, message]; 17 | 18 | id internalLogOutputInterface = [[[NEEventTracingEngine sharedInstance] context] internalLogOutputInterface]; 19 | if ([internalLogOutputInterface respondsToSelector:@selector(logLevel:content:)]) { 20 | [internalLogOutputInterface logLevel:level content:outContent]; 21 | } 22 | 23 | va_end(arglist); 24 | } 25 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Output/NEEventTracingEventOutput.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventOutput.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/3/22. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingOutputFormatter.h" 10 | #import "NEEventTracingEventOutputChannel.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface NEEventTracingEventOutput : NSObject 15 | 16 | @property(nonatomic, strong, readonly) id formatter; 17 | @property(nonatomic, weak, readonly) id publicDynamicParamsProvider; 18 | @property(nonatomic, strong, readonly) NSDictionary *staticPublicParmas; 19 | @property(nonatomic, strong, readonly) NSDictionary *currentActivePublicParmas; 20 | 21 | @property(nonatomic, strong, readonly) NSArray> *allOutputChannels; 22 | @property(nonatomic, strong, readonly) NSArray> *allParmasFilters; 23 | 24 | - (void)configStaticPublicParams:(NSDictionary *)params withParamGuard:(BOOL)withParamGuard; 25 | - (void)configCurrentActivePublicParams:(NSDictionary *)params withParamGuard:(BOOL)withParamGuard; 26 | - (void)removeCurrentActivePublicParmas; 27 | 28 | @end 29 | 30 | NS_ASSUME_NONNULL_END 31 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Output/NEEventTracingEventOutputChannel.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventOutputChannel.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/3/22. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | /// MARK: 日志输出的通道,可以配置多个 13 | @class NEEventTracingEventOutput; 14 | @protocol NEEventTracingEventOutputChannel 15 | 16 | - (void)eventOutput:(NEEventTracingEventOutput *)eventOutput didOutputEvent:(NSString *)event json:(NSDictionary *)json; 17 | 18 | @optional 19 | - (void)eventOutput:(NEEventTracingEventOutput *)eventOutput 20 | didOutputEvent:(NSString *)event 21 | node:(NEEventTracingVTreeNode * _Nullable)node 22 | json:(NSDictionary *)json; 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Output/NEEventTracingOutputFlattenFormatter.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingOutputFlattenFormatter.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/4. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingOutputFormatter.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingOutputFlattenFormatter : NSObject 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Output/NEEventTracingReferNodeSCMDefaultFormatter.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingReferNodeSCMDefaultFormatter.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/9/2. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingOutputFormatter.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingReferNodeSCMDefaultFormatter : NSObject 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Output/NEEventTracingReferNodeSCMDefaultFormatter.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingReferNodeSCMDefaultFormatter.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/9/2. 6 | // 7 | 8 | #import "NEEventTracingReferNodeSCMDefaultFormatter.h" 9 | #import "NSString+EventTracingUtil.h" 10 | 11 | @implementation NEEventTracingReferNodeSCMDefaultFormatter 12 | 13 | - (nonnull NSString *)nodeSCMWithView:(nonnull UIView *)view 14 | node:(nonnull NEEventTracingVTreeNode *)node 15 | inVTree:(nonnull NEEventTracingVTree *)VTree { 16 | NSDictionary *nodeParams = [node nodeParams]; 17 | 18 | return [self nodeSCMWithNodeParams:nodeParams]; 19 | } 20 | 21 | - (BOOL)needsEncodeSCMForNode:(NEEventTracingVTreeNode *)node { 22 | NSDictionary *nodeParams = [node nodeParams]; 23 | 24 | return [self needsEncodeSCMForNodeParams:nodeParams]; 25 | } 26 | 27 | - (NSString *)nodeSCMWithNodeParams:(NSDictionary *)params { 28 | #define stringify(s) !s ? @"" : ([s isKindOfClass:NSString.class] ? s : [NSString stringWithFormat:@"%@", s]) 29 | NSString *cid = stringify([params objectForKey:@"s_cid"]); 30 | NSString *ctype = stringify([params objectForKey:@"s_ctype"]); 31 | NSString *ctraceid = stringify([params objectForKey:@"s_ctraceid"]); 32 | NSString *ctrp = stringify([params objectForKey:@"s_ctrp"]); 33 | #undef stringify 34 | 35 | BOOL needsEncode = [cid isKindOfClass:NSString.class] && [cid ne_et_simplyNeedsEncoded]; 36 | NSString *cidValue = needsEncode ? [cid ne_et_urlEncode] : cid; 37 | 38 | NSMutableString *result = [NSMutableString string]; 39 | [result appendString:(cidValue ?: @"")]; 40 | [result appendString:@":"]; 41 | [result appendString:(ctype ?: @"")]; 42 | [result appendString:@":"]; 43 | [result appendString:(ctraceid ?: @"")]; 44 | [result appendString:@":"]; 45 | [result appendString:(ctrp ?: @"")]; 46 | 47 | return result.copy; 48 | } 49 | 50 | - (BOOL)needsEncodeSCMForNodeParams:(NSDictionary *)params { 51 | NSString *cid = [params objectForKey:@"s_cid"]; 52 | 53 | return [cid isKindOfClass:NSString.class] && [cid ne_et_simplyNeedsEncoded];; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Output/Private/NEEventTracingEventOutput+Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventOutput+Private.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/3/24. 6 | // 7 | 8 | #import "NEEventTracingEventOutput.h" 9 | #import "NEEventTracingContext.h" 10 | #import "UIView+EventTracingPrivate.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface NEEventTracingEventOutput () 15 | 16 | @property(nonatomic, strong) NSHashTable> *outputChannels; 17 | @property(nonatomic, strong) NSHashTable> *outputParamsFilters; 18 | @property(nonatomic, strong) NSMutableDictionary *innerStaticPublicParams; 19 | @property(nonatomic, strong, nullable) NSMutableDictionary *innerCurrentActivePublicParams; 20 | 21 | - (void)outputEvent:(NSString *)event 22 | contextParams:(NSDictionary * _Nullable)contextParams 23 | logActionParams:(NSDictionary * _Nullable)logActionParams 24 | node:(NEEventTracingVTreeNode *)node 25 | inVTree:(NEEventTracingVTree *)VTree; 26 | 27 | - (void)outputEventWithoutNode:(NSString *)event contextParams:(NSDictionary * _Nullable)contextParams; 28 | 29 | - (NSDictionary *)publicParamsForEvent:(NSString * _Nullable)event 30 | node:(NEEventTracingVTreeNode * _Nullable)node 31 | inVTree:(NEEventTracingVTree * _Nullable)VTree; 32 | 33 | - (NSDictionary *)fulllyParamsForEvent:(NSString * _Nullable)event 34 | contextParams:(NSDictionary * _Nullable)contextParams 35 | logActionParams:(NSDictionary * _Nullable)logActionParams 36 | node:(NEEventTracingVTreeNode * _Nullable)node 37 | inVTree:(NEEventTracingVTree * _Nullable)VTree; 38 | @end 39 | 40 | @interface NEEventTracingEventOutput (MergeLogForH5) 41 | 42 | - (void)outputEvent:(NSString *)event 43 | baseNode:(NEEventTracingVTreeNode *)baseNode 44 | useForRefer:(BOOL)useForRefer 45 | fromH5:(BOOL)fromH5 46 | elist:(NSArray *> *)elist 47 | plist:(NSArray *> *)plist 48 | positionKey:(NSString *)positionKey 49 | params:(NSDictionary *)params; 50 | 51 | @end 52 | 53 | NS_ASSUME_NONNULL_END 54 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/ParamGuard/NEEventTracingParamGuardConfiguration.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingParamGuardConfiguration.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/5/20. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | extern NSString * const ETParamKeyGuardErrorRegxKey; 13 | 14 | FOUNDATION_EXPORT BOOL NE_ET_CheckEventKeyValid(NSString *eventKey); 15 | FOUNDATION_EXPORT BOOL NE_ET_CheckPublicParamKeyValid(NSString *publicParamKey); 16 | FOUNDATION_EXPORT BOOL NE_ET_CheckUserParamKeyValid(NSString *userParamKey); 17 | 18 | @protocol NEEventTracingParamGuardConfiguration 19 | 20 | // default: `^(_)[a-z]+(?:[-_][a-z]+)*$` 21 | // 参见: `NEEventTracingExceptionEventKeyInvalid` 22 | @property(nonatomic, copy) NSString *eventKeyRegx; 23 | // default: `^(g_)[a-z][^\\W_]+[^\\W_]*(?:[-_][^\\W_]+)*$` 24 | // 参见: `NEEventTracingExceptionPublicParamInvalid` 25 | @property(nonatomic, copy) NSString *publicParamRegx; 26 | 27 | // default: s_ 28 | @property(nonatomic, copy) NSString *userParamRegxOptionalPrefix; // 比如 s_ 29 | // default: `^[a-z][^\\W_]+[^\\W_]*(?:[-_][^\\W_]+)*$` 30 | @property(nonatomic, copy) NSString *userParamRegx; 31 | 32 | // default: `^[s_]{0,}[a-z][^\\W_]+[^\\W_]*(?:[-_][^\\W_]+)*$` 33 | // 参见: `NEEventTracingExceptionUserParamInvalid` 34 | @property(nonatomic, readonly) NSString *userParamRegxFixed; 35 | 36 | @end 37 | 38 | NS_ASSUME_NONNULL_END 39 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/ParamGuard/Private/NEEventTracingParamGuardExector.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingParamGuardExector.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/5/20. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingParamGuardConfiguration.h" 10 | #import "NEEventTracingDefines.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface NEEventTracingParamGuardExector : NSObject 15 | 16 | - (void)asyncDoDispatchCheckTask:(void(^)(void))block; 17 | 18 | - (BOOL)checkEventKeyValid:(NSString *)eventKey error:(NSError ** _Nullable)error; 19 | - (BOOL)checkPublicParamKeyValid:(NSString *)publicParamKey error:(NSError ** _Nullable)error; 20 | - (BOOL)checkUserParamKeyValid:(NSString *)userParamKey error:(NSError ** _Nullable)error; 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Public/BILogBuilder/NEEventTracingMultiReferPatch.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingMultiReferPatch.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2022/12/6. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingContext.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | FOUNDATION_EXTERN NSUInteger NEEventTracingMultiRefersMaxCount; // => 5 14 | FOUNDATION_EXTERN NSString * NEEventTracingMultiRefersEvents; // => "_pv,_ec" 15 | 16 | /// 多级归因: 在一些实时分析的场景中,分析师需要知道实时某一个埋点向前N步的路径,但是离线数据上报是存量上报,没有那么实时 17 | /// 所以可以配置一些埋点会带上 N 级的归因 refer 18 | /// ==> `_multirefers` 19 | @interface NEEventTracingMultiReferPatch : NSObject 20 | 21 | /// MARK: 是数组 22 | @property(nonatomic, copy, readonly) NSArray *multiRefers; 23 | /// MARK: Array => JsonString 24 | @property(nonatomic, copy, readonly) NSString *multiRefersJsonString; 25 | 26 | + (instancetype)sharedPatch; 27 | - (void)patchOnContextBuilder:(id)builder; 28 | 29 | @end 30 | 31 | NS_ASSUME_NONNULL_END 32 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Public/NEEventTracing.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracing.h 3 | // Pods 4 | // 5 | // Created by dl on 2021/3/9. 6 | // 7 | 8 | // define 9 | #import "NEEventTracingDefines.h" 10 | #import "NEEventTracingReferFuncs.h" 11 | 12 | // engine 13 | #import "NEEventTracingEngine.h" 14 | #import "NEEventTracingContext.h" 15 | 16 | // formater 17 | #import "NEEventTracingOutputFormatter.h" 18 | 19 | // categories 20 | #import "UIView+EventTracing.h" 21 | #import "UIView+EventTracingNodeImpressObserver.h" 22 | #import "UIAlertController+EventTracingParams.h" 23 | #import "UIView+EventTracingPipEvent.h" 24 | #import "UIScrollView+EventTracingES.h" 25 | 26 | // VTree & Node 27 | #import "NEEventTracingVTree.h" 28 | #import "NEEventTracingVTreeNode.h" 29 | 30 | // Refer 31 | #import "NEEventTracingEventRefer.h" 32 | #import "NEEventTracingFormattedRefer.h" 33 | 34 | // output & format 35 | #import "NEEventTracingEventOutput.h" 36 | #import "NEEventTracingEventOutputChannel.h" 37 | #import "NEEventTracingOutputFlattenFormatter.h" 38 | 39 | // diff 40 | #import "NEEventTracingDiffable.h" 41 | #import "NEEventTracingDiff.h" 42 | 43 | // ParamGuard & Exception 44 | #import "NEEventTracingParamGuardConfiguration.h" 45 | #import "NEEventTracingExceptionDelegate.h" 46 | 47 | // others 48 | #import "NEEventTracingVTreeNodeExtraConfigProtocol.h" 49 | #import "NEEventTracingEventActionConfig.h" 50 | #import "NEEventTracingInternalLogOutputInterface.h" 51 | 52 | // Click Observers 53 | #import "NEEventTracingClickMonitor.h" 54 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Public/NEEventTracingAppLifecycleProcotol.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingAppLifecycleProcotol.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/3/24. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @protocol NEEventTracingAppLifecycleProcotol 13 | 14 | @required 15 | - (void)appViewController:(UIViewController *)controller changedToAppear:(BOOL)appear; 16 | - (void)appDidBecomeActive; 17 | - (void)appWillEnterForeground; 18 | - (void)appDidEnterBackground; 19 | - (void)appDidTerminate; 20 | 21 | @end 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Public/NEEventTracingEventActionConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventActionConfig.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/25. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface NEEventTracingEventActionConfig : NSObject 13 | - (instancetype)init NS_UNAVAILABLE; 14 | +(instancetype)new NS_UNAVAILABLE; 15 | 16 | // 标识该自定义事件,可以作为下一个页面的 _pgrefer&_psrefer 来对接 17 | // useForRefer == YES是, 忽略increaseActseq的值(当做YES对待),_actseq也会加1 18 | @property(nonatomic, assign) BOOL useForRefer; 19 | // 优先取这里的值,否则取 needIncreaseActseqForCustomLogEvent: 的设置 20 | @property(nonatomic, assign) BOOL increaseActseq; 21 | 22 | /// MARK: 针对H5场景,过来的埋点,在参与链路追踪的时候, 23 | @property(nonatomic, assign) BOOL fromH5; 24 | 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END 28 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Public/NEEventTracingInternalLogOutputInterface.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingInternalLogOutputInterface.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/5/19. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingDefines.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @protocol NEEventTracingInternalLogOutputInterface 14 | 15 | - (void)logLevel:(ETLogLevel)level content:(NSString *)content; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Public/NEEventTracingOutputFormatter.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingOutputFormatter.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/4. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingVTree.h" 10 | #import "NEEventTracingVTreeNode.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | /// MARK: 日志输出的格式 15 | @protocol NEEventTracingOutputFormatter 16 | 17 | /// 格式化生成日志的格式 18 | /// - Parameters: 19 | /// - event: 埋点的事件 20 | /// - logActionParams: 对象上的事件参数 21 | /// - node: 节点 22 | /// - VTree: 节点对应的VTree 23 | /// - Returns: 日志 Json 24 | - (NSDictionary *)formatWithEvent:(NSString *)event 25 | logActionParams:(NSDictionary * _Nullable)logActionParams 26 | node:(NEEventTracingVTreeNode *)node 27 | inVTree:(NEEventTracingVTree *)VTree; 28 | 29 | @end 30 | 31 | /// MARK: 动态公参的注入 32 | @protocol NEEventTracingOutputPublicDynamicParamsProvider 33 | 34 | /// 所有日志输出之前,通过调用该方法动态添加全局公参,返回的公参,仅仅对本次调用生效 35 | /// - Parameters: 36 | /// - event: 埋点事件 37 | /// - node: 节点 38 | /// - VTree: 节点对应的VTree 39 | - (NSDictionary *)outputPublicDynamicParamsForEvent:(NSString *)event 40 | node:(NEEventTracingVTreeNode * _Nullable)node 41 | inVTree:(NEEventTracingVTree * _Nullable)VTree; 42 | 43 | @end 44 | 45 | /// 日志输出到 `OutputChannel` 之前,有一些修改或者监控的能力 46 | @protocol NEEventTracingOutputParamsFilter 47 | 48 | /// 给每一个即将要输出的日志内容,做二次加工 49 | /// - Parameters: 50 | /// - event: 埋点的事件 51 | /// - originalJson: 原始 Json 52 | /// - node: 节点 53 | /// - VTree: 节点对应的VTree 54 | /// - Returns: 修改之后的 Json 55 | - (NSDictionary *)filteredJsonWithEvent:(NSString *)event 56 | originalJson:(NSDictionary *)originalJson 57 | node:(NEEventTracingVTreeNode * _Nullable)node 58 | inVTree:(NEEventTracingVTree * _Nullable)VTree; 59 | 60 | @end 61 | 62 | /// @brief SCM的格式化配置 63 | /// @discussion 所有的 _xxrefer 的格式中都包含 _scm, 而且是自底向上递归节点的 _nodeSCM 通过 `|` 拼接得来 64 | /// @discussion 默认实现使用 NEEventTracingReferNodeSCMDefaultFormatter,格式 => s_cid:s_ctype:s_ctraceid:s_ctrp 65 | @protocol NEEventTracingReferNodeSCMFormatter 66 | 67 | /// scm 格式构造方法 68 | /// @param view 节点对应的view对象 69 | /// @param node 节点 70 | /// @param VTree 节点对应的VTree 71 | - (NSString *)nodeSCMWithView:(UIView *)view 72 | node:(NEEventTracingVTreeNode *)node 73 | inVTree:(NEEventTracingVTree *)VTree; 74 | 75 | /// 如果cid中有特殊字符,则需要加密 76 | /// @param node 节点 77 | - (BOOL)needsEncodeSCMForNode:(NEEventTracingVTreeNode *)node; 78 | 79 | /// MARK: for H5 80 | /// 对于 H5 场景,H5内部的节点对 Native 不可见,仅仅有 params,对于这个场景,scm的生成就没有 view node 等信息 81 | /// @param params H5 节点的参数 82 | - (NSString *)nodeSCMWithNodeParams:(NSDictionary *)params; 83 | 84 | /// MARK: for H5 85 | /// 对于 H5 场景,H5内部的节点对 Native 不可见,仅仅有 params,对于这个场景,scm的生成就没有 view node 等信息 86 | /// @param params H5 节点的参数 87 | - (BOOL)needsEncodeSCMForNodeParams:(NSDictionary *)params; 88 | 89 | @end 90 | 91 | NS_ASSUME_NONNULL_END 92 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Public/NEEventTracingReferFuncs.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingReferFuncs.h 3 | // Pods 4 | // 5 | // Created by dl on 2021/6/8. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingEventRefer.h" 10 | 11 | #ifndef NEEventTracingReferFuncs_h 12 | #define NEEventTracingReferFuncs_h 13 | 14 | /// MARK: find view (注:查找链路遵循原始的view树,忽略逻辑挂载) 15 | // 1. 基于当前 view 向上查找,找到第一个 节点 即返回 16 | // 没有性能问题,推荐使用 17 | __attribute__((overloadable)) 18 | FOUNDATION_EXPORT UIView * _Nullable NE_ET_FindAncestorNodeViewAt(UIView *view); 19 | 20 | /// MARK: find view (注:查找链路遵循原始的view树,忽略逻辑挂载) 21 | // 2. 基于当前 view 向上查找,找到第一个 oid 相等的即返回 22 | // 没有性能问题,推荐使用 23 | FOUNDATION_EXPORT UIView * _Nullable NE_ET_FindAncestorNodeViewAt(UIView *view, NSString *oid); 24 | 25 | // 3. 基于当前 view 向下查找,找到第一个 oid 相等的即返回 26 | // 右侧深度遍历,不太建议使用 27 | FOUNDATION_EXPORT UIView * _Nullable NE_ET_FindSubNodeViewAt(UIView *view, NSString *oid); 28 | // 4. 全局查找 29 | // 右侧深度遍历,不推荐使用 30 | FOUNDATION_EXPORT UIView * _Nullable NE_ET_FindNodeViewGlobally(NSString *oid); 31 | 32 | // 5. 获取 view/vc 的spm 33 | // 过早的调用该方法可能获取不到(此时虚拟树未生成, _spm无法计算得出) 34 | // 使用场景: 做一些自定义事件的时候使用,这个时候view树已经处于稳定状态,虚拟树也已经生成好了的,这个时候是可以获取到spm的 35 | FOUNDATION_EXPORT NSString * _Nullable NE_ET_spmForView(UIView *v); 36 | FOUNDATION_EXPORT NSString * _Nullable NE_ET_spmForViewController(UIViewController *vc); 37 | 38 | // 6.1 获取 event refer 39 | // 指定了view,可防止取错 40 | // event refer: 41 | // 其中, _spm 业务方可以自定义formatter: NEEventTracingEventReferFormatter 42 | // _spm默认: 取值 node.spm 43 | __attribute__((overloadable)) 44 | FOUNDATION_EXPORT NSString * _Nullable NE_ET_eventReferForView(UIView *v); 45 | 46 | // 6.2 获取 evnet refer 47 | // 如果后面即将在 `view` 上触发一个event,可以采用 `预取` 的方式来获取下次点击的 event refer 48 | FOUNDATION_EXPORT NSString * _Nullable NE_ET_eventReferForView(UIView *v, BOOL useNextActseq); 49 | 50 | // 7. 获取 event refer 51 | // 没有指定view,默认取上次在任何一个view上发生了 event事件 时的refer 52 | // 特点: 53 | // 1. AOP内的点击事件,在业务方点击事件handler触发之前,SDK内部push一个该view的event refer 54 | // 2. 业务方点击事件handler之后,执行SDK内置的埋点 55 | // 3. 如果是自定义事件的埋点,埋点代码需要放在业务handler取refer逻辑代码之前执行 56 | // 使用场景: 57 | // 1. 业务方的点击事件处理代码中,可直接取 event refer 58 | // 2. 业务方可以在业务模块内封装,这样可以对业务开发人员透明了 (典型场景: router层面) 59 | FOUNDATION_EXPORT id _Nullable NE_ET_lastestAutoEventRefer(void); // 默认是带 [sessid] 的refer格式【!!!如果需要持久化,则需要带上sessid】 60 | FOUNDATION_EXPORT id _Nullable NE_ET_lastestAutoEventNoSessidRefer(void); 61 | 62 | FOUNDATION_EXPORT id _Nullable NE_ET_lastestAutoEventReferForEvent(NSString *event); // 默认是带 [sessid] 的refer格式【!!!如果需要持久化,则需要带上sessid】 63 | FOUNDATION_EXPORT id _Nullable NE_ET_lastestAutoEventNoSessidReferForEvent(NSString *event); 64 | 65 | // 8. 获取 AOP点击事件的 event refer 66 | // 跟上面俩方法的区别: 只要是SDK内部AOP的点击事件,都会生成 67 | // 生成的 refer 不再包含VTree结构,而是纯正根据 view 层级来构建 68 | // SDK内AOP分为: 69 | // 1. UITableViewCell 的点击 70 | // 2. UICollectionViewCell 的点击 71 | // 3. UIControl target-action 形式的点击 72 | // 4. UIView tap gesture 形式的点击 73 | FOUNDATION_EXPORT id _Nullable NE_ET_lastestAutoClckEventViewTreeSPMRefer(void) DEPRECATED_MSG_ATTRIBUTE("已经废弃,请使用`NE_ET_lastestUndefinedXpathRefer(void)`"); 74 | FOUNDATION_EXPORT id _Nullable NE_ET_lastestUndefinedXpathRefer(void); 75 | 76 | // 9. !!! 废弃了 77 | FOUNDATION_EXPORT void NE_ET_pushAutoEventReferSubfix(UIView *view, NSString *event, NSString *subfix) DEPRECATED_MSG_ATTRIBUTE("已经废弃,调用该方法,将什么都不做"); 78 | 79 | #endif /* NEEventTracingReferFuncs_h */ 80 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Public/NEEventTracingReferObserver.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingReferObserver.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/11/8. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingVTree.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef NS_ENUM(NSInteger, NEETReferUpdateOption) { 14 | NEETReferUpdateOptionNone = 0, 15 | NEETReferUpdateOptionPsreferMute = 1 << 0L, 16 | }; 17 | 18 | @protocol NEEventTracingReferObserver 19 | 20 | @optional 21 | 22 | /// hsrefer 更新时,会调用该方法 23 | /// - Parameter hsrefer: hsrefer 字符串 24 | - (void)hsreferNeedsUpdatedTo:(NSString *)hsrefer; 25 | 26 | /// page 的pgrefer & psrefer 更新的时候,会调用该方法 27 | /// - Parameters: 28 | /// - pgrefer: pgrefer 29 | /// - psrefer: psrefer 30 | /// - node: 节点 31 | /// - VTree: 节点对应的 VTree 32 | - (void)pgreferNeedsUpdatedTo:(NSString *)pgrefer 33 | psrefer:(NSString *)psrefer 34 | node:(NEEventTracingVTreeNode *)node 35 | inVTree:(NEEventTracingVTree *)VTree; 36 | 37 | /// page 的pgrefer & psrefer 更新的时候,会调用该方法 38 | /// - Parameters: 39 | /// - pgrefer: pgrefer 40 | /// - psrefer: psrefer 41 | /// - node: 节点 42 | /// - VTree: 节点对应的 VTree 43 | /// - option: option,如果是 ETReferUpdateOptionPsreferMute 的话,监听者应该忽略 44 | - (void)pgreferNeedsUpdatedTo:(NSString *)pgrefer 45 | psrefer:(NSString *)psrefer 46 | node:(NEEventTracingVTreeNode *)node 47 | inVTree:(NEEventTracingVTree *)VTree 48 | option:(NEETReferUpdateOption)option; 49 | 50 | @end 51 | 52 | NS_ASSUME_NONNULL_END 53 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Public/NEEventTracingVTreeNodeExtraConfigProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingVTreeNodeExtraConfigProtocol.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/25. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | /// MARK: 针对 page 节点,一些额外的配置 13 | @protocol NEEventTracingVTreeNodeExtraConfigProtocol 14 | 15 | // 如果设置了oids列表,遍历结果中如果该节点未包含oids列表中的任何节点,则该节点置为invalid, 并且不可见 16 | // 该节点名下必须要包含oids中的一个才是valid,而且该节点名下也只能挂载oids列表的节点(自动逻辑挂载除外) 17 | // 实际场景: app处于主屏幕(main)的时候,如果当前有一个tab正在展示,则该main节点有效 18 | // 当处于别的二级页面的时候,main无效 19 | // 当从正在打开二级页面的时候,main有效,但是只有tab vc才能作为其子节点,二级页面此时就处于main的同级别节点 20 | - (NSArray *)ne_et_validForContainingSubNodeOids; 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Public/UIScrollView+EventTracingES.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIScrollView+EventTracingES.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/8/2. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | /// MARK: SDK内置了 _es 滑动事件,可以按需开启 13 | @interface UIScrollView (EventTracingES) 14 | 15 | // default: NO 16 | @property(nonatomic, assign, getter=ne_et_isESEventEnable, setter=ne_et_setESEventEnable:) BOOL ne_et_esEventEnable; 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Public/UIView+EventTracingNodeImpressObserver.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+EventTracingNodeImpressObserver.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/25. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | // 在节点(虚拟层节点不支持)层面来 observer impress/impressend 事件,业务侧可以针对这个时候做一些事情 13 | @class NEEventTracingVTree; 14 | @class NEEventTracingVTreeNode; 15 | @protocol NEEventTracingVTreeNodeImpressObserver 16 | @optional 17 | 18 | /*! 19 | 一个节点即将曝光的时候被调用 20 | 21 | @param view 节点对应的view 22 | @param event 曝光事件的key => _pv/_ev 23 | @param node 节点对象 24 | @param VTree 虚拟树 25 | */ 26 | - (void)view:(UIView *)view willImpressWithEvent:(NSString *)event node:(NEEventTracingVTreeNode *)node inVTree:(NEEventTracingVTree *)VTree; 27 | 28 | /*! 29 | @brief一个节点即曝光结束的时候被调用 30 | 在这个时机,可以完整获取各种refer,已经生成好 31 | 32 | @param view 节点对应的view 33 | @param event 曝光事件的key => _pv/_ev 34 | @param node 节点对象 35 | @param VTree 虚拟树 36 | */ 37 | - (void)view:(UIView *)view didImpressWithEvent:(NSString *)event node:(NEEventTracingVTreeNode *)node inVTree:(NEEventTracingVTree *)VTree; 38 | 39 | /*! 40 | 一个节点曝光曝光结束的时候被调用 41 | 42 | @param view 节点对应的view 43 | @param event 曝光事件的key => _pv/_ev 44 | @param duration 曝光时长, 单位 => ms 45 | @param node 节点对象 46 | @param VTree 虚拟树 47 | */ 48 | - (void)view:(UIView *)view didImpressendWithEvent:(NSString *)event duration:(NSTimeInterval)duration node:(NEEventTracingVTreeNode *)node inVTree:(NEEventTracingVTree *)VTree; 49 | @end 50 | 51 | @interface UIView (EventTracingVTreeObserver) 52 | @property(nonatomic, strong, readonly) NSArray> *ne_et_impressObservers; 53 | 54 | - (void)ne_et_addImpressObserver:(id)observer; 55 | - (void)ne_et_removeImpressObserver:(id)observer; 56 | - (void)ne_et_removeallImpressObservers; 57 | @end 58 | 59 | NS_ASSUME_NONNULL_END 60 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Public/UIView+EventTracingPipEvent.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+EventTracingPipEvent.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/7/22. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | /// MARK: 可以将一个非节点的 event pip 到另外一个节点上 13 | /// 前提条件: 当前view不是一个节点 && 目标view是一个节点 14 | @interface UIView (EventTracingPipEvent) 15 | 16 | @property(nonatomic, strong, readonly, nullable) NSDictionary *> *ne_et_pipedToMeEventViews; 17 | @property(nonatomic, strong, readonly, nullable) NSDictionary *ne_et_pipTargetEventViews; 18 | 19 | /// 指定 view 进行 pip 20 | - (void)ne_et_pipEventClickToView:(UIView *)view; 21 | - (void)ne_et_pipEvent:(NSString *)event toView:(UIView *)view; 22 | 23 | /// 针对 click 事件 pip 24 | /// 1. 向上查找最近的匹配oid的节点 25 | /// 2. 向上查找最近的(任意)节点 26 | - (void)ne_et_pipEventClickToAncestorNodeViewOid:(NSString *)oid; 27 | - (void)ne_et_pipEventClickToAncestorNodeView; 28 | 29 | /// 指定 event 事件 pip 30 | /// 1. 向上查找最近的匹配oid的节点 31 | /// 2. 向上查找最近的(任意)节点 32 | - (void)ne_et_pipEvent:(NSString *)event toAncestorNodeViewOid:(NSString *)oid; 33 | - (void)ne_et_pipEventToAncestorNodeView:(NSString *)event; 34 | 35 | /// 取消到 目标view 的 pipEvent 操作 36 | - (void)ne_et_cancelPipEvent; 37 | 38 | @end 39 | 40 | NS_ASSUME_NONNULL_END 41 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Refer/NEEventTracingEventRefer.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventRefer.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2022/2/23. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | typedef NS_ENUM(NSInteger, NEEventTracingEventReferType) { 13 | NEEventTracingEventReferTypeFormatted, // 标准`格式化` 的refer 14 | NEEventTracingEventReferTypeUndefinedXpath // undefined-xpath 形式的 refer 15 | }; 16 | 17 | @protocol NEEventTracingEventRefer 18 | 19 | @property(nonatomic, copy, readonly) NSString *event; 20 | @property(nonatomic, assign, readonly) NSTimeInterval eventTime; 21 | @property(nonatomic, copy, readonly) NSString *refer; 22 | 23 | @property(nonatomic, assign, readonly) NEEventTracingEventReferType referType; 24 | 25 | @end 26 | 27 | NS_ASSUME_NONNULL_END 28 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Refer/NEEventTracingFormattedRefer.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingFormattedRefer.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2022/2/22. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | typedef NS_OPTIONS(NSUInteger, NEEventTracingFormattedReferComponentOptions) { 13 | NEEventTracingFormattedReferComponentUnknown = 0, 14 | 15 | /// MARK: 第 [0-10) 位,是用来保留的,作为存在真实 component 的位 16 | NEEventTracingFormattedReferComponentSessid = 1 << 0, // => _dkey: sessid 17 | NEEventTracingFormattedReferComponentType = 1 << 1, // => _dkey: type 18 | NEEventTracingFormattedReferComponentActseq = 1 << 2, // => _dkey: actseq 19 | NEEventTracingFormattedReferComponentPgstep = 1 << 3, // => _dkey: pgstep 20 | NEEventTracingFormattedReferComponentSPM = 1 << 4, // => _dkey: spm 21 | NEEventTracingFormattedReferComponentSCM = 1 << 5, // => _dkey: scm 22 | 23 | /// MARK: 第 [11-~) 位,用来做 `标记位` 使用 24 | NEEventTracingFormattedReferComponentFlagER = 1 << 10, // => _dkey: er 25 | NEEventTracingFormattedReferComponentFlagUndefinedXpath = 1 << 11, // => _dkey: undefined-xpath 26 | NEEventTracingFormattedReferComponentFlagH5 = 1 << 12 // => _dkey: h5 27 | }; 28 | 29 | /// MARK: 格式如下 30 | // [_dkey:er|undefined-path|sessid|type|actseq|pgstep|spm|scm][F:${option}][sessid][e/p][_actseq][_pgstep][spm][scm] 31 | // 其中 _dkey 应该配置成金测试包下存在 32 | /// MARK: 从右向左,1-10位,属于 component, 会以 `[$param]` 的形式存在 33 | /// MARK: 超过10位,仅仅属于标记位,会在 _dkey & F:${option} 中体现出来 34 | // sessid, type, actseq, pgstep, spm, scm => 分别是 1-6位 35 | // er, undefinex-xpath, h5 => 分别是 11-13 位 36 | @protocol NEEventTracingFormattedRefer 37 | 38 | /// MARK: refer的value值,字符串 39 | @property(nonatomic, copy, readonly) NSString *value; 40 | @property(nonatomic, copy, readonly, nullable) NSString *dkey; 41 | @property(nonatomic, assign, readonly) NEEventTracingFormattedReferComponentOptions options; 42 | 43 | /// MARK: 第 [0-10) 位,是用来保留的,作为存在真实 component 的位 44 | @property(nonatomic, copy, readonly) NSString *sessid; 45 | @property(nonatomic, copy, readonly) NSString *type; 46 | @property(nonatomic, assign, readonly) NSInteger actseq; 47 | @property(nonatomic, assign, readonly) NSInteger pgstep; 48 | @property(nonatomic, copy, readonly, nullable) NSString *spm; 49 | @property(nonatomic, copy, readonly, nullable) NSString *scm; 50 | 51 | /// MARK: 第 [11-~) 位,用来做 `标记位` 使用 52 | // scm是否涉及加密 53 | @property(nonatomic, assign, readonly, getter=isER) BOOL er; 54 | // 是否被标记位 undefined-xpath 55 | @property(nonatomic, assign, readonly, getter=isUndefinedXpath) BOOL undefinedXpath; 56 | // 是否来自于 h5 57 | @property(nonatomic, assign, readonly, getter=isH5) BOOL h5; 58 | 59 | /// MARK: 单独 开启/关闭 sessid 60 | - (NSString *)valueWithSessid:(BOOL)withSessid undefinedXpath:(BOOL)undefinedXpath; 61 | 62 | @end 63 | 64 | /// MARK: 从一个字符串,可以反向生成 refer 对象 65 | /// MARK: 对字符串refer做解析 66 | FOUNDATION_EXPORT id _Nullable NE_ET_FormattedReferParseFromReferString(NSString *referString); 67 | FOUNDATION_EXPORT id _Nullable NE_ET_FormattedReferParseFromReferStringWithError(NSString *referString, NSError ** _Nullable error); 68 | 69 | NS_ASSUME_NONNULL_END 70 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Refer/Private/NEEventTracingEventRefer+Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventRefer+Private.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2022/2/23. 6 | // 7 | 8 | #import "NEEventTracingEventRefer.h" 9 | #import "NEEventTracingFormattedRefer.h" 10 | #import "NEEventTracingVTreeNode.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | /// MARK: 非公开的几个内部方法 15 | FOUNDATION_EXPORT 16 | id NE_ET_formattedReferForNode(NEEventTracingVTreeNode *node, BOOL useNextActseq); 17 | 18 | 19 | @class NEEventTracingFormattedEventRefer; 20 | @interface NEEventTracingEventRefer : NSObject 21 | 22 | @property(nonatomic, copy, readwrite) NSString *event; 23 | @property(nonatomic, assign, readwrite) NSTimeInterval eventTime; 24 | 25 | @end 26 | 27 | /// MARK: 1.1 rootpage 名下,或者app全局级别 生成的refer 28 | /// MARK: 1.2 rootpage 曝光对应的refer 29 | @interface NEEventTracingFormattedEventRefer : NEEventTracingEventRefer 30 | 31 | @property(nonatomic, assign) BOOL shouldStartHsrefer; 32 | 33 | @property(nonatomic, assign, readonly, getter=isRootPagePV) BOOL rootPagePV; // 是否是 root page PV 34 | @property(nonatomic, weak, nullable) NEEventTracingFormattedEventRefer *parentRefer; // 普通的refer可能存在 parentRefer(rootPagePV == YES) 35 | @property(nonatomic, strong, readonly) NSArray *subRefers; // 当 rootPagePV == YES时,subRefers可能有多个 36 | @property(nonatomic, assign) NSInteger appEnterBackgroundSeq; 37 | 38 | @property(nonatomic, strong) id formattedRefer; 39 | 40 | @property(nonatomic, assign) BOOL psreferMute; //psrefer 静默 41 | 42 | +(instancetype)referWithEvent:(NSString *)event 43 | formattedRefer:(id)formattedRefer 44 | rootPagePV:(BOOL)rootPagePV 45 | shouldStartHsrefer:(BOOL)shouldStartHsrefer 46 | isNodePsreferMuted:(BOOL)isNodePsreferMuted; 47 | 48 | - (void)addSubRefer:(NEEventTracingFormattedEventRefer *)refer; 49 | 50 | @end 51 | 52 | /// MARK: 2. undefined-xpath refer 53 | // 一个 undefined-xpath 可能会关联一个 formetted refer,如果关联不上,则可认为 54 | @interface NEEventTracingUndefinedXpathEventRefer : NEEventTracingEventRefer 55 | 56 | +(instancetype)referWithEvent:(NSString *)event 57 | undefinedXpathRefer:(NSString *)undefinedXpathRefer; 58 | 59 | @end 60 | 61 | /// MARK: 便捷工具方法 62 | @interface NEEventTracingFormattedEventRefer (Util) 63 | + (instancetype)becomeActiveRefer; 64 | + (instancetype)enterForegroundRefer; 65 | @end 66 | 67 | /// MARK: 对外临时封装,对应的refer中可能不包含sessid,业务侧获取 event refer 的时候,需要带上 68 | @interface NEEventTracingFormattedWithSessidUndefinedXpathEventRefer : NEEventTracingEventRefer 69 | 70 | +(instancetype)referFromFormattedEventRefer:(NEEventTracingFormattedEventRefer *)formattedEventRefer 71 | withSessid:(BOOL)withSessid 72 | undefinedXpath:(BOOL)undefinedXPath; 73 | 74 | @end 75 | 76 | NS_ASSUME_NONNULL_END 77 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Refer/Private/NEEventTracingEventReferCollector.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventReferCollector.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/8. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingVTree.h" 10 | #import "NEEventTracingVTreeNode.h" 11 | #import "NEEventTracingEventAction.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface NEEventTracingEventReferCollector : NSObject 16 | 17 | - (void)appWillEnterForeground; 18 | 19 | - (void)willImpressNode:(NEEventTracingVTreeNode *)node inVTree:(NEEventTracingVTree *)VTree; 20 | 21 | @end 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Refer/Private/NEEventTracingEventReferQueue+Query.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventReferQueue+Query.h 3 | // NEEventTracing 4 | // 5 | // Created by 熊勋泉 on 2023/2/22. 6 | // 7 | 8 | #import "NEEventTracingEventReferQueue.h" 9 | #import "NEEventTracingEventRefer+Private.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingEventReferQueryParams : NSObject 14 | 15 | /// 站在 refer 消费侧,关心的 refer 类型有哪些 16 | @property (nonatomic, assign) NEEventTracingPageReferConsumeOption referConsumeOption; 17 | 18 | /// 针对获取事件 refer 场景,可以指定事件来获取refer 19 | @property (nonatomic, copy, nullable) NSString *event; 20 | 21 | /// 对于 `subpage_pv` 场景,refer的生成和消费,是需要限定在一个 rootPage 曝光周期内的 22 | @property (nonatomic, strong, nullable) NEEventTracingVTreeNode *rootPageNode; 23 | 24 | - (instancetype)init NS_UNAVAILABLE; 25 | + (instancetype)new NS_UNAVAILABLE; 26 | 27 | @end 28 | 29 | @interface NEEventTracingEventReferQueryResult : NSObject 30 | 31 | @property(nonatomic, assign, readonly, getter=isValid) BOOL valid; //如果发生降级,则为 false,否则为 true 32 | @property(nonatomic, strong, readonly, nullable) id refer; // psrefer 33 | 34 | /// 在 refer 查找过程中,以下refer可能都获取,从而得出最终该使用的refer 35 | @property(nonatomic, strong, readonly, nullable) NEEventTracingFormattedEventRefer * latestRootPageRefer; 36 | @property(nonatomic, strong, readonly, nullable) NEEventTracingFormattedEventRefer * latestSubPageRefer; 37 | @property(nonatomic, strong, readonly, nullable) NEEventTracingFormattedEventRefer * latestEventRefer; 38 | 39 | @property(nonatomic, strong, readonly, nullable) id latestUndefinedXpathRefer; 40 | 41 | - (instancetype)init NS_UNAVAILABLE; 42 | + (instancetype)new NS_UNAVAILABLE; 43 | @end 44 | 45 | 46 | typedef void(^NEEventTracingReferQueryBuilder)(NEEventTracingEventReferQueryParams *params); 47 | 48 | /// MARK: AOP pre 时机,将 event refer 放入队列,供业务方在 event handler 内部即可获取refer 49 | /// MARK: 内部会 actseq 做 `预+1` 操作 50 | @interface NEEventTracingEventReferQueue (Query) 51 | 52 | - (NEEventTracingEventReferQueryResult *)queryWithBuilder:(NEEventTracingReferQueryBuilder NS_NOESCAPE)block; 53 | 54 | @end 55 | 56 | NS_ASSUME_NONNULL_END 57 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Refer/Private/NEEventTracingEventReferQueue.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventReferQueue.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/1. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingEventRefer+Private.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingEventReferQueue : NSObject 14 | 15 | @property(nonatomic, strong, readonly) NSArray *allRefers; 16 | 17 | + (instancetype)queue; 18 | 19 | - (void)pushEventRefer:(NEEventTracingFormattedEventRefer *)refer; 20 | - (void)pushEventRefer:(NEEventTracingFormattedEventRefer *)refer 21 | node:(NEEventTracingVTreeNode * _Nullable)node 22 | isSubPage:(BOOL)isSubPage; 23 | - (void)removeEventRefer:(NEEventTracingFormattedEventRefer *)refer; 24 | - (void)clear; 25 | 26 | @end 27 | 28 | /// MARK: AOP pre 时机,将 event refer 放入队列,供业务方在 event handler 内部即可获取refer 29 | /// MARK: 内部会 actseq 做 `预+1` 操作 30 | @interface NEEventTracingEventReferQueue (EventRefer) 31 | 32 | - (BOOL)pushEventReferForEvent:(NSString *)event 33 | view:(UIView *)view 34 | node:(NEEventTracingVTreeNode * _Nullable)node 35 | useForRefer:(BOOL)useForRefer 36 | useNextActseq:(BOOL)useNextActseq; 37 | 38 | - (void)rootPageNodeDidImpress:(NEEventTracingVTreeNode * _Nullable)node 39 | inVTree:(NEEventTracingVTree * _Nullable)VTree; 40 | 41 | - (void)subPageNodeDidImpress:(NEEventTracingVTreeNode * _Nullable)node 42 | inVTree:(NEEventTracingVTree * _Nullable)VTree; 43 | 44 | - (NEEventTracingFormattedEventRefer *)fetchLastestRootPagePVRefer; 45 | 46 | @end 47 | 48 | /// MARK: AOP场景,基于原始 View 而生产的 `SPM Refer` 49 | /// MARK: 目前仅针对各种 click 场景 50 | @interface NEEventTracingEventReferQueue (UndefinedXpathEventRefer) 51 | - (void)undefinedXpath_pushEventReferForEvent:(NSString *)event view:(UIView *)view; 52 | - (NEEventTracingUndefinedXpathEventRefer * _Nullable)undefinedXpath_fetchLastestEventRefer; 53 | - (NEEventTracingUndefinedXpathEventRefer * _Nullable)undefinedXpath_fetchLastestEventReferForEvent:(NSString *)event; 54 | @end 55 | 56 | /// MARK: hsrefer 57 | @interface NEEventTracingEventReferQueue (Hsrefer) 58 | - (NSString * _Nullable)hsrefer; 59 | - (void)hsreferNeedsUpdateTo:(NSString *)hsrefer; 60 | @end 61 | 62 | NS_ASSUME_NONNULL_END 63 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Refer/Private/NEEventTracingFormattedReferBuilder.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingFormattedReferBuilder.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2022/2/23. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingFormattedRefer.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @protocol NEEventTracingFormattedReferComponentBuilder 14 | 15 | /// MARK: component s 16 | @property(nonatomic, readonly) id (^withSesid)(void); 17 | 18 | @property(nonatomic, readonly) id (^type)(NSString *value); 19 | @property(nonatomic, readonly) id (^typeE)(void); 20 | @property(nonatomic, readonly) id (^typeP)(void); 21 | 22 | @property(nonatomic, readonly) id (^actseq)(NSInteger value); 23 | @property(nonatomic, readonly) id (^pgstep)(NSInteger value); 24 | @property(nonatomic, readonly) id (^spm)(NSString *value); 25 | @property(nonatomic, readonly) id (^scm)(NSString *value); 26 | 27 | /// MARK: mark s 28 | @property(nonatomic, readonly) id (^undefinedXpath)(void); 29 | @property(nonatomic, readonly) id (^er)(void); 30 | @property(nonatomic, readonly) id (^h5)(void); 31 | 32 | @end 33 | 34 | @interface NEEventTracingFormattedReferBuilder : NSObject 35 | 36 | + (NEEventTracingFormattedReferBuilder *)build:(void(^)(id builder))block; 37 | - (id)generateRefer; 38 | 39 | @end 40 | 41 | NS_ASSUME_NONNULL_END 42 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Throttle/NEEventTracingTraversalRunnerDurationThrottle.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingTraversalRunnerDurationThrottle.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/2. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingTraversalRunnerThrottle.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingTraversalRunnerDurationThrottle : NSObject 14 | 15 | // 最小需要多长时间才放行 16 | // 默认 0.1s 17 | @property(nonatomic, assign) NSTimeInterval tolerentDuration; 18 | 19 | @end 20 | 21 | NS_ASSUME_NONNULL_END 22 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Throttle/NEEventTracingTraversalRunnerDurationThrottle.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingTraversalRunnerDurationThrottle.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/2. 6 | // 7 | 8 | #import "NEEventTracingTraversalRunnerDurationThrottle.h" 9 | 10 | @interface NEEventTracingTraversalRunnerDurationThrottle () { 11 | BOOL _throttled; 12 | __weak id _callback; 13 | 14 | NSTimeInterval _preTime; 15 | } 16 | @end 17 | 18 | @implementation NEEventTracingTraversalRunnerDurationThrottle 19 | @synthesize throttled = _throttled; 20 | @synthesize paused = _paused; 21 | @synthesize callback = _callback; 22 | 23 | - (instancetype)init { 24 | self = [super init]; 25 | if (self) { 26 | _tolerentDuration = .1f; 27 | 28 | [self reset]; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)reset { 34 | _preTime = [NSDate date].timeIntervalSince1970; 35 | _throttled = NO; 36 | _paused = NO; 37 | 38 | [NSObject cancelPreviousPerformRequestsWithTarget:self]; 39 | } 40 | 41 | - (void)pause { 42 | _paused = YES; 43 | } 44 | 45 | - (void)pushValue:(id _Nullable)value { 46 | if (_paused) { 47 | return; 48 | } 49 | 50 | [NSObject cancelPreviousPerformRequestsWithTarget:self]; 51 | 52 | NSTimeInterval now = [NSDate date].timeIntervalSince1970; 53 | 54 | if (_preTime >= now) { 55 | _preTime = now; 56 | } 57 | 58 | if (now - self.tolerentDuration >= _preTime) { 59 | [self _finishThrottled]; 60 | } else { 61 | NSTimeInterval diff = self.tolerentDuration - (now - _preTime); 62 | _throttled = YES; 63 | 64 | [self performSelector:@selector(_finishThrottled) withObject:nil afterDelay:diff]; 65 | } 66 | } 67 | 68 | - (void)_finishThrottled { 69 | _preTime = [NSDate date].timeIntervalSince1970; 70 | _throttled = NO; 71 | 72 | if ([self.callback respondsToSelector:@selector(throttle:throttleDidFinished:)]) { 73 | [self.callback throttle:self throttleDidFinished:_throttled]; 74 | } 75 | } 76 | 77 | - (NSString *)name { 78 | return @"Throttle.Duration"; 79 | } 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Throttle/NEEventTracingTraversalRunnerScrollViewOffsetThrottle.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingTraversalRunnerScrollViewOffsetThrottle.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/2. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingTraversalRunnerThrottle.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | /// MARK: 被添加后,仅仅对 UIScrollView 的滚动场景做限流 14 | @interface NEEventTracingTraversalRunnerScrollViewOffsetThrottle : NSObject 15 | 16 | // 最小要 X/Y 轴移动超过阈值,才放行 17 | // 默认是 {5.f, 5.f} 18 | @property(nonatomic, assign) CGPoint tolerentOffset; 19 | 20 | @end 21 | 22 | NS_ASSUME_NONNULL_END 23 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Throttle/NEEventTracingTraversalRunnerScrollViewOffsetThrottle.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingTraversalRunnerScrollViewOffsetThrottle.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/2. 6 | // 7 | 8 | #import "NEEventTracingTraversalRunnerScrollViewOffsetThrottle.h" 9 | 10 | @interface NEEventTracingTraversalRunnerScrollViewOffsetThrottle () { 11 | BOOL _throttled; 12 | __weak id _callback; 13 | CGPoint _preContentOffset; 14 | } 15 | 16 | @end 17 | 18 | @implementation NEEventTracingTraversalRunnerScrollViewOffsetThrottle 19 | @synthesize throttled = _throttled; 20 | @synthesize paused = _paused; 21 | @synthesize callback = _callback; 22 | 23 | - (instancetype)init { 24 | self = [super init]; 25 | if (self) { 26 | _tolerentOffset = CGPointMake(5.f, 5.f); 27 | 28 | [self reset]; 29 | } 30 | return self; 31 | } 32 | 33 | - (void)reset { 34 | _throttled = NO; 35 | _preContentOffset = CGPointZero; 36 | _paused = NO; 37 | } 38 | 39 | - (void)pause { 40 | _paused = YES; 41 | } 42 | 43 | - (void)pushValue:(id _Nullable)value { 44 | if (_paused) { 45 | return; 46 | } 47 | 48 | if (![value isKindOfClass:NSValue.class] 49 | || CGPointEqualToPoint([value CGPointValue], CGPointZero)) { 50 | 51 | if (_throttled) { 52 | [self reset]; 53 | } 54 | 55 | return; 56 | } 57 | 58 | CGPoint offset = [value CGPointValue]; 59 | CGPoint preOffset = _preContentOffset; 60 | 61 | if (CGPointEqualToPoint(CGPointZero, preOffset)) { 62 | _preContentOffset = offset; 63 | 64 | return; 65 | } 66 | 67 | if (fabs(preOffset.x - offset.x) > fabs(_tolerentOffset.x) 68 | || fabs(preOffset.y - offset.y) > fabs(_tolerentOffset.y)) { 69 | 70 | _preContentOffset = offset; 71 | [self _finishThrottled]; 72 | } 73 | } 74 | 75 | - (void)_finishThrottled { 76 | _throttled = NO; 77 | 78 | if ([self.callback respondsToSelector:@selector(throttle:throttleDidFinished:)]) { 79 | [self.callback throttle:self throttleDidFinished:_throttled]; 80 | } 81 | } 82 | 83 | - (NSString *)name { 84 | return @"Throttle.ContentOffset"; 85 | } 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Throttle/NEEventTracingTraversalRunnerThrottle.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingTraversalRunnerThrottle.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/2. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @protocol NEEventTracingTraversalRunnerThrottle; 13 | @protocol NEEventTracingTraversalRunnerThrottleCallback 14 | - (void)throttle:(id)throttle throttleDidFinished:(BOOL)throttled; 15 | @end 16 | 17 | @protocol NEEventTracingTraversalRunnerThrottle 18 | 19 | @property(nonatomic, copy, readonly) NSString *name; 20 | // 标识当前正在处于 被限流状态 21 | @property(nonatomic, assign, readonly, getter=isThrottled) BOOL throttled; 22 | @property(nonatomic, assign, readonly, getter=isPaused) BOOL paused; 23 | @property(nonatomic, weak, nullable) id callback; 24 | 25 | - (void)pushValue:(id _Nullable)value; 26 | - (void)reset; 27 | - (void)pause; 28 | 29 | @end 30 | 31 | NS_ASSUME_NONNULL_END 32 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Traverser/NEEventTracingEventAction.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventAction.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/8. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingVTree.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NEEventTracingEventAction : NSObject 14 | 15 | @property(nonatomic, assign) BOOL increaseActseq; 16 | @property(nonatomic, assign) BOOL useForRefer; 17 | 18 | @property(nonatomic, copy, nullable) NSDictionary *params; 19 | @property(nonatomic, copy, nullable) NSDictionary *contextParams; 20 | 21 | @property(nonatomic, copy) NSString *event; 22 | @property(nonatomic, weak) UIView *view; 23 | 24 | @property(nonatomic, strong) NEEventTracingVTreeNode *node; 25 | @property(nonatomic, strong) NEEventTracingVTree *VTree; 26 | 27 | + (instancetype)actionWithEvent:(NSString *)event view:(UIView *)view; 28 | - (void)syncFromActionConfig:(NEEventTracingEventActionConfig *)config; 29 | 30 | - (void)setupNode:(NEEventTracingVTreeNode *)node VTree:(NEEventTracingVTree *)VTree; 31 | 32 | @end 33 | 34 | NS_ASSUME_NONNULL_END 35 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Traverser/NEEventTracingEventAction.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventAction.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/4/8. 6 | // 7 | 8 | #import "NEEventTracingEventAction.h" 9 | 10 | @implementation NEEventTracingEventAction 11 | 12 | + (instancetype) actionWithEvent:(NSString *)event view:(UIView *)view { 13 | NEEventTracingEventAction *action = [[NEEventTracingEventAction alloc] init]; 14 | action.event = event; 15 | action.view = view; 16 | return action; 17 | } 18 | 19 | - (void)syncFromActionConfig:(NEEventTracingEventActionConfig *)config { 20 | self.increaseActseq = config.increaseActseq; 21 | self.useForRefer = config.useForRefer; 22 | } 23 | 24 | - (void)setupNode:(NEEventTracingVTreeNode *)node VTree:(NEEventTracingVTree *)VTree { 25 | self.node = node; 26 | self.VTree = VTree; 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Traverser/NEEventTracingEventEmitter.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingEventEmitter.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/3/16. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingContext.h" 10 | #import "NEEventTracingVTree.h" 11 | #import "NEEventTracingEventReferCollector.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @class NEEventTracingEventEmitter; 16 | @protocol NEEventTracingEventEmitterDelegate 17 | 18 | - (void)eventEmitter:(NEEventTracingEventEmitter *)eventEmitter 19 | emitEvent:(NSString *)event 20 | contextParams:(NSDictionary * _Nullable)contextParams 21 | logActionParams:(NSDictionary * _Nullable)logActionParams 22 | node:(NEEventTracingVTreeNode * _Nullable)node 23 | inVTree:(NEEventTracingVTree * _Nullable)VTree; 24 | 25 | @end 26 | 27 | @interface NEEventTracingEventEmitter : NSObject 28 | 29 | @property(nonatomic, weak, nullable) id delegate; 30 | @property(nonatomic, strong, readonly, nullable) NEEventTracingVTree *lastVTree; 31 | @property(nonatomic, strong, readonly, nullable) NSArray> *allVTreeObservers; 32 | @property(nonatomic, weak, nullable) id VTreePerformanceObserver; 33 | @property(nonatomic, strong) NEEventTracingEventReferCollector *referCollector; 34 | 35 | - (void)consumeVTree:(NEEventTracingVTree *)VTree; 36 | - (void)flush; 37 | 38 | // 下面俩方法,仅仅在主线程中调用 39 | - (void)consumeEventAction:(NEEventTracingEventAction *)action; 40 | 41 | /// MARK: 目前仅仅针对 UIAlertController 场景使用 42 | - (void)consumeEventAction:(NEEventTracingEventAction *)action forceInCurrentVTree:(BOOL)forceInCurrentVTree; 43 | 44 | @end 45 | 46 | NS_ASSUME_NONNULL_END 47 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Traverser/NEEventTracingTraversalRunner.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingTraversalRunner.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/4. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @class NEEventTracingTraversalRunner; 13 | @protocol NEEventTracingTraversalRunnerDelegate 14 | - (void) traversalRunner:(NEEventTracingTraversalRunner *)runner runWithRunModeMatched:(BOOL)runModeMatched; 15 | @end 16 | 17 | __attribute__((objc_direct_members)) 18 | @interface NEEventTracingTraversalRunner : NSObject 19 | 20 | @property(nonatomic, assign, readonly) BOOL running; 21 | @property(nonatomic, assign, readonly) BOOL paused; 22 | 23 | @property(nonatomic, weak, nullable) id delegate; 24 | @property(nonatomic, copy, readonly) NSRunLoopMode currentRunMode; 25 | 26 | - (void) run; 27 | - (void) runWithRunloopMode:(NSRunLoopMode)runloopMode; 28 | - (void) stop; 29 | 30 | - (void) pause; 31 | - (void) resume; 32 | 33 | @end 34 | 35 | NS_ASSUME_NONNULL_END 36 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Traverser/NEEventTracingTraverser.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingTraverser.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/2/4. 6 | // 7 | 8 | #import 9 | #import "NEEventTracingVTree.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | FOUNDATION_EXPORT BOOL NE_ET_isPage(UIView *view); 14 | FOUNDATION_EXPORT BOOL NE_ET_isElement(UIView *view); 15 | FOUNDATION_EXPORT BOOL NE_ET_isPageOrElement(UIView *view); 16 | FOUNDATION_EXPORT NSArray * NE_ET_subViews(UIView *view); 17 | FOUNDATION_EXPORT UIView * _Nullable NE_ET_superView(UIView *view); 18 | FOUNDATION_EXPORT BOOL NE_ET_isIgnoreRefer(UIView *view); 19 | FOUNDATION_EXPORT BOOL NE_ET_isHasSubNodes(UIView *view); // MARK: 使用原始 view 树来判断是否 子view 中有节点对象 20 | FOUNDATION_EXPORT CGRect NE_ET_viewVisibleRectOnSelf(UIView *view); 21 | FOUNDATION_EXPORT CGRect NE_ET_calculateVisibleRect(UIView *view, CGRect visibleRectOnView, CGRect containerVisibleRect); 22 | FOUNDATION_EXPORT BOOL NE_ET_checkIfExistsLogicalMountEndlessLoopAtView(UIView *view, UIView *viewToMount); 23 | FOUNDATION_EXPORT NSString * _Nullable NE_ET_undefinedXpathReferForView(UIView *view); 24 | FOUNDATION_EXPORT BOOL NE_ET_checkIfExistsAncestorViewControllerTransitioning(UIView *view); 25 | 26 | @interface NEEventTracingTraverser : NSObject 27 | 28 | - (void)cleanAssociationForPreVTree:(NEEventTracingVTree *)VTree; 29 | - (void)associateNodeToViewForVTree:(NEEventTracingVTree *)VTree; 30 | 31 | - (NEEventTracingVTree *)totalGenerateVTreeFromWindows; 32 | - (NEEventTracingVTree *)incrementalGenerateVTreeFrom:(NEEventTracingVTree * _Nullable)VTree 33 | views:(NSArray * _Nullable)views; 34 | 35 | @end 36 | 37 | NS_ASSUME_NONNULL_END 38 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Utils/NSArray+ETEnumerator.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+ETEnumerator.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/3/18. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | typedef NS_ENUM(NSUInteger, NEEventTracingEnumeratorType) { 13 | NEEventTracingEnumeratorTypeDFS, // 深度优先遍历 14 | NEEventTracingEnumeratorTypeDFSRight, // 深度优先遍历, 优先遍历右节点 15 | NEEventTracingEnumeratorTypeBFS, // 广度优先遍历 16 | NEEventTracingEnumeratorTypeBFSRight // 广度优先遍历, 优先遍历右节点 17 | }; 18 | 19 | @interface NSArray<__covariant ObjectType> (ETEnumerator) 20 | 21 | - (void)ne_et_enumerateObjectsUsingBlock:(NSArray* (NS_NOESCAPE ^)(ObjectType obj, BOOL *stop))block; 22 | 23 | - (void)ne_et_enumerateObjectsWithType:(NEEventTracingEnumeratorType)type 24 | usingBlock:(NSArray* (NS_NOESCAPE ^)(ObjectType obj, BOOL *stop))block; 25 | 26 | @end 27 | 28 | NS_ASSUME_NONNULL_END 29 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Utils/NSArray+ETEnumerator.mm: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+ETEnumerator.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/3/18. 6 | // 7 | 8 | #import "NSArray+ETEnumerator.h" 9 | #include 10 | #include 11 | 12 | @implementation NSArray (ETEnumerator) 13 | 14 | - (void)ne_et_enumerateObjectsUsingBlock:(NSArray * _Nonnull (NS_NOESCAPE ^)(id _Nonnull obj, BOOL * _Nonnull stop))block { 15 | [self ne_et_enumerateObjectsWithType:NEEventTracingEnumeratorTypeBFS usingBlock:block]; 16 | } 17 | 18 | - (void)ne_et_enumerateObjectsWithType:(NEEventTracingEnumeratorType)type usingBlock:(NSArray * _Nonnull (NS_NOESCAPE ^)(id _Nonnull obj, BOOL * _Nonnull stop))block { 19 | if (!block) { 20 | return; 21 | } 22 | 23 | if (type == NEEventTracingEnumeratorTypeBFS) { 24 | [self _et_enumerateObjectsBFSUsingBlock:block]; 25 | } else if (type == NEEventTracingEnumeratorTypeBFSRight) { 26 | [self _et_enumerateObjectsBFSWithReverse:YES usingBlock:block]; 27 | } else if (type == NEEventTracingEnumeratorTypeDFS) { 28 | [self _et_enumerateObjectsDFSUsingBlock:block]; 29 | } else if (type == NEEventTracingEnumeratorTypeDFSRight) { 30 | [self _et_enumerateObjectsDFSWithReverse:YES UsingBlock:block]; 31 | } 32 | } 33 | 34 | - (void) _et_enumerateObjectsBFSUsingBlock:(NSArray * _Nonnull (^)(id _Nonnull obj, BOOL * _Nonnull stop))block { 35 | [self _et_enumerateObjectsBFSWithReverse:NO usingBlock:block]; 36 | } 37 | 38 | - (void) _et_enumerateObjectsBFSWithReverse:(BOOL)reverse usingBlock:(NSArray * _Nonnull (^)(id _Nonnull obj, BOOL * _Nonnull stop))block { 39 | __block std::vector vector; 40 | 41 | void(^pushVectorObjects)(NSArray *) = ^(NSArray *objects){ 42 | [objects enumerateObjectsWithOptions:(reverse ? NSEnumerationReverse : 0) usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 43 | vector.insert(vector.begin(), obj); 44 | }]; 45 | }; 46 | pushVectorObjects(self); 47 | 48 | __block BOOL stop = NO; 49 | while (!vector.empty() && !stop) { 50 | id obj = vector.back(); 51 | 52 | NSArray *result = block(obj, &stop); 53 | 54 | vector.pop_back(); 55 | 56 | pushVectorObjects(result); 57 | } 58 | } 59 | 60 | - (void) _et_enumerateObjectsDFSUsingBlock:(NSArray * _Nonnull (^)(id _Nonnull obj, BOOL * _Nonnull stop))block { 61 | [self _et_enumerateObjectsDFSWithReverse:NO UsingBlock:block]; 62 | } 63 | 64 | - (void) _et_enumerateObjectsDFSWithReverse:(BOOL)reverse UsingBlock:(NSArray * _Nonnull (^)(id _Nonnull obj, BOOL * _Nonnull stop))block { 65 | __block std::stack stack; 66 | 67 | void(^pushStackObjects)(NSArray *) = ^(NSArray *objects){ 68 | [objects enumerateObjectsWithOptions:(reverse ? 0 : NSEnumerationReverse) usingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 69 | stack.push(obj); 70 | }]; 71 | }; 72 | 73 | pushStackObjects(self); 74 | 75 | __block BOOL stop = NO; 76 | while (!stack.empty() && !stop) { 77 | id obj = stack.top(); 78 | 79 | NSArray *result = block(obj, &stop); 80 | 81 | stack.pop(); 82 | 83 | pushStackObjects(result); 84 | } 85 | } 86 | 87 | @end 88 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Utils/Private/NEEventTracingConstData.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingConstData.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/5/20. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | #ifndef NEEventTracingConstData_H 13 | #define NEEventTracingConstData_H 14 | 15 | #define kETConstKeyTypeEvent "EVENT" 16 | #define kETConstKeyTypeRefer "REFER" 17 | #define kETConstKeyTypeSpecParamKey "SPEC_PARAM_KEY" 18 | #define kETConstKeyTypeNodeValidation "NODE_VALIDATION" 19 | 20 | #define ETConstDataSecName "ETConstData" 21 | #define ETConstKeyValueSecDATA(sectname) __attribute((used, section("__DATA," sectname))) 22 | 23 | #define ETConstKeyValue(TYPE, key, value) \ 24 | static char * _ETConst_ ## key ## _Private_ ETConstKeyValueSecDATA(ETConstDataSecName) = TYPE "/"#key"/" value; 25 | 26 | #endif 27 | 28 | @interface NEEventTracingConstData : NSObject 29 | 30 | @property(nonatomic, copy, readonly) NSArray *allConstKeys; 31 | 32 | + (instancetype)sharedInstance; 33 | - (NSArray *)constKeysForType:(NSString *)type; 34 | 35 | @end 36 | 37 | NS_ASSUME_NONNULL_END 38 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Utils/Private/NEEventTracingConstData.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingConstData.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/5/20. 6 | // 7 | 8 | #import "NEEventTracingConstData.h" 9 | #include 10 | #include 11 | 12 | #ifdef __LP64__ 13 | typedef struct mach_header_64 * mach_header_ptr_t; 14 | #else 15 | typedef struct mach_header * mach_header_ptr_t; 16 | #endif 17 | 18 | @interface NEEventTracingConstData() 19 | @property(nonatomic, strong) NSDictionary *> *constData; 20 | @end 21 | 22 | @implementation NEEventTracingConstData 23 | 24 | + (instancetype)sharedInstance { 25 | static NEEventTracingConstData *instance = nil; 26 | static dispatch_once_t onceToken; 27 | dispatch_once(&onceToken, ^{ 28 | instance = [[NEEventTracingConstData alloc] init]; 29 | }); 30 | return instance; 31 | } 32 | 33 | - (instancetype)init { 34 | self = [super init]; 35 | if (self) { 36 | [self _doLoadStaticallyRegisteredItems]; 37 | } 38 | return self; 39 | } 40 | 41 | - (NSArray *)constKeysForType:(NSString *)type { 42 | return [self.constData objectForKey:type]; 43 | } 44 | 45 | #pragma mark - private methods 46 | -(void)_doLoadStaticallyRegisteredItems { 47 | for (uint32_t i = 0, n = _dyld_image_count(); i < n; ++i) { 48 | [self _doLoadStaticallyRegisteredItemsFromMachO:(mach_header_ptr_t)_dyld_get_image_header(i)]; 49 | } 50 | } 51 | 52 | - (void)_doLoadStaticallyRegisteredItemsFromMachO:(mach_header_ptr_t)header { 53 | NSMutableDictionary *> *data = @{}.mutableCopy; 54 | unsigned long size = 0; 55 | uintptr_t *memory = (uintptr_t*)getsectiondata(header, SEG_DATA, ETConstDataSecName, &size); 56 | 57 | unsigned long counter = size/sizeof(void*); 58 | for(int idx = 0; idx < counter; ++idx){ 59 | char *string = (char*)memory[idx]; 60 | NSString *str = [NSString stringWithUTF8String:string]; 61 | if(!str)continue; 62 | 63 | NSArray *comps = [str componentsSeparatedByString:@"/"]; 64 | if (comps.count != 3) { 65 | return; 66 | } 67 | 68 | NSString *type = comps.firstObject; 69 | NSString *key = comps.lastObject; 70 | 71 | NSMutableArray *keys = [data objectForKey:type].mutableCopy; 72 | if (!keys) { 73 | keys = @[].mutableCopy; 74 | } 75 | [keys addObject:key]; 76 | [data setObject:keys.copy forKey:type]; 77 | } 78 | 79 | if (data.count) { 80 | self.constData = data.copy; 81 | } 82 | } 83 | 84 | #pragma mark - getters 85 | - (NSArray *)allConstKeys { 86 | NSMutableArray *keys = @[].mutableCopy; 87 | [self.constData enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSArray * _Nonnull obj, BOOL * _Nonnull stop) { 88 | [keys addObjectsFromArray:obj]; 89 | }]; 90 | return keys.copy; 91 | } 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Utils/Private/NEEventTracingSentinel.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingSentinel.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/3/25. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | /// a thread safe incrementing counter. 13 | @interface NEEventTracingSentinel : NSObject 14 | 15 | @property(atomic, readonly) int32_t value; 16 | 17 | + (instancetype)sentinel; 18 | + (instancetype)sentinelWithInitialValue:(int32_t)initialValue; 19 | 20 | - (int32_t)increase; 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Utils/Private/NEEventTracingSentinel.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingSentinel.m 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/3/25. 6 | // 7 | 8 | #import "NEEventTracingSentinel.h" 9 | #import 10 | 11 | @implementation NEEventTracingSentinel { 12 | atomic_int _value; 13 | } 14 | 15 | + (instancetype)sentinel { 16 | return [self sentinelWithInitialValue:0]; 17 | } 18 | 19 | + (instancetype)sentinelWithInitialValue:(int32_t)initialValue { 20 | NEEventTracingSentinel *s = [NEEventTracingSentinel new]; 21 | s->_value = initialValue; 22 | return s; 23 | } 24 | 25 | - (int32_t)value { 26 | return atomic_load_explicit(&_value, memory_order_acquire); 27 | } 28 | - (int32_t)increase { 29 | return atomic_fetch_add_explicit(&_value, 1, memory_order_acq_rel); 30 | } 31 | @end 32 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Utils/Private/NSString+EventTracingUtil.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+EventTracingUtil.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2022/2/23. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface NSString (EventTracingUtil) 13 | 14 | /// MARK: cid在组装scm的时候,如果存在特殊字符,会影响scm的格式,此时需要url encode的方式来解决 15 | - (BOOL)ne_et_simplyNeedsEncoded; 16 | 17 | - (BOOL)ne_et_hasBeenUrlEncoded; 18 | - (NSString * _Nullable)ne_et_urlEncode; 19 | - (NSString * _Nullable)ne_et_urlDecode; 20 | 21 | @end 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/Utils/Private/NSString+EventTracingUtil.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+EventTracingUtil.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2022/2/23. 6 | // 7 | 8 | #import "NSString+EventTracingUtil.h" 9 | 10 | @implementation NSString (EventTracingUtil) 11 | 12 | - (BOOL)ne_et_simplyNeedsEncoded { 13 | static NSRegularExpression *reg = nil; 14 | static dispatch_once_t onceToken; 15 | dispatch_once(&onceToken, ^{ 16 | reg = [NSRegularExpression regularExpressionWithPattern:@"[:|\\[\\],.\\/\\\\{}`<>@?&\\s'\"]" options:0 error:nil]; 17 | }); 18 | NSInteger matchCount = [reg numberOfMatchesInString:self 19 | options:NSMatchingReportProgress 20 | range:NSMakeRange(0, self.length)]; 21 | return matchCount > 0; 22 | } 23 | 24 | - (BOOL)ne_et_hasBeenUrlEncoded { 25 | return ![self.ne_et_urlDecode isEqualToString:self]; 26 | } 27 | 28 | - (NSString * _Nullable)ne_et_urlEncode { 29 | static dispatch_once_t onceToken; 30 | static NSCharacterSet *charSet = nil; 31 | dispatch_once(&onceToken, ^{ 32 | NSMutableCharacterSet *set = [NSCharacterSet URLQueryAllowedCharacterSet].invertedSet.mutableCopy; 33 | [set formUnionWithCharacterSet:[NSCharacterSet characterSetWithCharactersInString:@"!*'\"();:@&=+$,/?%#[]%,.\\|{}`<>\x20\t\n\r"]]; 34 | charSet = [set invertedSet]; 35 | }); 36 | return [self stringByAddingPercentEncodingWithAllowedCharacters:charSet]; 37 | } 38 | 39 | - (NSString * _Nullable)ne_et_urlDecode { 40 | return self.stringByRemovingPercentEncoding; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/VTree/Private/NEEventTracingVTree+Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingVTree+Private.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/3/12. 6 | // 7 | 8 | #import "NEEventTracingVTree.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | #define LOCK dispatch_semaphore_wait(_lock, DISPATCH_TIME_FOREVER); 13 | #define UNLOCK dispatch_semaphore_signal(_lock); 14 | 15 | @interface NEEventTracingVTree () 16 | 17 | @property(nonnull, strong) dispatch_semaphore_t lock; 18 | @property(nonatomic, copy) NSString *identifier; 19 | 20 | @property(nonatomic, strong, readonly) NSArray *flattenNodes; 21 | 22 | + (instancetype)emptyVTree; 23 | - (void)VTreeDidBecomeStable; 24 | - (void)VTreeMarkUnStable; 25 | - (void)markVTreeVisible:(BOOL)visible; 26 | - (void)regenerateVTreeIdentifier; 27 | 28 | - (void)pushNode:(NEEventTracingVTreeNode *)node parentNode:(NEEventTracingVTreeNode * _Nullable)parentNode ignoreParentValid:(BOOL)ignoreParentValid; 29 | - (void)removeNode:(NEEventTracingVTreeNode *)node; 30 | 31 | // 自动逻辑挂载 32 | - (NEEventTracingVTreeNode * _Nullable)findNodeByDiffIdentifier:(id)diffIdentifier; 33 | 34 | @end 35 | 36 | NS_ASSUME_NONNULL_END 37 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/VTree/Sync/NEEventTracingVTree+Sync.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingVTree+Sync.h 3 | // BlocksKit 4 | // 5 | // Created by dl on 2021/3/25. 6 | // 7 | 8 | #import "NEEventTracingVTree.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface NEEventTracingVTree (Sync) 13 | 14 | // 同步VTree的 pgstep & actseq 等重要参数 15 | - (void)syncToVTree:(NEEventTracingVTree *)VTree; 16 | 17 | // 更新节点以及父节点的params 18 | - (void)syncNodeDynamicParamsForNode:(NEEventTracingVTreeNode *)node event:(NSString *)event; 19 | 20 | // 这里用来回填数据,由于某些原因导致VTree切换后,上一个VTree又触发了 event ,需要递增 actseq 21 | // 目前这里针对 UIAlertController 22 | - (void)increaseActseqFromOtherTree:(NEEventTracingVTree *)otherTree node:(NEEventTracingVTreeNode *)node; 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/VTree/Visible/NEEventTracingVTree+Visible.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingVTree+Visible.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/3/18. 6 | // 7 | 8 | #import "NEEventTracingVTree+Private.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface NEEventTracingVTree (Visible) 13 | 14 | - (void)updateVisibleForNode:(NEEventTracingVTreeNode *)node; 15 | - (void)applySubpageOcclusionIfNeeded; 16 | 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/VTree/Visible/NEEventTracingVTreeNode+Visible.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingVTreeNode+Visible.h 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/3/18. 6 | // 7 | 8 | #import "NEEventTracingVTreeNode+Private.h" 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface NEEventTracingVTreeNode (Visible) 13 | 14 | // VisibleRect 15 | - (void)updateVisible:(BOOL)visible visibleRect:(CGRect)visibleRect; 16 | - (void)markBlockedByOcclusionPageNode:(NEEventTracingVTreeNode *)occlusionPageNode; 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /EventTracing-iOS/Classes/VTree/Visible/NEEventTracingVTreeNode+Visible.m: -------------------------------------------------------------------------------- 1 | // 2 | // NEEventTracingVTreeNode+Visible.m 3 | // NEEventTracing 4 | // 5 | // Created by dl on 2021/3/18. 6 | // 7 | 8 | #import "NEEventTracingVTreeNode+Visible.h" 9 | #import "NSArray+ETEnumerator.h" 10 | #import 11 | 12 | @implementation NEEventTracingVTreeNode (Visible) 13 | 14 | - (void)updateVisible:(BOOL)visible visibleRect:(CGRect)visibleRect { 15 | self.visible = visible; 16 | self.visibleRect = visibleRect; 17 | 18 | CGFloat viewSelfArea = self.viewVisibleRectOnScreen.size.width * self.viewVisibleRectOnScreen.size.height; 19 | if (viewSelfArea <= 0) { 20 | return; 21 | } 22 | CGFloat viewVisibleArea = visibleRect.size.width * visibleRect.size.height; 23 | self.impressMaxRatio = MAX(0.f, MIN(1.f, roundf(viewVisibleArea / viewSelfArea * 100) / 100.f)); // 保留两位小数 24 | } 25 | 26 | - (void)markBlockedByOcclusionPageNode:(NEEventTracingVTreeNode *)occlusionPageNode { 27 | if (self.isVirtualNode) { 28 | self.blockedBySubPage = YES; 29 | return; 30 | } 31 | 32 | [@[self] ne_et_enumerateObjectsUsingBlock:^NSArray * _Nonnull(NEEventTracingVTreeNode * _Nonnull obj, BOOL * _Nonnull stop) { 33 | obj.blockedBySubPage = YES; 34 | return obj.subNodes; 35 | }]; 36 | 37 | if (self.parentNode.isVirtualNode) { 38 | BOOL parentVirtualNodeHasVisiableSubNodes = [self.parentNode.subNodes bk_any:^BOOL(NEEventTracingVTreeNode *obj) { 39 | return !obj.blockedBySubPage && obj.isVisible; 40 | }]; 41 | if (!parentVirtualNodeHasVisiableSubNodes) { 42 | self.parentNode.blockedBySubPage = YES; 43 | } 44 | 45 | return; 46 | } 47 | 48 | /// MARK: 如果一个节点明确声明只有存在指定子节点的时候才合法,而且所有子节点都被遮挡了,该节点也应该算被遮挡 49 | if (self.parentNode.validForContainingSubNodeOids.count == 0) { 50 | return; 51 | } 52 | 53 | /// MARK: 遮挡,只能遮挡`左侧兄弟节点`,或者左右兄弟节点的子节点,不可以向上遮挡 54 | __block BOOL shouldBeBlocked = YES; 55 | [occlusionPageNode enumerateAncestorNodeWithBlock:^(NEEventTracingVTreeNode * _Nonnull ancestorNode, BOOL * _Nonnull stop) { 56 | if (ancestorNode == self.parentNode) { 57 | shouldBeBlocked = NO; 58 | *stop = YES; 59 | } 60 | }]; 61 | 62 | if (shouldBeBlocked) { 63 | [[self.parentNode.subNodes bk_reject:^BOOL(NEEventTracingVTreeNode *obj) { 64 | return !obj.visible; 65 | }] enumerateObjectsUsingBlock:^(NEEventTracingVTreeNode * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 66 | if ([self.parentNode.validForContainingSubNodeOids containsObject:obj.oid]) { 67 | shouldBeBlocked = NO; 68 | } 69 | }]; 70 | } 71 | 72 | if (shouldBeBlocked) { 73 | [self.parentNode markBlockedByOcclusionPageNode:occlusionPageNode]; 74 | } 75 | } 76 | 77 | @end 78 | -------------------------------------------------------------------------------- /EventTracing.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'EventTracing' 3 | s.version = '2.0.0' 4 | s.summary = 'EventTracing' 5 | 6 | s.description = <<-DESC 7 | EventTracing-iOS 8 | DESC 9 | 10 | s.homepage = 'https://github.com/EventTracing/EventTracing-iOS' 11 | s.license = { :type => 'MIT', :file => 'LICENSE' } 12 | s.author = { 'eventtracing' => 'eventtracing@service.netease.com' } 13 | s.source = { :git => 'https://github.com/EventTracing/EventTracing-iOS.git', :tag => s.version.to_s } 14 | 15 | s.ios.deployment_target = '10.0' 16 | s.library = 'c++' 17 | s.pod_target_xcconfig = { 18 | 'GCC_PRECOMPILE_PREFIX_HEADER' => true 19 | } 20 | 21 | s.source_files = [ 22 | 'EventTracing-iOS/Classes/**/*.{h,m,mm}' 23 | ] 24 | 25 | s.private_header_files = [ 26 | 'EventTracing-iOS/Classes/Categorys/*.h', 27 | 'EventTracing-iOS/Classes/Core/*.h', 28 | 'EventTracing-iOS/Classes/Log/*.h', 29 | 'EventTracing-iOS/Classes/Output/Private/*.h', 30 | 'EventTracing-iOS/Classes/ParamGuard/Private/*.h', 31 | 'EventTracing-iOS/Classes/Refer/Private/*.h', 32 | 'EventTracing-iOS/Classes/Throttle/*.h', 33 | 'EventTracing-iOS/Classes/Traverser/*.h', 34 | 'EventTracing-iOS/Classes/Utils/Private/*.h', 35 | 'EventTracing-iOS/Classes/VTree/Private/*.h', 36 | 'EventTracing-iOS/Classes/VTree/Sync/*.h', 37 | 'EventTracing-iOS/Classes/VTree/Visible/*.h' 38 | ] 39 | s.public_header_files = [ 40 | 'EventTracing-iOS/Classes/Public/**/*.h', 41 | 'EventTracing-iOS/Classes/VTree/*.h', 42 | 'EventTracing-iOS/Classes/Refer/*.h', 43 | 'EventTracing-iOS/Classes/Output/*.h', 44 | 'EventTracing-iOS/Classes/Diff/*.h', 45 | 'EventTracing-iOS/Classes/ParamGuard/NEEventTracingParamGuardConfiguration.h', 46 | 'EventTracing-iOS/Classes/Exceptions/NEEventTracingExceptionDelegate.h', 47 | 'EventTracing-iOS/Classes/Utils/NSArray+ETEnumerator.h' 48 | ] 49 | 50 | s.dependency 'JRSwizzle', '~> 1.0' 51 | s.dependency 'BlocksKit', '~> 2.2.5' 52 | end 53 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/ETCommonDefines.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETCommonDefines.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2023/1/5. 6 | // Copyright © 2023 9446796. All rights reserved. 7 | // 8 | 9 | #ifndef ETCommonDefines_h 10 | #define ETCommonDefines_h 11 | 12 | /// MARK: 如果你自己启动了 H5 Demo, 则开启如下,如果需要,你还需要修改 `H5_Demo_URL` 的值 13 | //#define H5_Demo_Use_Remote 1 14 | 15 | #ifdef H5_Demo_Use_Remote 16 | #define H5_Demo_URL @"http://localhost:8000/" 17 | #else 18 | #define H5_Demo_URL @"" 19 | #endif 20 | 21 | #endif /* ETCommonDefines_h */ 22 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/ETTabBarViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETTabBarViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by xxq on 2022/12/9. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETTabBarViewController : UITabBarController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/ETTabBarViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETTabBarViewController.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by xxq on 2022/12/9. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "ETTabBarViewController.h" 10 | #import 11 | 12 | @interface ETTabBarViewController () 13 | @property(nonatomic, strong) UIButton *floatBtn; 14 | @end 15 | 16 | @implementation ETTabBarViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | 21 | [[NEEventTracingBuilder viewController:self pageId:@"page_main"] build:^(id _Nonnull builder) { 22 | builder 23 | .logicalParentView(self.view.window) 24 | .params.set(@"abc", @"root.val.abc"); 25 | }]; 26 | } 27 | 28 | #pragma mark - NEEventTracingVTreeNodeExtraConfigProtocol 29 | - (NSArray *)et_validForContainingSubNodeOids { 30 | return @[@"page_tab_vc_1", @"page_tab_vc_2"]; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/EventTracing-iOS-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 123 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.2.30 25 | LSRequiresIPhoneOS 26 | 27 | NSCameraUsageDescription 28 | 需要相机权限 29 | UILaunchStoryboardName 30 | LaunchScreen 31 | UIMainStoryboardFile 32 | Main 33 | UIRequiredDeviceCapabilities 34 | 35 | armv7 36 | 37 | UISupportedInterfaceOrientations 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationLandscapeLeft 41 | UIInterfaceOrientationLandscapeRight 42 | 43 | UISupportedInterfaceOrientations~ipad 44 | 45 | UIInterfaceOrientationPortrait 46 | UIInterfaceOrientationPortraitUpsideDown 47 | UIInterfaceOrientationLandscapeLeft 48 | UIInterfaceOrientationLandscapeRight 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/EventTracing-iOS-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | 17 | #import 18 | #import 19 | #import 20 | #import 21 | #import 22 | #import 23 | #import 24 | #import 25 | #import 26 | #import 27 | 28 | #import "ETBaseViewController.h" 29 | #import "UIColor+ET.h" 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/ETH5ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETH5ViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ETBaseViewController.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface ETH5ViewController : ETBaseViewController 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/ETH5ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETH5ViewController.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "ETH5ViewController.h" 10 | #import "ETWebView.h" 11 | #import "EventTracingTestLogComing.h" 12 | #import "ETCommonDefines.h" 13 | #import 14 | 15 | @interface ETH5ViewController () 16 | @property (nonatomic, strong) ETWebView *webView; 17 | @end 18 | 19 | @implementation ETH5ViewController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | 24 | self.webView = [[ETWebView alloc] init]; 25 | [self.view addSubview:self.webView]; 26 | 27 | [self.webView mas_makeConstraints:^(MASConstraintMaker *make) { 28 | make.edges.equalTo(self.view); 29 | }]; 30 | 31 | #ifdef H5_Demo_Use_Remote 32 | NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:H5_Demo_URL]]; 33 | [self.webView loadRequest:urlRequest]; 34 | #else 35 | [self loadExamplePage:self.webView]; 36 | #endif 37 | 38 | [NEEventTracingBuilder viewController:self pageId:@"page_h5_biz"]; 39 | 40 | // [self testBridgeFunc]; 41 | } 42 | 43 | - (void) testBridgeFunc { 44 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 45 | [self.webView execJsFunc:@"foo" inModule:@"module_in_js" params:@{ 46 | @"tip": @"This is H5 Tip" 47 | } completionHandler:nil]; 48 | 49 | [self.webView checkoutIfHasJsFunc:@"foo" inModule:@"module_in_js" completionHandler:^(id _Nullable result, NSError * _Nullable error) { 50 | NSLog(@"result: %@, error: %@", result, error); 51 | }]; 52 | }); 53 | } 54 | 55 | - (void)viewDidAppear:(BOOL)animated { 56 | [super viewDidAppear:animated]; 57 | 58 | [EventTracingAllTestLogComings() enumerateObjectsUsingBlock:^(EventTracingTestLogComing * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 59 | [obj webViewDidShow:self.webView]; 60 | }]; 61 | } 62 | 63 | - (void)loadExamplePage:(WKWebView*)webView { 64 | NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"h5" ofType:@"html"]; 65 | NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil]; 66 | NSURL *baseURL = [NSURL fileURLWithPath:htmlPath]; 67 | [webView loadHTMLString:appHtml baseURL:baseURL]; 68 | } 69 | 70 | - (NSString *)tipText { 71 | return @"" 72 | "1. 本 demo 中使用的 jsbridge 仅供参考\n" 73 | " 1.1 jsbridge 支持 js 调用oc方法,并且带 callback\n" 74 | " 1.2 jsbridge 支持主动调用一个 js 中注册的方法\n" 75 | " 1.3 js 中可以 checkout 判断native是否存在某个 bridge\n" 76 | " 1.4 native 可以判断 js 中是否注册了某个方法,可以供native调用\n" 77 | ""; 78 | } 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/ETJSBInternalBridgeAvaiable.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETJSBInternalBridgeAvaiable.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/28. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "ETWebViewBridgeManager.h" 10 | 11 | @interface ETJSBInternalBridgeAvaiable : ETWebViewBridgeModule 12 | @end 13 | 14 | @implementation ETJSBInternalBridgeAvaiable 15 | 16 | ETWEBKIT_BRIDGE_MODULE_EXPORT(__et_jsb_internal_bridge) 17 | 18 | ETWEBKIT_BRIDGE_MODULE_METHDO_EXPORT(avaiable) { 19 | NSString *moduleName = [context.params objectForKey:@"module"]; 20 | NSString *methodName = [context.params objectForKey:@"method"]; 21 | 22 | Class moduleClass = [[ETWebViewBridgeManager sharedInstance] moduleClassForModuleName:moduleName]; 23 | id module = [moduleClass new]; 24 | SEL handleSel = NSSelectorFromString([NSString stringWithFormat:@"%@DidCallWithContext:completionHandler:", methodName]); 25 | 26 | callback(nil, @{@"avaiable": @([module respondsToSelector:handleSel])}); 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/ETWebUtility.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETWebUtility.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETWebUtility : NSObject 14 | 15 | + (NSString *)scriptWithJSFunc:(NSString *)funcName withArgs:(NSArray *)args; 16 | 17 | #pragma mark - json 18 | + (NSString *)JSONStringifyWithJSONObject:(id)object; 19 | + (id)JSONObjectFromJSONString:(NSString *)string; 20 | 21 | @end 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/ETWebUtility.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETWebUtility.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "ETWebUtility.h" 10 | 11 | @implementation ETWebUtility 12 | 13 | + (NSString *)scriptWithJSFunc:(NSString *)funcName withArgs:(NSArray *)args { 14 | 15 | NSMutableString *js = funcName.mutableCopy; 16 | [js appendString:@"("]; 17 | NSMutableArray *values = @[].mutableCopy; 18 | [args enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) { 19 | NSString *value = @""; 20 | if ([obj isKindOfClass:[NSString class]]) { 21 | value = [self javaScriptStringEncodeValue:obj]; 22 | } else if ([obj isKindOfClass:[NSNumber class]]) { 23 | value = [NSString stringWithFormat:@"%@", obj]; 24 | } else if ([obj isKindOfClass:[NSArray class]] || [obj isKindOfClass:[NSDictionary class]]) { 25 | value = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:obj options:0 error:nil] 26 | encoding:NSUTF8StringEncoding]; 27 | } else if ([obj isKindOfClass:[NSNull class]]) { 28 | value = @"null"; 29 | } 30 | [values addObject:value]; 31 | }]; 32 | [js appendString:[values componentsJoinedByString:@","]]; 33 | [js appendString:@")"]; 34 | return js; 35 | } 36 | 37 | + (NSString *)javaScriptStringEncodeValue:(NSString *)value { 38 | 39 | NSMutableString *result = value.mutableCopy; 40 | [result replaceOccurrencesOfString:@"\\" withString:@"\\\\" options:0 range:NSMakeRange(0, result.length)]; 41 | [result replaceOccurrencesOfString:@"\"" withString:@"\\\"" options:0 range:NSMakeRange(0, result.length)]; 42 | [result replaceOccurrencesOfString:@"\n" withString:@"\\n" options:0 range:NSMakeRange(0, result.length)]; 43 | [result replaceOccurrencesOfString:@"\r" withString:@"\\r" options:0 range:NSMakeRange(0, result.length)]; 44 | [result replaceOccurrencesOfString:@"\f" withString:@"\\f" options:0 range:NSMakeRange(0, result.length)]; 45 | [result replaceOccurrencesOfString:@"\u2028" withString:@"\\u2028" options:0 range:NSMakeRange(0, result.length)]; 46 | [result replaceOccurrencesOfString:@"\u2029" withString:@"\\u2029" options:0 range:NSMakeRange(0, result.length)]; 47 | return [NSString stringWithFormat:@"\"%@\"", result]; 48 | } 49 | 50 | #pragma mark - 51 | 52 | + (id)JSONObjectFromJSONString:(NSString *)string { 53 | 54 | NSData *jsonData = [string dataUsingEncoding:NSUTF8StringEncoding]; 55 | if (! jsonData) { 56 | return nil; 57 | } 58 | NSDictionary *ret = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:nil]; 59 | return ret; 60 | } 61 | 62 | + (NSString *)JSONStringifyWithJSONObject:(id)object { 63 | 64 | if (! object) { 65 | return nil; 66 | } 67 | NSData *data = [NSJSONSerialization dataWithJSONObject:object options:kNilOptions error:nil]; 68 | if (! data) { 69 | return nil; 70 | } 71 | return [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 72 | } 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/ETWebView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETWebView.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETWebView : WKWebView 14 | 15 | - (void)unsafeEvaluateJavaScript:(NSString * _Nonnull)javaScriptString 16 | completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler; 17 | - (void)evaluateJavaScript:(NSString * _Nonnull)javaScriptString; 18 | 19 | - (void)execJsFunc:(NSString *)jsFunc 20 | inModule:(NSString * _Nullable)module 21 | params:(NSDictionary *)params 22 | completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler; 23 | 24 | - (void)checkoutIfHasJsFunc:(NSString *)jsFunc 25 | inModule:(NSString * _Nullable)module 26 | completionHandler:(void (^ _Nullable)(_Nullable id, NSError * _Nullable error))completionHandler; 27 | 28 | @end 29 | 30 | NS_ASSUME_NONNULL_END 31 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/ETWebViewBridge.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETWebViewBridge.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @class ETWebView; 16 | 17 | @protocol ETWebViewJSBridgeProtocol 18 | - (void)postMessage:(NSDictionary *)message; 19 | @end 20 | 21 | @protocol ETWebViewBridgeContextProtocol 22 | @property (nonatomic, weak, readonly) ETWebView *webView; // 当前的 webView 对象 23 | @property (nonatomic, weak, nullable, readonly) UIViewController *viewController; // 当前的控制器 24 | @end 25 | 26 | @interface ETWebViewBridge : NSObject 27 | 28 | @property(nonatomic, strong, readonly) id context; 29 | 30 | - (instancetype)initWithWebView:(ETWebView *)webView; 31 | 32 | - (void)buildBridgeWithUserContentController:(WKUserContentController *)userContentController; 33 | - (void)clearBridgeWithUserContentController:(WKUserContentController *)userContentController; 34 | 35 | @end 36 | 37 | NS_ASSUME_NONNULL_END 38 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/ETWebViewBridgeManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETWebViewBridgeManager.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ETWebViewBridgeModuleContext.h" 11 | #import "NSError+ETWebViewBridge.h" 12 | #import "ETWebView.h" 13 | #import "ETWebViewBridge.h" 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | typedef void(^ETWebViewBridgeCallBack)(NSDictionary * _Nullable result, NSDictionary * _Nullable error); 18 | 19 | #define ETWEB_BRIDGE_STRINGIFY(S) #S 20 | #define ETWEBKIT_BRIDGE_MODULE_EXPORT(NAME) \ 21 | + (void)load { \ 22 | [[ETWebViewBridgeManager sharedInstance] registModule:self forModuleName:@ETWEB_BRIDGE_STRINGIFY(NAME)]; \ 23 | } \ 24 | - (NSString *)moduleName {\ 25 | return @ETWEB_BRIDGE_STRINGIFY(NAME); \ 26 | }\ 27 | 28 | #define ETWEBKIT_BRIDGE_MODULE_METHDO_EXPORT(methodName) \ 29 | - (void)\ 30 | methodName ## DidCallWithContext:(id)context callback:(ETWebViewBridgeCallBack)callback 31 | 32 | @protocol ETWebViewBridgeModuleProtocol 33 | @property(nonatomic, weak, readonly) ETWebViewBridge *bridge; 34 | 35 | - (NSString *)moduleName; 36 | @end 37 | 38 | @interface ETWebViewBridgeModule : NSObject 39 | @end 40 | 41 | @protocol ETWebViewBridgeManagerProtocol 42 | 43 | /// 注册一个可以处理该协议的模块 44 | /// @param moduleClass 模块 45 | /// @param moduleName 协议名称 46 | - (void)registModule:(Class)moduleClass forModuleName:(NSString *)moduleName; 47 | 48 | /// 根据 moduleName 找到对应可以处理的类 49 | /// @param moduleName 模块名称 50 | /// @return 可以处理改协议的类 51 | - (Class __nullable)moduleClassForModuleName:(NSString *)moduleName; 52 | 53 | @end 54 | 55 | @interface ETWebViewBridgeManager : NSObject 56 | + (instancetype)sharedInstance; 57 | @end 58 | 59 | @interface ETWebViewBridgeManager (Debug) 60 | 61 | /// For Debug 62 | /// 获取所有的 模块名字 63 | - (NSArray *)debug_allModuleNames; 64 | 65 | /// For Debug 66 | /// 获取当前注册的所有的 模块 67 | - (NSDictionary *)debug_allModuleMap; 68 | @end 69 | 70 | NS_ASSUME_NONNULL_END 71 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/ETWebViewBridgeManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETWebViewBridgeManager.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "ETWebViewBridgeManager.h" 10 | 11 | @interface ETWebViewBridgeManager () 12 | @property (nonatomic) NSMutableDictionary *modules; 13 | @end 14 | 15 | @implementation ETWebViewBridgeManager 16 | 17 | + (instancetype)sharedInstance { 18 | static ETWebViewBridgeManager *sharedInstance = nil; 19 | static dispatch_once_t onceToken; 20 | dispatch_once(&onceToken, ^{ 21 | sharedInstance = [self new]; 22 | sharedInstance.modules = @{}.mutableCopy; 23 | }); 24 | return sharedInstance; 25 | } 26 | 27 | - (void)registModule:(Class)moduleClass forModuleName:(NSString *)moduleName { 28 | 29 | Class previousClass = self.modules[moduleName]; 30 | NSAssert(previousClass == nil, @"%@ 存在可以处理的模块 %@", moduleName, previousClass); 31 | self.modules[moduleName] = moduleClass; 32 | } 33 | 34 | - (Class)moduleClassForModuleName:(NSString *)moduleName { 35 | return self.modules[moduleName]; 36 | } 37 | 38 | @end 39 | 40 | @implementation ETWebViewBridgeManager (Debug) 41 | 42 | - (NSArray *)debug_allModuleNames { 43 | return self.modules.allKeys; 44 | } 45 | 46 | - (NSDictionary *)debug_allModuleMap { 47 | return [self.modules copy];; 48 | } 49 | 50 | 51 | @end 52 | 53 | @implementation ETWebViewBridgeModule 54 | @synthesize bridge = _bridge; 55 | 56 | #pragma mark - ETWebViewBridgeModuleProtocol 57 | - (NSString *)moduleName { 58 | NSAssert(NO, @"Sub module class need override"); 59 | return nil; 60 | } 61 | @end 62 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/ETWebViewBridgeModuleContext.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETWebViewBridgeModuleContext.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @class ETWebView; 14 | 15 | @class ETWebViewBridge; 16 | @protocol ETWebViewBridgeCallContextProtocol 17 | 18 | @property (nonatomic, copy, readonly) NSString *seq; // call seq 19 | @property (nonatomic, copy, readonly) NSString *method; // 请求名 20 | @property (nonatomic, copy, readonly) NSDictionary *params; // 请求的参数 21 | 22 | @property (nonatomic, weak, readonly) ETWebViewBridge *bridge; 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/Message/ETWebViewBridgeMessage.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETWebViewBridgeMessage.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETWebViewBridgeMessage : NSObject 14 | 15 | @property (nonatomic, copy, readonly) NSString *seq; // 用于唯一确定一次请求 16 | @property (nonatomic, copy, readonly) NSString *module; // 模块名称 17 | @property (nonatomic, copy, readonly) NSString *method; // 调用的接口 18 | @property (nonatomic, copy, readonly) NSDictionary *params; // 调用的参数 19 | 20 | + (BOOL)isValidMessageObject:(id)message errorMessage:(NSString * _Nullable * _Nullable)errorMessage; 21 | 22 | + (instancetype)webViewBridgeMessageWithMessageObject:(NSDictionary *)messageObject; 23 | 24 | @end 25 | 26 | NS_ASSUME_NONNULL_END 27 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/Message/ETWebViewBridgeMessage.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETWebViewBridgeMessage.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "ETWebViewBridgeMessage.h" 10 | 11 | @interface ETWebViewBridgeMessage () 12 | 13 | @property (nonatomic, copy, readwrite) NSString *seq; 14 | @property (nonatomic, copy, readwrite) NSString *module; 15 | @property (nonatomic, copy, readwrite) NSString *method; 16 | @property (nonatomic, copy, readwrite) NSDictionary *params; 17 | 18 | @end 19 | 20 | @implementation ETWebViewBridgeMessage 21 | 22 | + (BOOL)isValidMessageObject:(id)message errorMessage:(NSString *__autoreleasing *)errorMessage { 23 | 24 | if (! [message isKindOfClass:[NSDictionary class]]) { 25 | return NO; 26 | } 27 | 28 | // seq 用于唯一确定一次请求 回调的时候需要带回去 29 | NSString *seq = [message objectForKey:@"seq"]; 30 | if (![seq isKindOfClass:NSString.class] || seq.length == 0) { 31 | *errorMessage = @"seq 不能为空"; 32 | return NO; 33 | } 34 | 35 | // method 表示需要调用的什么服务 36 | NSString *method = [message objectForKey:@"method"]; 37 | if (![method isKindOfClass:NSString.class] || method.length == 0) { 38 | *errorMessage = @"method 不能为空"; 39 | return NO; 40 | } 41 | 42 | // params 表示调用服务时传递过来的参数 43 | NSDictionary *params = [message objectForKey:@"params"]; 44 | if (![params isKindOfClass:NSDictionary.class]) { 45 | *errorMessage = @"params 只能为字典"; 46 | return NO; 47 | } 48 | 49 | return YES; 50 | } 51 | 52 | + (instancetype)webViewBridgeMessageWithMessageObject:(NSDictionary *)messageObject { 53 | ETWebViewBridgeMessage *webViewBridgeMessage = [ETWebViewBridgeMessage new]; 54 | 55 | webViewBridgeMessage.seq = [messageObject objectForKey:@"seq"]; 56 | webViewBridgeMessage.module = [messageObject objectForKey:@"module"]; 57 | webViewBridgeMessage.method = [messageObject objectForKey:@"method"]; 58 | webViewBridgeMessage.params = [messageObject objectForKey:@"params"]; 59 | 60 | return webViewBridgeMessage; 61 | } 62 | 63 | - (NSString *)description { 64 | return [NSString stringWithFormat:@"seq: %@\n class: %@\n method: %@\n params: %@\n", _seq, _module, _method, _params]; 65 | } 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/NSError+ETWebViewBridge.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSError+ETWebViewBridge.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | typedef NS_ENUM(NSInteger, ETWebViewBridgeCode) { 14 | ETWebViewBridgeCodeSuccess = 200, 15 | 16 | ETWebViewBridgeCodeInvalidParams = 400, 17 | ETWebViewBridgeCodeNotFound = 404, 18 | }; 19 | 20 | @interface NSError (ETWebViewBridge) 21 | 22 | + (NSDictionary *)et_webkit_errorNotFound; 23 | + (NSDictionary *)et_webkit_errorParamsWithCode:(NSUInteger)code message:(NSString * __nullable)message; 24 | + (NSDictionary *)et_webkit_errorParamsWithMessage:(NSString * __nullable)message; 25 | + (NSDictionary *)et_webkit_errorParamsWithMessage:(NSString *)message userInfo:(NSDictionary * __nullable)userInfo; 26 | 27 | + (NSDictionary *)et_webkit_errorWithMessage:(NSString *)message code:(ETWebViewBridgeCode)code; 28 | + (NSDictionary *)et_webkit_errorWithMessage:(NSString *)message code:(ETWebViewBridgeCode)code userInfo:(NSDictionary * __nullable)userInfo; 29 | 30 | @end 31 | 32 | NS_ASSUME_NONNULL_END 33 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/NSError+ETWebViewBridge.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSError+ETWebViewBridge.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/27. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "NSError+ETWebViewBridge.h" 10 | 11 | @implementation NSError (ETWebViewBridge) 12 | 13 | + (NSDictionary *)et_webkit_errorParamsWithMessage:(NSString *)message { 14 | return [self et_webkit_errorWithMessage:message ?: @"参数错误" code:ETWebViewBridgeCodeInvalidParams userInfo:nil]; 15 | } 16 | 17 | + (NSDictionary *)et_webkit_errorParamsWithMessage:(NSString *)message userInfo:(NSDictionary *)userInfo { 18 | return [self et_webkit_errorWithMessage:message code:ETWebViewBridgeCodeInvalidParams userInfo:userInfo]; 19 | } 20 | 21 | + (NSDictionary *)et_webkit_errorParamsWithCode:(NSUInteger)code message:(NSString *)message { 22 | return [self et_webkit_errorWithMessage:message code:code userInfo:nil]; 23 | } 24 | 25 | + (NSDictionary *)et_webkit_errorNotFound { 26 | return [self et_webkit_errorWithMessage:@"找不到该协议" code:ETWebViewBridgeCodeNotFound userInfo:nil]; 27 | } 28 | 29 | + (NSDictionary *)et_webkit_errorWithMessage:(NSString *)message code:(ETWebViewBridgeCode)code { 30 | return [self et_webkit_errorWithMessage:message code:code userInfo:nil]; 31 | } 32 | 33 | + (NSDictionary *)et_webkit_errorWithMessage:(NSString *)message code:(ETWebViewBridgeCode)code userInfo:(NSDictionary * __nullable)userInfo { 34 | NSMutableDictionary *dict = @{}.mutableCopy; 35 | dict[@"code"] = @(code); 36 | dict[@"domain"] = @"com.et.webkit"; 37 | dict[@"message"] = message; 38 | dict[@"userInfo"] = userInfo; 39 | return dict.copy; 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/inject.js: -------------------------------------------------------------------------------- 1 | var bridge = { 2 | default: this, // for typescript 3 | call: function (module, method, args, cb) { 4 | if (typeof args == "function") { 5 | cb = args; 6 | args = {}; 7 | } 8 | args = args === undefined ? null : args; 9 | window.__et_message_call_seq++ 10 | if (typeof cb == "function") { 11 | var cb_name = "__etcb_" + window.__et_message_call_seq; 12 | window[cb_name] = cb; 13 | } 14 | 15 | // For iOS WK: `et_js_is_wk` provided 16 | if (window.et_js_is_wk) { 17 | setTimeout(() => { 18 | window.webkit.messageHandlers.et_js_wk_bridge.postMessage({ 19 | seq: window.__et_message_call_seq + "", 20 | module: module, 21 | method: method, 22 | params: args 23 | }); 24 | }, 0); 25 | } 26 | // For Android 27 | // else if(window.__et_bridge_use_prompt){ 28 | // ret = prompt("__et_bridge=" + method, args); 29 | // } 30 | }, 31 | registe: function (module, method, fun) { 32 | var q = window.__et_bridge_f; 33 | if (typeof fun != "function") { 34 | return 35 | } 36 | 37 | if (method === undefined || method == '' || method == null) { 38 | return 39 | } 40 | 41 | if (module === undefined || module == '' || module == null) { 42 | q[method] = fun 43 | return 44 | } 45 | 46 | var methods = q[module] 47 | methods = methods==undefined ? {} : methods 48 | methods[method] = fun 49 | q[module] = methods 50 | }, 51 | isBridgeAvaiable: function (module, method, cb) { 52 | this.call('__et_jsb_internal_bridge', 'avaiable', {'module': module, 'method': method}, function(error, result, context){ 53 | cb(result['avaiable'], {'module': module, 'method': method}) 54 | }) 55 | } 56 | }; 57 | 58 | !(function () { 59 | if (window.__et_bridge_initialized) return; 60 | 61 | var ob = { 62 | __et_bridge_initialized: true, 63 | __et_bridge_f: {}, 64 | __et_message_call_seq: 0, 65 | __et_bridge: bridge, 66 | __et_call_cb_from_native: function (seq, error, result, context) { 67 | var cb_name = "__etcb_" + seq; 68 | var cb = window[cb_name] 69 | if (typeof cb != 'function') { 70 | return 71 | } 72 | 73 | setTimeout(() => { 74 | cb(error, result, context) 75 | }, 0); 76 | }, 77 | __et_call_f_from_native: function (module, method, args) { 78 | var methods = window.__et_bridge_f[module] 79 | var f = methods[method] 80 | if (typeof f != 'function') { 81 | return 82 | } 83 | 84 | setTimeout(() => { 85 | f(args, {'module': module, 'method': method}) 86 | }, 0); 87 | }, 88 | __et_has_js_method: function (module, method) { 89 | var methods = window.__et_bridge_f[module] 90 | var f = methods[method] 91 | return f && (typeof f == 'function'); 92 | } 93 | }; 94 | for (var attr in ob) { 95 | window[attr] = ob[attr]; 96 | } 97 | })(); 98 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/H5/Jsb/smulate_click.js: -------------------------------------------------------------------------------- 1 | function simulate_click(eid) { 2 | var options = { 3 | pointerX: 0, 4 | pointerY: 0, 5 | button: 0, 6 | ctrlKey: false, 7 | altKey: false, 8 | shiftKey: false, 9 | metaKey: false, 10 | bubbles: true, 11 | cancelable: true, 12 | }; 13 | 14 | function extend(destination, source) { 15 | for (var property in source) destination[property] = source[property]; 16 | return destination; 17 | } 18 | 19 | var oEvent; 20 | var eventType = "MouseEvents"; 21 | var element = document.querySelector("#" + eid); 22 | if (!element) { 23 | return; 24 | } 25 | 26 | oEvent = document.createEvent(eventType); 27 | oEvent.initMouseEvent( 28 | "click", 29 | options.bubbles, 30 | options.cancelable, 31 | document.defaultView, 32 | options.button, 33 | options.pointerX, 34 | options.pointerY, 35 | options.pointerX, 36 | options.pointerY, 37 | options.ctrlKey, 38 | options.altKey, 39 | options.shiftKey, 40 | options.metaKey, 41 | options.button, 42 | element 43 | ); 44 | element.dispatchEvent(oEvent); 45 | } 46 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Images.xcassets/close.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "scale" : "2x" 10 | }, 11 | { 12 | "filename" : "close@3x.png", 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Images.xcassets/close.imageset/close@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eventtracing/EventTracing-iOS/afa6706b719590e7ebe9ade85cc2dcf782873faa/Example/EventTracing-iOS/Images.xcassets/close.imageset/close@3x.png -------------------------------------------------------------------------------- /Example/EventTracing-iOS/NEAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // NEAppDelegate.h 3 | // EventTracing-iOS 4 | // 5 | // Created by 9446796 on 11/29/2021. 6 | // Copyright (c) 2021 9446796. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface NEAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/Base/ETBaseViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETBaseViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/16. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETBaseViewController : UIViewController 14 | 15 | - (NSString *)tipText; 16 | - (NSAttributedString *)tipAttributeText; 17 | 18 | @end 19 | 20 | NS_ASSUME_NONNULL_END 21 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/Base/ETBaseViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETBaseViewController.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/16. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "ETBaseViewController.h" 10 | #import "ETTipViewController.h" 11 | 12 | @interface ETBaseViewController () 13 | 14 | @end 15 | 16 | @implementation ETBaseViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | 21 | self.view.backgroundColor = [UIColor whiteColor]; 22 | self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Tip" style:UIBarButtonItemStylePlain target:self action:@selector(showTip:)]; 23 | } 24 | 25 | - (void)showTip:(id)sender { 26 | NSAttributedString *tipAttributeText = [self tipAttributeText]; 27 | if (!tipAttributeText || tipAttributeText.length == 0) { 28 | NSString *tipText = [self tipText]; 29 | if (tipText.length) { 30 | ETShowTipText(tipText); 31 | } 32 | } else { 33 | ETShowTipAttributeText(tipAttributeText); 34 | } 35 | } 36 | 37 | - (NSString *)tipText { 38 | return nil; 39 | } 40 | 41 | - (NSAttributedString *)tipAttributeText { 42 | return nil; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/Tip/ETTipViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETTipViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/16. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | FOUNDATION_EXPORT void ETShowTipText(NSString *tipText); 14 | FOUNDATION_EXPORT void ETShowTipAttributeText(NSAttributedString *tipAttributeText); 15 | 16 | @interface ETTipViewController : UIViewController 17 | 18 | - (void)showWithTipText:(NSString *)tipText; 19 | - (void)showWithTipAttributeText:(NSAttributedString *)tipAttributeText; 20 | 21 | @end 22 | 23 | NS_ASSUME_NONNULL_END 24 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/categories/UICollectionView+ETDemo.h: -------------------------------------------------------------------------------- 1 | // 2 | // UICollectionView+ETDemo.h 3 | // NEEventTracingDataCompass 4 | // 5 | // Created by xxq on 2022/10/9. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | @interface UICollectionView (ETDemo) 13 | 14 | + (instancetype)et_demo_horiListWithFrame:(CGRect)frame 15 | itemSize:(CGSize)itemSize 16 | horiEdge:(CGFloat)horiEdge 17 | horiSpace:(CGFloat)horiSpace; 18 | 19 | + (instancetype)et_demo_collectionWithFrame:(CGRect)frame 20 | itemSize:(CGSize)itemSize 21 | horiEdge:(CGFloat)horiEdge 22 | horiSpace:(CGFloat)horiSpace 23 | vertEdge:(CGFloat)vertEdge 24 | vertSpace:(CGFloat)vertSpace; 25 | 26 | + (instancetype)et_demo_collectionWithFrame:(CGRect)frame 27 | itemSize:(CGSize)itemSize 28 | horiEdge:(CGFloat)horiEdge 29 | horiSpace:(CGFloat)horiSpace 30 | vertEdge:(CGFloat)vertEdge 31 | vertSpace:(CGFloat)vertSpace 32 | isHori:(BOOL)isHori 33 | layoutClass:(Class)layoutClass; 34 | 35 | @end 36 | 37 | NS_ASSUME_NONNULL_END 38 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/categories/UICollectionView+ETDemo.m: -------------------------------------------------------------------------------- 1 | // 2 | // UICollectionView+ETDemo.m 3 | // NEEventTracingDataCompass 4 | // 5 | // Created by xxq on 2022/10/9. 6 | // 7 | 8 | #import "UICollectionView+ETDemo.h" 9 | 10 | @implementation UICollectionView (ETDemo) 11 | + (instancetype)et_demo_horiListWithFrame:(CGRect)frame 12 | itemSize:(CGSize)itemSize 13 | horiEdge:(CGFloat)horiEdge 14 | horiSpace:(CGFloat)horiSpace { 15 | return [self et_demo_collectionWithFrame:frame itemSize:itemSize horiEdge:horiEdge horiSpace:horiSpace vertEdge:0 vertSpace:0 isHori:YES layoutClass:UICollectionViewFlowLayout.class]; 16 | } 17 | 18 | + (instancetype)et_demo_collectionWithFrame:(CGRect)frame 19 | itemSize:(CGSize)itemSize 20 | horiEdge:(CGFloat)horiEdge 21 | horiSpace:(CGFloat)horiSpace 22 | vertEdge:(CGFloat)vertEdge 23 | vertSpace:(CGFloat)vertSpace { 24 | return [self et_demo_collectionWithFrame:frame itemSize:itemSize horiEdge:horiEdge horiSpace:horiSpace vertEdge:vertEdge vertSpace:vertSpace isHori:NO layoutClass:UICollectionViewFlowLayout.class]; 25 | } 26 | 27 | + (instancetype)et_demo_collectionWithFrame:(CGRect)frame 28 | itemSize:(CGSize)itemSize 29 | horiEdge:(CGFloat)horiEdge 30 | horiSpace:(CGFloat)horiSpace 31 | vertEdge:(CGFloat)vertEdge 32 | vertSpace:(CGFloat)vertSpace 33 | isHori:(BOOL)isHori 34 | layoutClass:(Class)layoutClass { 35 | UICollectionViewFlowLayout *layout = [[layoutClass alloc] init]; 36 | if (isHori) { 37 | layout.scrollDirection = UICollectionViewScrollDirectionHorizontal; 38 | layout.minimumInteritemSpacing = vertSpace; 39 | layout.minimumLineSpacing = horiSpace; 40 | } else { 41 | layout.scrollDirection = UICollectionViewScrollDirectionVertical; 42 | layout.minimumInteritemSpacing = horiSpace; 43 | layout.minimumLineSpacing = vertSpace; 44 | } 45 | layout.itemSize = itemSize; 46 | layout.sectionInset = UIEdgeInsetsMake(vertEdge, horiEdge, vertEdge, horiEdge); 47 | UICollectionView *collection = [[self alloc] initWithFrame:frame collectionViewLayout:layout]; 48 | collection.userInteractionEnabled = YES; 49 | collection.bounces = NO; 50 | collection.showsHorizontalScrollIndicator = NO; 51 | collection.showsVerticalScrollIndicator = NO; 52 | collection.decelerationRate = UIScrollViewDecelerationRateNormal; 53 | collection.backgroundColor = [UIColor clearColor]; 54 | return collection; 55 | } 56 | @end 57 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/categories/UIColor+ET.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+ET.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/14. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface UIColor (ET) 14 | 15 | + (UIColor *)et_randomColorWithBrightness:(float)brightness; 16 | 17 | + (UIColor *)et_randomColor; 18 | 19 | + (UIColor *)et_bgColorWithHue:(float)hue; 20 | 21 | + (UIColor *)et_colorWithHexStr:(NSString *)hexStr; 22 | 23 | @end 24 | 25 | NS_ASSUME_NONNULL_END 26 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/categories/UIColor+ET.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+ET.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/14. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "UIColor+ET.h" 10 | 11 | @implementation UIColor (ET) 12 | 13 | + (UIColor *)et_randomColorWithBrightness:(float)brightness { 14 | return [UIColor colorWithHue:drand48() saturation:1.0 brightness:brightness alpha:1.0]; 15 | } 16 | 17 | + (UIColor *)et_randomColor { 18 | return [UIColor colorWithHue:drand48() saturation:1.0 brightness:0.5 alpha:1.0]; 19 | } 20 | 21 | + (UIColor *)et_bgColorWithHue:(float)hue { 22 | return [UIColor colorWithHue:hue saturation:1.0 brightness:0.5 alpha:1]; 23 | } 24 | 25 | + (UIColor *)et_colorWithHexStr:(NSString *)hexStr { 26 | if ([hexStr hasPrefix:@"#"]) { 27 | hexStr = [hexStr stringByReplacingOccurrencesOfString:@"#" withString:@""]; 28 | } 29 | 30 | if (hexStr.length == 3) { 31 | NSUInteger value = 0; 32 | if (sscanf(hexStr.UTF8String, "%tx", &value)) { 33 | NSUInteger r, g, b; 34 | r = (value & 0x0f00) >> 8; 35 | g = (value & 0x00f0) >> 4; 36 | b = (value & 0x000f) >> 0; 37 | return [UIColor colorWithRed:1.f * (r) / 0x0f 38 | green:1.f * (g) / 0x0f 39 | blue:1.f * (b) / 0x0f 40 | alpha:1]; 41 | } 42 | return nil; 43 | } 44 | else if (hexStr.length == 6) { 45 | NSUInteger value = 0; 46 | if (sscanf(hexStr.UTF8String, "%tx", &value)) { 47 | return [UIColor colorWithRed:1.f * (value >> 16 & 0xff) / 0xff 48 | green:1.f * (value >> 8 & 0xff) / 0xff 49 | blue:1.f * (value >> 0 & 0xff) / 0xff 50 | alpha:1]; 51 | } 52 | return nil; 53 | } 54 | else { 55 | return nil; 56 | } 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/categories/UITableView+ETDemo.h: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+ETDemo.h 3 | // ETDemo 4 | // 5 | // Created by xxq on 2022/4/13. 6 | // 7 | 8 | #import 9 | 10 | NS_ASSUME_NONNULL_BEGIN 11 | 12 | /// 提供一些快速创建 tableview 的工厂方法 13 | @interface UITableView (ETDemo) 14 | 15 | /// 内部调用的底部方法,缺省一些参数 16 | /// @param provider tableView 的 delegate & datasource 17 | /// @param bgColor 背景色 18 | /// @param contentInset 边距 19 | /* 20 | [self et_demo_tableViewWithProvider:provider 21 | bgColor:bgColor 22 | separatorStyle:UITableViewCellSeparatorStyleNone 23 | contentInset:contentInset 24 | useSysFitSafeArea:NO 25 | adaptIOS11:YES]; 26 | */ 27 | + (instancetype)et_demo_tableViewWithProvider:(id)provider 28 | bgColor:(UIColor *)bgColor 29 | contentInset:(UIEdgeInsets)contentInset; 30 | 31 | /// 创建tableView 32 | /// @param provider tableView 的 delegate & datasource 33 | /// @param bgColor 背景色 34 | /// @param separatorStyle 分割线 35 | /// @param contentInset 边距 36 | /// @param useSysFitSafeArea 是否使用系统的安全边距适配,默认NO 37 | /// @param adaptIOS11 是否适配 iOS11,默认 YES 38 | + (instancetype)et_demo_tableViewWithProvider:(id)provider 39 | bgColor:(UIColor *)bgColor 40 | separatorStyle:(UITableViewCellSeparatorStyle)separatorStyle 41 | contentInset:(UIEdgeInsets)contentInset 42 | useSysFitSafeArea:(BOOL)useSysFitSafeArea 43 | adaptIOS11:(BOOL)adaptIOS11; 44 | 45 | @end 46 | 47 | NS_ASSUME_NONNULL_END 48 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/categories/UITableView+ETDemo.m: -------------------------------------------------------------------------------- 1 | // 2 | // UITableView+ETDemo.m 3 | // ETDemo 4 | // 5 | // Created by xxq on 2022/4/13. 6 | // 7 | 8 | #import "UITableView+ETDemo.h" 9 | 10 | @implementation UITableView (ETDemo) 11 | 12 | + (instancetype)et_demo_tableViewWithProvider:(id)provider 13 | bgColor:(UIColor *)bgColor 14 | contentInset:(UIEdgeInsets)contentInset { 15 | return 16 | [self et_demo_tableViewWithProvider:provider 17 | bgColor:bgColor 18 | separatorStyle:UITableViewCellSeparatorStyleNone 19 | contentInset:contentInset 20 | useSysFitSafeArea:NO 21 | adaptIOS11:YES]; 22 | } 23 | + (instancetype)et_demo_tableViewWithProvider:(id)provider 24 | bgColor:(UIColor *)bgColor 25 | separatorStyle:(UITableViewCellSeparatorStyle)separatorStyle 26 | contentInset:(UIEdgeInsets)contentInset 27 | useSysFitSafeArea:(BOOL)useSysFitSafeArea 28 | adaptIOS11:(BOOL)adaptIOS11 { 29 | UITableView *tableView = [[UITableView alloc] init]; 30 | tableView.delegate = provider; 31 | tableView.dataSource = provider; 32 | tableView.backgroundColor = bgColor; 33 | tableView.tableFooterView = [[UIView alloc] init]; 34 | tableView.separatorStyle = separatorStyle; 35 | tableView.contentInset = contentInset; 36 | 37 | if (@available(iOS 11.0, *)) { 38 | tableView.insetsContentViewsToSafeArea = useSysFitSafeArea; 39 | if (adaptIOS11) { 40 | [tableView et_demo_adaptediOS11AdjustmentBehavior:UIScrollViewContentInsetAdjustmentNever]; 41 | } 42 | } else { 43 | // Fallback on earlier versions 44 | } // 关闭系统自带的安全区域适配 45 | return tableView; 46 | } 47 | 48 | - (void)et_demo_adaptediOS11AdjustmentBehavior:(UIScrollViewContentInsetAdjustmentBehavior)behavior API_AVAILABLE(ios(11.0)) { 49 | self.estimatedRowHeight = 0; 50 | self.estimatedSectionHeaderHeight = 0; 51 | self.estimatedSectionFooterHeight = 0; 52 | if ([self respondsToSelector:@selector(contentInsetAdjustmentBehavior)]) { 53 | if (@available(iOS 11.0, *)) { 54 | self.contentInsetAdjustmentBehavior = behavior; 55 | } 56 | } 57 | } 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Alert/ETAlertViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETAlertViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/15. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETAlertViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Cell/ETMainTestCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETMainTestCell.h 3 | // NEMemoryDetect_Example 4 | // 5 | // Created by xxq on 2022/6/2. 6 | // Copyright © 2022 netease_music. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ETMainTestCellItem.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface ETMainTestCell : UITableViewCell 15 | @property (nonatomic, strong) UILabel *contentLabel; 16 | @property (nonatomic, strong) ETMainTestCellItem *item; 17 | 18 | - (void)configWithItem:(ETMainTestCellItem *)item; 19 | @end 20 | 21 | NS_ASSUME_NONNULL_END 22 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Cell/ETMainTestCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETMainTestCell.m 3 | // NEMemoryDetect_Example 4 | // 5 | // Created by xxq on 2022/6/2. 6 | // Copyright © 2022 netease_music. All rights reserved. 7 | // 8 | 9 | #import "ETMainTestCell.h" 10 | #import 11 | 12 | @implementation ETMainTestCell 13 | 14 | - (void)awakeFromNib { 15 | [super awakeFromNib]; 16 | } 17 | 18 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 19 | [super setSelected:selected animated:animated]; 20 | } 21 | 22 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 23 | if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 24 | _contentLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, 5, self.bounds.size.width - 20, self.bounds.size.height - 10)]; 25 | _contentLabel.backgroundColor = [UIColor et_colorWithHexStr:@"#4895ef"]; 26 | _contentLabel.font = [UIFont systemFontOfSize:20]; 27 | _contentLabel.textColor = [UIColor whiteColor]; 28 | _contentLabel.textAlignment = NSTextAlignmentCenter; 29 | _contentLabel.layer.masksToBounds = YES; 30 | _contentLabel.layer.cornerRadius = 6; 31 | [self.contentView addSubview:_contentLabel]; 32 | [_contentLabel mas_makeConstraints:^(MASConstraintMaker *make) { 33 | make.center.equalTo(self.contentView); 34 | make.left.equalTo(self.contentView).offset(20); 35 | make.top.equalTo(self.contentView).offset(6); 36 | }]; 37 | 38 | [[NEEventTracingBuilder view:self elementId:@"TableCell"] build:^(id _Nonnull builder) { 39 | builder.params.set(@"cell_key", @"cell_val_456"); 40 | }]; 41 | } 42 | return self; 43 | } 44 | 45 | - (void)configWithItem:(ETMainTestCellItem *)item { 46 | self.item = item; 47 | _contentLabel.text = item.title; 48 | 49 | [self ne_etb_build:^(id _Nonnull builder) { 50 | builder.bindDataForReuse(item) 51 | .params 52 | .set(@"title", item.title ?: @""); 53 | }]; 54 | } 55 | 56 | - (void)ne_etb_makeDynamicParams:(id)builder { 57 | NSString *title1 = self.item.title; 58 | NSString *title2 = [self.ne_et_currentVTreeNode.nodeParams objectForKey:@"title"]; 59 | if (title1 && title2 && ![title1 isEqualToString:title2]) { 60 | NSLog(@"title not equal"); 61 | } 62 | 63 | builder.set(@"d_title", self.item.title); 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Cell/ETMainTestCellItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETMainTestCellItem.h 3 | // NEMemoryDetect_Example 4 | // 5 | // Created by xxq on 2022/6/2. 6 | // Copyright © 2022 netease_music. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETMainTestCellItem : NSObject 14 | @property (nonatomic, copy) NSString *title; 15 | @property (nonatomic, weak) id target; 16 | @property (nonatomic, assign) SEL action; 17 | 18 | + (instancetype)itemWithTitle:(NSString *)title target:(nullable id)target action:(SEL)action; 19 | @end 20 | 21 | NS_ASSUME_NONNULL_END 22 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Cell/ETMainTestCellItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETMainTestCellItem.m 3 | // NEMemoryDetect_Example 4 | // 5 | // Created by xxq on 2022/6/2. 6 | // Copyright © 2022 netease_music. All rights reserved. 7 | // 8 | 9 | #import "ETMainTestCellItem.h" 10 | 11 | @implementation ETMainTestCellItem 12 | + (instancetype)itemWithTitle:(NSString *)title target:(id)target action:(SEL)action { 13 | ETMainTestCellItem *item = [[ETMainTestCellItem alloc] init]; 14 | item.title = title; 15 | item.target = target; 16 | item.action = action; 17 | return item; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Cell/ETMainTestInputCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETMainTestInputCell.h 3 | // NEMemoryDetect_Example 4 | // 5 | // Created by xxq on 2022/6/3. 6 | // Copyright © 2022 netease_music. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETMainTestInputCell : UITableViewCell 14 | @property (nonatomic, strong) UITextView *inputTextView; 15 | 16 | - (void)configWithText:(NSString *)text; 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Cell/ETMainTestInputCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETMainTestInputCell.m 3 | // NEMemoryDetect_Example 4 | // 5 | // Created by xxq on 2022/6/3. 6 | // Copyright © 2022 netease_music. All rights reserved. 7 | // 8 | 9 | #import "ETMainTestInputCell.h" 10 | 11 | @implementation ETMainTestInputCell 12 | 13 | - (void)awakeFromNib { 14 | [super awakeFromNib]; 15 | // Initialization code 16 | } 17 | 18 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 19 | [super setSelected:selected animated:animated]; 20 | 21 | // Configure the view for the selected state 22 | } 23 | 24 | - (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 25 | if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { 26 | _inputTextView = [[UITextView alloc] initWithFrame:CGRectMake(10, 10, 27 | self.bounds.size.width - 20, 28 | self.bounds.size.height - 20)]; 29 | _inputTextView.layer.cornerRadius = 5; 30 | _inputTextView.layer.masksToBounds = YES; 31 | _inputTextView.backgroundColor = [UIColor lightGrayColor]; 32 | [self.contentView addSubview:_inputTextView]; 33 | [_inputTextView mas_makeConstraints:^(MASConstraintMaker *make) { 34 | make.center.equalTo(self.contentView); 35 | make.left.equalTo(self.contentView).offset(10); 36 | make.top.equalTo(self.contentView).offset(10); 37 | }]; 38 | } 39 | return self; 40 | } 41 | 42 | - (void)configWithText:(NSString *)text { 43 | _inputTextView.text = text; 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/ETHomeTableViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETHomeTableViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by xxq on 2022/12/9. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETHomeTableViewController : UIViewController 14 | @property (weak, nonatomic) IBOutlet UITableView *tableView; 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/ETTestLogicMountViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETTestLogicMountViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by xxq on 2022/12/9. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETTestLogicMountViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/ETTestLogicMountViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETTestLogicMountViewController.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by xxq on 2022/12/9. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "ETTestLogicMountViewController.h" 10 | 11 | @interface ETTestLogicMountViewController () 12 | 13 | @end 14 | 15 | @implementation ETTestLogicMountViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view. 20 | } 21 | 22 | /* 23 | #pragma mark - Navigation 24 | 25 | // In a storyboard-based application, you will often want to do a little preparation before navigation 26 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 27 | // Get the new view controller using [segue destinationViewController]. 28 | // Pass the selected object to the new view controller. 29 | } 30 | */ 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/ETTestLoginViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETTestLoginViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by xxq on 2022/12/9. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETTestLoginViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/ETTestLoginViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETTestLoginViewController.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by xxq on 2022/12/9. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "ETTestLoginViewController.h" 10 | 11 | @interface ETTestLoginViewController () 12 | 13 | @end 14 | 15 | @implementation ETTestLoginViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view. 20 | } 21 | 22 | /* 23 | #pragma mark - Navigation 24 | 25 | // In a storyboard-based application, you will often want to do a little preparation before navigation 26 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 27 | // Get the new view controller using [segue destinationViewController]. 28 | // Pass the selected object to the new view controller. 29 | } 30 | */ 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Event/ETEventViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETEventViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/14. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETEventViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Impress/ETAutoImpressController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETAutoImpressController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by xxq on 2022/12/12. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETAutoImpressController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Logout/ETLogoutViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETLogoutViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/14. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETLogoutViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Mount/ETMountViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETMountViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by 熊勋泉 on 2022/12/14. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETMountViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Params/ETHomeParamsViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETHomeParamsViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/14. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETHomeParamsViewController : ETBaseViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/QRCode/ETQRCodeScanViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETQRCodeScanViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by 熊勋泉 on 2023/1/4. 6 | // Copyright © 2023 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETQRCodeScanViewController : UIViewController 14 | @property (nonatomic, copy) void(^didFinishScanBlk)(NSString * text); 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Refer/ETBridgeViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETBridgeViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by 熊勋泉 on 2022/12/16. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "ETReferViewController.h" 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETBridgeViewController : ETReferViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Refer/ETBridgeViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETBridgeViewController.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by 熊勋泉 on 2022/12/16. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "ETBridgeViewController.h" 10 | #import 11 | 12 | @interface ETBridgeViewController () 13 | 14 | @end 15 | 16 | @implementation ETBridgeViewController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | self.title = [NSString stringWithFormat:@"曙光-[不参与]链路追踪-%@层", @(self.depth+1)]; 21 | 22 | [[NEEventTracingBuilder viewController:self pageId:[@"bridge_page" stringByAppendingFormat:@"_%@", @(self.depth)]] build:^(id _Nonnull builder) { 23 | //builder.doNotParticipateMultirefer(YES); 24 | }]; 25 | 26 | [NEEventTracingBuilder view:self.pushVCBtn elementId:@"bridge_push_btn"]; 27 | [NEEventTracingBuilder view:self.presentVCBtn elementId:@"bridge_present_btn"]; 28 | [NEEventTracingBuilder view:self.exitBtn elementId:@"bridge_exit_btn"]; 29 | [NEEventTracingBuilder view:self.pushBridgeVCBtn elementId:@"bridge_push_bridge_btn"]; 30 | 31 | /// 下面的节点不参与 multirefer(链路追踪) 32 | /// 因此从下面按钮点击出去的事件表现为:有ec事件产生,后续的 multirefers 里无此节点 33 | /// multirefers 会降级到根节点,即 bridge_page_xx 34 | self.pushVCBtn.ne_et_psreferMute = YES; 35 | self.presentVCBtn.ne_et_psreferMute = YES; 36 | self.exitBtn.ne_et_psreferMute = YES; 37 | self.pushBridgeVCBtn.ne_et_psreferMute = YES; 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Refer/ETReferViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETReferViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by 熊勋泉 on 2022/12/15. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETReferViewController : UIViewController 14 | @property (nonatomic, assign, readonly) NSInteger depth; 15 | 16 | @property (nonatomic, strong, readonly) UIButton * pushVCBtn; 17 | @property (nonatomic, strong, readonly) UIButton * presentVCBtn; 18 | @property (nonatomic, strong, readonly) UIButton * exitBtn; 19 | @property (nonatomic, strong, readonly) UIButton * pushBridgeVCBtn; 20 | 21 | - (instancetype)initWithDepth:(NSInteger)depth; 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_1/Visible/ETVisibleViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETVisibleViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/14. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETVisibleViewController : UIViewController 14 | 15 | @end 16 | 17 | NS_ASSUME_NONNULL_END 18 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_2/ETHomeCollectionViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETHomeCollectionViewCell.h 3 | // EventTracing_Example 4 | // 5 | // Created by dl on 2021/4/1. 6 | // Copyright © 2021 ShakeShakeMe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETHomeCollectionViewCell : UICollectionViewCell 14 | @property(nonatomic, strong) UILabel *titleLabel; 15 | 16 | - (void) refreshWithData:(NSDictionary *)data; 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_2/ETHomeCollectionViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETHomeCollectionViewCell.m 3 | // EventTracing_Example 4 | // 5 | // Created by dl on 2021/4/1. 6 | // Copyright © 2021 ShakeShakeMe. All rights reserved. 7 | // 8 | 9 | #import "ETHomeCollectionViewCell.h" 10 | #import 11 | 12 | @interface ETHomeCollectionViewCell () 13 | @property(nonatomic, strong) NSDictionary *data; 14 | @end 15 | 16 | @implementation ETHomeCollectionViewCell 17 | - (instancetype)initWithFrame:(CGRect)frame { 18 | self = [super initWithFrame:frame]; 19 | if (self) { 20 | self.titleLabel = [[UILabel alloc] init]; 21 | self.titleLabel.font = [UIFont systemFontOfSize:15]; 22 | self.titleLabel.textAlignment = NSTextAlignmentCenter; 23 | [self.contentView addSubview:self.titleLabel]; 24 | 25 | [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) { 26 | make.edges.equalTo(self.contentView); 27 | }]; 28 | 29 | [[NEEventTracingBuilder view:self elementId:@"CollectionCell"] build:^(id _Nonnull builder) { 30 | builder.params.set(@"cell_key", @"cell_val_123"); 31 | }]; 32 | } 33 | return self; 34 | } 35 | 36 | - (void)refreshWithData:(NSDictionary *)data { 37 | self.data = data; 38 | 39 | self.contentView.backgroundColor = [data objectForKey:@"color"]; 40 | self.titleLabel.text = [data objectForKey:@"idx"]; 41 | 42 | [self ne_etb_build:^(id _Nonnull builder) { 43 | builder.bindDataForReuse(data) 44 | .params 45 | .set(@"idx", [data objectForKey:@"idx"]); 46 | }]; 47 | } 48 | 49 | - (void)ne_etb_makeDynamicParams:(id)builder { 50 | builder.set(@"d_idx", [self.data objectForKey:@"idx"]); 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/Native/tab_page_2/ETHomeCollectionViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ETHomeCollectionViewController.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by xxq on 2022/12/9. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface ETHomeCollectionViewController : UIViewController 14 | @property (weak, nonatomic) IBOutlet UICollectionView *collectionView; 15 | 16 | @end 17 | 18 | NS_ASSUME_NONNULL_END 19 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/TestUtils/EventTracingTestLogComing.h: -------------------------------------------------------------------------------- 1 | // 2 | // EventTracingTestLogComing.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/13. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "ETWebView.h" 12 | 13 | NS_ASSUME_NONNULL_BEGIN 14 | 15 | @interface NEEventTracingVTree (UITest_LogComing) 16 | @property(nonatomic, assign) BOOL hasChangesToLastVTree; 17 | @end 18 | 19 | @class EventTracingTestLogComing; 20 | FOUNDATION_EXTERN NSArray *EventTracingAllTestLogComings(void); 21 | FOUNDATION_EXTERN EventTracingTestLogComing *EventTracingTestLogComingForKey(NSString *key); 22 | __attribute__((overloadable)) 23 | FOUNDATION_EXTERN void EventTracingEnumateAllLogComings(void (NS_NOESCAPE ^block)(EventTracingTestLogComing *logComing, NSUInteger idx, BOOL *stop)); 24 | FOUNDATION_EXTERN void EventTracingEnumateAllLogComings(SEL delegateSEL, void (NS_NOESCAPE ^block)(EventTracingTestLogComing *logComing, id delegate, NSUInteger idx, BOOL *stop)); 25 | 26 | FOUNDATION_EXTERN NSString * EventTracingDescForEvent(NSString * event); 27 | 28 | @protocol EventTracingTestLogComingDelegate 29 | /// MARK: 生成一次 VTree 并产生日志 级别,回调一次 30 | @optional 31 | - (void)logComing:(EventTracingTestLogComing *)logComing 32 | didOutputLogJsons:(NSArray *)logJsons 33 | atVTreeGenerateLevel:(NEEventTracingVTree *)VTree; 34 | @end 35 | 36 | @interface EventTracingTestLogComing : NSObject 37 | 38 | @property(nonatomic, copy, readonly) NSString *key; 39 | @property(nonatomic, strong, readonly) NSArray *logJsons; 40 | @property(nonatomic, strong, readonly) NSArray *VTrees; 41 | @property(nonatomic, strong, readonly) NEEventTracingVTree *lastVTree; 42 | 43 | @property(nonatomic, weak) id delegate; 44 | 45 | /// MARK: Alert 46 | @property(nonatomic, copy, readonly) NSDictionary *alertActionClickCountMap; 47 | 48 | /// MARK: current showing H5 49 | @property(nonatomic, weak, readonly) ETWebView *currentShowingWebView; 50 | 51 | // ### 公参 ### 52 | @property(nonatomic, assign) NSInteger publicDynamicParamsCallCount; 53 | 54 | + (instancetype)logComingWithKey:(NSString *)key; 55 | + (instancetype)logComingWithRandomKey; 56 | 57 | - (void)addLogJson:(NSDictionary *)logJson; 58 | - (void)addVTree:(NEEventTracingVTree *)VTree; 59 | 60 | - (void)alertController:(NSString *)pageId didClickActionWithElementId:(NSString *)elementId position:(NSUInteger)position; 61 | - (void)webViewDidShow:(ETWebView *)webView; 62 | 63 | - (NSArray *)fetchJsonLogsForEvent:(NSString *)event spm:(NSString *)spm; 64 | - (NSArray *)fetchJsonLogsForEvent:(NSString *)event spm:(NSString *)spm hasParaKey:(NSString *)paraKey isPage:(BOOL)isPage; 65 | - (NSDictionary *)fetchLastJsonLogForEvent:(NSString *)event spm:(NSString *)spm; 66 | - (NSDictionary *)fetchLastJsonLogForEvent:(NSString *)event oid:(NSString *)oid; 67 | 68 | - (NSDictionary *)fetchLastJsonLogForEvent:(NSString *)event; 69 | 70 | - (NSString *)fetchValueForEvent:(NSString *)event spm:(NSString *)spm key:(NSString *)key; 71 | - (NSArray *)fetchMultirefersForEvent:(NSString *)event spm:(NSString *)spm; 72 | - (NSDictionary *)fetchPageInfoForEvent:(NSString *)event spm:(NSString *)spm oid:(NSString *)oid; 73 | - (NSString *)fetchPageInfoValueForEvent:(NSString *)event spm:(NSString *)spm oid:(NSString *)oid key:(NSString *)key; 74 | 75 | @end 76 | 77 | NS_ASSUME_NONNULL_END 78 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/EventTracing-iOS/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // EventTracing-iOS 4 | // 5 | // Created by 9446796 on 11/29/2021. 6 | // Copyright (c) 2021 9446796. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "NEAppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) 13 | { 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([NEAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Example/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | gem "fastlane" 3 | gem "cocoapods", '1.10.0' 4 | gem 'rest-client', '2.1.0' 5 | gem 'mail', '2.7.1' 6 | gem 'json', '2.3.1' 7 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | platform :ios, '11.0' 4 | 5 | workspace 'EventTracing-iOS.xcworkspace' 6 | project 'EventTracing-iOS.xcodeproj' 7 | 8 | target 'EventTracing-iOS_Example' do 9 | pod 'EventTracing', '~> 2.0.0' #, :path => '../' 10 | pod 'EventTracing-iOS-Debug', '~> 1.0.2' #, :path => '../../EventTracing-iOS-Debug' 11 | pod 'EventTracing-iOS-LogViewer', '~> 1.0.0' #, :path => '../../EventTracing-iOS-LogViewer' 12 | pod 'libextobjc' 13 | # pod 'LookinServer' 14 | 15 | target 'EventTracing-iOS_Tests' do 16 | inherit! :search_paths 17 | pod 'KIF', :configurations => ['Debug'] 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /Example/Tests/ETEventTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETEventTests.m 3 | // EventTracing-iOS_Tests 4 | // 5 | // Created by 熊勋泉 on 2022/12/19. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "EventTracingDefines.h" 11 | 12 | @interface ETEventTests : KIFTestCase 13 | 14 | @end 15 | 16 | @implementation ETEventTests 17 | 18 | - (void)beforeAll { 19 | [tester tapViewWithAccessibilityLabel:@"Home"]; 20 | } 21 | 22 | - (void)setUp { 23 | self.continueAfterFailure = NO; 24 | } 25 | 26 | - (void)afterAll { 27 | [tester tapViewWithAccessibilityLabel:@"Home"]; 28 | } 29 | 30 | - (void)testEvents { 31 | EventTracingTestLogComing *logComing = [EventTracingTestLogComing logComingWithRandomKey]; 32 | [tester ne_et_asyncTapViewWithAccessibilityLabel:@"事件测试"]; 33 | 34 | NE_ET_Test_WaitForTimeAtVTreeGenerateWithCondition(3, logComing, ^BOOL(EventTracingTestLogComing * _Nonnull logComing) { 35 | return [logComing fetchJsonLogsForEvent:NE_ET_EVENT_ID_E_CLCK spm:@"TableCell:5|mod_list_table|mod_virtual_parent_of_table|mod_list_page"].count > 0; 36 | }); 37 | 38 | // 按钮点击,自动ec 39 | XCTAssertTrue([logComing fetchJsonLogsForEvent:NE_ET_EVENT_ID_E_CLCK spm:@"button|event_test_page"].count == 0); 40 | [tester tapViewWithAccessibilityLabel:@"按钮点击"]; 41 | XCTAssertTrue([logComing fetchJsonLogsForEvent:NE_ET_EVENT_ID_E_CLCK spm:@"button|event_test_page"].count == 1); 42 | 43 | // 手势点击,自动ec 44 | XCTAssertTrue([logComing fetchJsonLogsForEvent:NE_ET_EVENT_ID_E_CLCK spm:@"label_1|event_test_page"].count == 0); 45 | [tester tapViewWithAccessibilityLabel:@"手势点击,自动ec"]; 46 | XCTAssertTrue([logComing fetchJsonLogsForEvent:NE_ET_EVENT_ID_E_CLCK spm:@"label_1|event_test_page"].count == 1); 47 | 48 | // 手势点击,手动ec 49 | XCTAssertTrue([logComing fetchJsonLogsForEvent:NE_ET_EVENT_ID_E_CLCK spm:@"label_2|event_test_page"].count == 0); 50 | [tester tapViewWithAccessibilityLabel:@"手势点击,手动ec"]; 51 | XCTAssertTrue([logComing fetchJsonLogsForEvent:NE_ET_EVENT_ID_E_CLCK spm:@"label_2|event_test_page"].count == 1); 52 | 53 | // 手动事件,无链路追踪 54 | XCTAssertTrue([logComing fetchLastJsonLogForEvent:@"manual_ec"].count == 0); 55 | [tester tapViewWithAccessibilityLabel:@"手动事件,无链路追踪"]; 56 | XCTAssertTrue([logComing fetchLastJsonLogForEvent:@"manual_ec"].count > 0); 57 | 58 | // 手动事件,参与链路追踪 59 | XCTAssertTrue([logComing fetchJsonLogsForEvent:@"manual_ec_2" spm:@"custom_label|event_test_page"].count == 0); 60 | [tester tapViewWithAccessibilityLabel:@"手动事件,参与链路追踪"]; 61 | XCTAssertTrue([logComing fetchJsonLogsForEvent:@"manual_ec_2" spm:@"custom_label|event_test_page"].count == 1); 62 | NSArray * multirefers = [logComing fetchMultirefersForEvent:NE_ET_EVENT_ID_P_VIEW spm:@"refer_page_0"]; 63 | XCTAssertTrue(multirefers.count > 0); 64 | // 链路追踪验证 65 | XCTAssertTrue([NE_ET_FormattedReferParseFromReferString(multirefers.firstObject).spm isEqualToString:@"custom_label|event_test_page"]); 66 | } 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /Example/Tests/ETH5Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ETH5Tests.m 3 | // EventTracing-iOS_Tests 4 | // 5 | // Created by dl on 2022/12/28. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "EventTracingDefines.h" 11 | 12 | @interface ETH5Tests : KIFTestCase 13 | @end 14 | 15 | @implementation ETH5Tests 16 | 17 | - (void)setUp { 18 | self.continueAfterFailure = NO; 19 | } 20 | 21 | - (void)afterAll { 22 | [tester tapViewWithAccessibilityLabel:@"Home"]; 23 | } 24 | 25 | - (void)afterEach { 26 | [tester tapViewWithAccessibilityLabel:@"Home"]; 27 | } 28 | 29 | - (void)testExample { 30 | EventTracingTestLogComing *logComing = [EventTracingTestLogComing logComingWithRandomKey]; 31 | [tester tapViewWithAccessibilityLabel:@"H5 页"]; 32 | 33 | NE_ET_Test_WaitForTime(0.5); 34 | // NSString *script = [NSString stringWithFormat:@"document.querySelector('#btn_check_avaiable').dispatchEvent(new MouseEvent('mousedown', {}))"]; 35 | NSString *script = [NSString stringWithFormat:@"simulate_click('btn_check_avaiable')"]; 36 | [[logComing currentShowingWebView] evaluateJavaScript:script]; 37 | 38 | NE_ET_Test_WaitForTime(0.5); 39 | script = [NSString stringWithFormat:@"simulate_click('btn_et_test')"]; 40 | [[logComing currentShowingWebView] evaluateJavaScript:script]; 41 | 42 | NE_ET_Test_WaitForTime(0.5); 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Example/Tests/EventTracingDefines.h: -------------------------------------------------------------------------------- 1 | // 2 | // EventTracingDefines.h 3 | // EventTracing-iOS 4 | // 5 | // Created by dl on 2022/12/14. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #ifndef EventTracingDefines_h 10 | #define EventTracingDefines_h 11 | 12 | #import 13 | #import 14 | #import 15 | #import "KIFUITestActor+NE_ET_Extra.h" 16 | 17 | #import 18 | #import 19 | 20 | #import 21 | #import 22 | 23 | #import "EventTracingTestUsefullFuncs.h" 24 | #import "EventTracingTestLogComing.h" 25 | #import "NSMutableArray+NE_ET_Extra.h" 26 | 27 | #endif /* EventTracingDefines_h */ 28 | -------------------------------------------------------------------------------- /Example/Tests/EventTracingTestUsefullFuncs.h: -------------------------------------------------------------------------------- 1 | // 2 | // EventTracingTestUsefullFuncs.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/13. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "EventTracingTestLogComing.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | @class XCTestExpectation; 14 | typedef void(^NE_ET_Test_Wait_ExecBlock)(XCTestExpectation *expectation); 15 | typedef BOOL(^NE_ET_Test_Wait_AtVTreeGenerateConditionBlock)(EventTracingTestLogComing *logComing); 16 | 17 | FOUNDATION_EXTERN void NE_ET_Test_WaitForTimeExecBlock(NSTimeInterval timeout, NE_ET_Test_Wait_ExecBlock execBlock); 18 | FOUNDATION_EXTERN void NE_ET_Test_WaitForTime(NSTimeInterval timeout); 19 | 20 | /// MARK: 以下都是基于上述俩进行的扩展 21 | __attribute__((overloadable)) 22 | FOUNDATION_EXTERN void NE_ET_Test_WaitForTimeAtVTreeGenerateWithCondition(NSTimeInterval timeout, 23 | NE_ET_Test_Wait_AtVTreeGenerateConditionBlock condition); 24 | 25 | FOUNDATION_EXTERN void NE_ET_Test_WaitForTimeAtVTreeGenerateWithCondition(NSTimeInterval timeout, 26 | EventTracingTestLogComing *logComing, 27 | NE_ET_Test_Wait_AtVTreeGenerateConditionBlock condition); 28 | 29 | NS_ASSUME_NONNULL_END 30 | -------------------------------------------------------------------------------- /Example/Tests/EventTracingTestUsefullFuncs.m: -------------------------------------------------------------------------------- 1 | // 2 | // EventTracingTestUsefullFuncs.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/13. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "EventTracingTestUsefullFuncs.h" 10 | #import 11 | #import 12 | #import 13 | 14 | void NE_ET_Test_WaitForTimeExecBlock(NSTimeInterval timeout, NE_ET_Test_Wait_ExecBlock execBlock) { 15 | XCTestExpectation *expectation = [[XCTestExpectation alloc] init]; 16 | expectation.inverted = YES; 17 | !execBlock ?: execBlock(expectation); 18 | XCTWaiterResult result = [[[XCTWaiter alloc] init] waitForExpectations:@[expectation] timeout:timeout]; 19 | XCTAssertTrue(result == XCTWaiterResultInvertedFulfillment); 20 | } 21 | 22 | void NE_ET_Test_WaitForTime(NSTimeInterval timeout) { 23 | XCTestExpectation *expectation = [[XCTestExpectation alloc] init]; 24 | expectation.inverted = YES; 25 | XCTWaiterResult result = [[[XCTWaiter alloc] init] waitForExpectations:@[expectation] timeout:timeout]; 26 | XCTAssertTrue(result == XCTWaiterResultCompleted); 27 | } 28 | 29 | __attribute__((overloadable)) 30 | void NE_ET_Test_WaitForTimeAtVTreeGenerateWithCondition(NSTimeInterval timeout, NE_ET_Test_Wait_AtVTreeGenerateConditionBlock condition) { 31 | EventTracingTestLogComing *logComing = [EventTracingTestLogComing logComingWithRandomKey]; 32 | NE_ET_Test_WaitForTimeAtVTreeGenerateWithCondition(timeout, logComing, condition); 33 | } 34 | 35 | void NE_ET_Test_WaitForTimeAtVTreeGenerateWithCondition(NSTimeInterval timeout, 36 | EventTracingTestLogComing *logComing, 37 | NE_ET_Test_Wait_AtVTreeGenerateConditionBlock condition) { 38 | NE_ET_Test_WaitForTimeExecBlock(timeout, ^(XCTestExpectation * _Nonnull expectation) { 39 | [[logComing bk_dynamicDelegateForProtocol:@protocol(EventTracingTestLogComingDelegate)] 40 | implementMethod:@selector(logComing:didOutputLogJsons:atVTreeGenerateLevel:) 41 | withBlock:^(EventTracingTestLogComing *logComing, NSArray *logJsons, NEEventTracingVTree *VTree) { 42 | if (condition && condition(logComing)) { 43 | [expectation fulfill]; 44 | } 45 | }]; 46 | }); 47 | } 48 | -------------------------------------------------------------------------------- /Example/Tests/KIFUITestActor+ET_Extra.h: -------------------------------------------------------------------------------- 1 | // 2 | // KIFUITestActor+NE_ET_Extra.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/14. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | @interface KIFUITestActor (NE_ET_Extra) 15 | 16 | - (BOOL)et_tryQuickFindingViewWithAccessibilityLabel:(NSString *)label; 17 | - (BOOL)et_tryFindingViewWithAccessibilityLabel:(NSString *)label timeout:(NSTimeInterval)timeout; 18 | - (BOOL)et_tryFindingViewWithAccessibilityLabel:(NSString *)label timeout:(NSTimeInterval)timeout tappable:(BOOL)tappable; 19 | 20 | - (void)et_asyncTapViewWithAccessibilityLabel:(NSString *)label; 21 | 22 | @end 23 | 24 | NS_ASSUME_NONNULL_END 25 | -------------------------------------------------------------------------------- /Example/Tests/KIFUITestActor+ET_Extra.m: -------------------------------------------------------------------------------- 1 | // 2 | // KIFUITestActor+NE_ET_Extra.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by dl on 2022/12/14. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "KIFUITestActor+NE_ET_Extra.h" 10 | 11 | @implementation KIFUITestActor (NE_ET_Extra) 12 | 13 | - (BOOL)et_tryQuickFindingViewWithAccessibilityLabel:(NSString *)label { 14 | return [self ne_et_tryFindingViewWithAccessibilityLabel:label timeout:0.05]; 15 | } 16 | 17 | - (BOOL)et_tryFindingViewWithAccessibilityLabel:(NSString *)label timeout:(NSTimeInterval)timeout { 18 | return [self ne_et_tryFindingViewWithAccessibilityLabel:label timeout:timeout tappable:NO]; 19 | } 20 | 21 | - (BOOL)et_tryFindingViewWithAccessibilityLabel:(NSString *)label timeout:(NSTimeInterval)timeout tappable:(BOOL)tappable { 22 | return [tester tryRunningBlock:^KIFTestStepResult(NSError *__autoreleasing *error) { 23 | return [UIAccessibilityElement accessibilityElement:NULL view:nil withLabel:label value:nil traits:UIAccessibilityTraitNone tappable:tappable error:nil] ? KIFTestStepResultSuccess : KIFTestStepResultWait; 24 | } complete:nil timeout:timeout error:nil]; 25 | } 26 | 27 | - (void)et_asyncTapViewWithAccessibilityLabel:(NSString *)label { 28 | dispatch_async(dispatch_get_main_queue(), ^{ 29 | [self tapViewWithAccessibilityLabel:label]; 30 | }); 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Example/Tests/NSMutableArray+ET_Extra.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableArray+NE_ET_Extra.h 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by 熊勋泉 on 2022/12/16. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | 13 | @interface NSMutableArray (NE_ET_Extra) 14 | 15 | - (void)et_pushObject:(id)anObject; 16 | - (void)et_popObject; 17 | @end 18 | 19 | NS_ASSUME_NONNULL_END 20 | -------------------------------------------------------------------------------- /Example/Tests/NSMutableArray+ET_Extra.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSMutableArray+NE_ET_Extra.m 3 | // EventTracing-iOS_Example 4 | // 5 | // Created by 熊勋泉 on 2022/12/16. 6 | // Copyright © 2022 9446796. All rights reserved. 7 | // 8 | 9 | #import "NSMutableArray+NE_ET_Extra.h" 10 | #import 11 | 12 | @implementation NSMutableArray (NE_ET_Extra) 13 | 14 | - (void)et_pushObject:(id)anObject { 15 | if (!anObject) 16 | { 17 | NSLog(@"error"); 18 | } 19 | XCTAssertTrue(anObject != nil); 20 | [self insertObject:anObject atIndex:0]; 21 | } 22 | 23 | - (void)et_popObject { 24 | [self removeObjectAtIndex:0]; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // The contents of this file are implicitly included at the beginning of every test case source file. 2 | 3 | #ifdef __OBJC__ 4 | 5 | 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 曙光 iOS SDK 2 | 3 | 隶属于 https://github.com/eventtracing/dawn 项目 4 | 5 | ## Example 6 | 7 | 参见 [Demo 文档](https://eventtracing.github.io/docs/Demo/iOS) 8 | 9 | ## Use 10 | 11 | 参见 [SDK详细使用文档](https://eventtracing.github.io/docs/category/ios) 12 | 13 | ## Installation 14 | 15 | EventTracing-iOS is available through [CocoaPods](https://cocoapods.org). To install 16 | it, simply add the following line to your Podfile: 17 | 18 | ```ruby 19 | pod 'EventTracing' 20 | ``` 21 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj --------------------------------------------------------------------------------