diff --git a/.github/workflows/ci_without_report.yml b/.github/workflows/ci_without_report.yml new file mode 100644 index 000000000..a80b20c30 --- /dev/null +++ b/.github/workflows/ci_without_report.yml @@ -0,0 +1,31 @@ +name: Testing + +on: + pull_request: + workflow_dispatch: + +jobs: + build: + runs-on: macos-12 + + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Cache cocoapods + uses: actions/cache@v4 + with: + path: Pods + key: ${{ runner.os }}-pods-${{ hashFiles('**/Podfile.lock') }} + restore-keys: | + ${{ runner.os }}-pods- + + - name: Pod Install + run: cd Example && pod install && cd .. + + - name: Run tests + run: | + xcodebuild test -workspace Example/GrowingAnalytics.xcworkspace \ + -scheme GrowingAnalyticsTests \ + -testPlan GrowingAnalyticsTests \ + -destination 'platform=iOS Simulator,name=iPhone 14' diff --git a/Example/GrowingAnalyticsTests/TrackerCoreTests/SwizzleTests/GrowingSwizzleTest.m b/Example/GrowingAnalyticsTests/TrackerCoreTests/SwizzleTests/GrowingSwizzleTest.m index a44e86e22..8a7942f67 100644 --- a/Example/GrowingAnalyticsTests/TrackerCoreTests/SwizzleTests/GrowingSwizzleTest.m +++ b/Example/GrowingAnalyticsTests/TrackerCoreTests/SwizzleTests/GrowingSwizzleTest.m @@ -24,20 +24,17 @@ #import #import +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundeclared-selector" +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#pragma clang diagnostic ignored "-Wincomplete-implementation" + static NSInteger b = 0; @interface Growing_Swizzle_XCTest : NSObject - (void)instanceMethod; -- (void)instanceMethod:(NSString *)arg1; - -- (void)instanceMethod:(NSString *)arg1 arg2:(NSString *)arg2; - -- (void)instanceMethod:(NSString *)arg1 arg2:(NSString *)arg2 arg3:(NSString *)arg3; - -- (void)instanceMethod:(NSString *)arg1 arg2:(NSString *)arg2 arg3:(NSString *)arg3 arg4:(NSString *)arg4; - + (void)classMethod; @end @@ -45,27 +42,69 @@ + (void)classMethod; @implementation Growing_Swizzle_XCTest - (void)instanceMethod { - b = 1; } + (void)classMethod { - b = 2; } -- (void)instanceMethod:(NSString *)arg1 { - b = 3; -} +@end + +@interface Growing_Swizzle_XCTest_B : Growing_Swizzle_XCTest + +@end + +@implementation Growing_Swizzle_XCTest_B + +@end + +@interface Growing_Swizzle_XCTest_C : Growing_Swizzle_XCTest_B + +@end + +@implementation Growing_Swizzle_XCTest_C + +@end + +@interface Growing_Swizzle_XCTest_D : Growing_Swizzle_XCTest_B -- (void)instanceMethod:(NSString *)arg1 arg2:(NSString *)arg2 { - b = 4; +@end + +@implementation Growing_Swizzle_XCTest_D + +- (void)instanceMethod { + [super instanceMethod]; } -- (void)instanceMethod:(NSString *)arg1 arg2:(NSString *)arg2 arg3:(NSString *)arg3 { - b = 5; +@end + +@interface Growing_Swizzle_XCTest_B_2 : Growing_Swizzle_XCTest + +@end + +@implementation Growing_Swizzle_XCTest_B_2 + +@end + +@interface Growing_Swizzle_XCTest_D_2 : Growing_Swizzle_XCTest_B_2 + +@end + +@implementation Growing_Swizzle_XCTest_D_2 + +- (void)instanceMethod { + [super instanceMethod]; } -- (void)instanceMethod:(NSString *)arg1 arg2:(NSString *)arg2 arg3:(NSString *)arg3 arg4:(NSString *)arg4 { - b = 6; +@end + +@interface Growing_Swizzle_XCTest_E : Growing_Swizzle_XCTest_B + +@end + +@implementation Growing_Swizzle_XCTest_E + +- (void)instanceMethod { + } @end @@ -81,11 +120,11 @@ + (void)swizzle_classMethod; @implementation Growing_Swizzle_XCTest (XCTest) - (void)swizzle_instanceMethod { - b = 6; + b++; } + (void)swizzle_classMethod { - b = 7; + b += 2; } @end @@ -100,9 +139,6 @@ - (void)delegateSelector2; @end -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wincomplete-implementation" - @implementation Growing_Swizzle_Proxy_XCTest - (instancetype)initWithTarget:(id)target { @@ -124,8 +160,6 @@ + (BOOL)resolveInstanceMethod:(SEL)sel { @end -#pragma clang diagnostic pop - @interface Growing_Swizzle_Proxy_XCTest2 : NSProxy @property (nonatomic, weak) id target; @@ -136,9 +170,6 @@ - (void)delegateSelector; @end -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wincomplete-implementation" - @implementation Growing_Swizzle_Proxy_XCTest2 - (instancetype)initWithTarget:(id)target { @@ -152,187 +183,351 @@ - (id)forwardingTargetForSelector:(SEL)aSelector { @end -#pragma clang diagnostic pop - @interface GrowingULSwizzleTest : XCTestCase +@property (nonatomic, strong) NSMutableString *swizzleString; + @end @implementation GrowingULSwizzleTest - (void)setUp { // Put setup code here. This method is called before the invocation of each test method in the class. + self.swizzleString = @"".mutableCopy; } - (void)tearDown { // Put teardown code here. This method is called after the invocation of each test method in the class. } -- (void)test0GrowingULSwizzler { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wundeclared-selector" - { - [GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b = 8; - } - named:@"xctest"]; - - Growing_Swizzle_XCTest *test = Growing_Swizzle_XCTest.new; - [test instanceMethod]; - XCTAssertEqual(b, 8); - - [GrowingULSwizzler growing_unswizzleSelector:@selector(instanceMethod) - onClass:Growing_Swizzle_XCTest.class - named:@"xctest"]; - [test instanceMethod]; - XCTAssertEqual(b, 1); - } +- (void)generalSwizzleClass:(Class)cls selector:(SEL)sel { + __weak typeof(self) weakSelf = self; + __block NSInvocation *invocation = nil; + invocation = [cls growingul_swizzleMethod:sel withBlock:^(id obj) { + [invocation invokeWithTarget:obj]; + [weakSelf.swizzleString appendString:@"A"]; + } error:nil]; +} - { - [GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod:) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b = 9; - } - named:@"xctest"]; - - Growing_Swizzle_XCTest *test = Growing_Swizzle_XCTest.new; - [test instanceMethod:@""]; - XCTAssertEqual(b, 9); - - [GrowingULSwizzler growing_unswizzleSelector:@selector(instanceMethod:) - onClass:Growing_Swizzle_XCTest.class - named:@"xctest"]; - [test instanceMethod:@""]; - XCTAssertEqual(b, 3); - } +- (void)guSwizzleClass:(Class)cls selector:(SEL)sel key:(const void *)key mode:(GrowingULSwizzleMode)mode { + __weak typeof(self) weakSelf = self; + GrowingULSwizzleInstanceMethod(cls, + sel, + GUSWReturnType(void), + GUSWArguments(), + GUSWReplacement({ + GUSWCallOriginal(); + [weakSelf.swizzleString appendString:@"B"]; + }), mode, key); +} +- (void)test01InstanceSwizzlingInModeOncePerClassAndSuperclasses { + SEL selector = @selector(instanceMethod); + static const void *key = &key; + + // hook子类B + [self guSwizzleClass:Growing_Swizzle_XCTest_B.class + selector:selector + key:key + mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + + // 父类没有调用swizzle方法 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @""); + + // 子类正常调用swizzle方法 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_B new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"B"); + + // 子类如果没有重写,则调用用的是父类的,会调用swizzle方法 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_C new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"B"); + + // 子类如果重写且调用super,则触发1次 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_D new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"B"); + + // hook子类D + [self guSwizzleClass:Growing_Swizzle_XCTest_D.class + selector:selector + key:key + mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + + // 子类如果重写且调用super,先后hook了B和B的子类D,则触发1次;此为ModeOncePerClassAndSuperclasses的作用 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_D new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"B"); + + // 异常情况1:如果先hook子类(重写且调用super),再hook父类的话,则会触发2次 { - [GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod:arg2:) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b = 10; - } - named:@"xctest"]; - - Growing_Swizzle_XCTest *test = Growing_Swizzle_XCTest.new; - [test instanceMethod:@"" arg2:@""]; - XCTAssertEqual(b, 10); - - [GrowingULSwizzler growing_unswizzleSelector:@selector(instanceMethod:arg2:) - onClass:Growing_Swizzle_XCTest.class - named:@"xctest"]; - [test instanceMethod:@"" arg2:@""]; - XCTAssertEqual(b, 4); + [self guSwizzleClass:Growing_Swizzle_XCTest_D_2.class + selector:selector + key:key + mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + [self guSwizzleClass:Growing_Swizzle_XCTest_B_2.class + selector:selector + key:key + mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + // B_2正常调用swizzle方法 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_B_2 new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"B"); + + // D_2会触发2次;此为异常情况 + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_D_2 new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"BB"); } - + + // 异常情况2:子类如果重写且没调用super,则swizzle不生效 { - [GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod:arg2:arg3:) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b = 11; - } - named:@"xctest"]; - - Growing_Swizzle_XCTest *test = Growing_Swizzle_XCTest.new; - [test instanceMethod:@"" arg2:@"" arg3:@""]; - XCTAssertEqual(b, 11); - - [GrowingULSwizzler growing_unswizzleSelector:@selector(instanceMethod:arg2:arg3:) - onClass:Growing_Swizzle_XCTest.class - named:@"xctest"]; - [test instanceMethod:@"" arg2:@"" arg3:@""]; - XCTAssertEqual(b, 5); + self.swizzleString.string = @""; + [[Growing_Swizzle_XCTest_E new] performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @""); } +} - { - [GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b *= 2; - } - named:@"xctest"]; - [GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b *= 3; - } - named:@"xctest2"]; - - Growing_Swizzle_XCTest *test = Growing_Swizzle_XCTest.new; - [test instanceMethod]; - XCTAssertEqual(b, 6); - - ((void (*)(id, SEL, SEL, Class))objc_msgSend)(GrowingULSwizzler.class, - @selector(growing_unswizzleSelector:onClass:), - @selector(instanceMethod), - Growing_Swizzle_XCTest.class); - [test instanceMethod]; - XCTAssertEqual(b, 1); +- (void)test02ClassSwizzling { + Class cls = Growing_Swizzle_XCTest_B.class; + SEL selector = @selector(classMethod); + __block NSMutableString *swizzleString = self.swizzleString; + + // hook子类B + GrowingULSwizzleClassMethod(cls, + selector, + GUSWReturnType(void), + GUSWArguments(), + GUSWReplacement({ + GUSWCallOriginal(); + [swizzleString appendString:@"B"]; + })); + + // 父类没有调用swizzle方法 + self.swizzleString.string = @""; + [Growing_Swizzle_XCTest classMethod]; + XCTAssertEqualObjects(self.swizzleString, @""); + + // 子类正常调用swizzle方法 + self.swizzleString.string = @""; + [Growing_Swizzle_XCTest_B classMethod]; + XCTAssertEqualObjects(self.swizzleString, @"B"); + + // 子类如果没有重写,则调用用的是父类的,会调用swizzle方法 + self.swizzleString.string = @""; + [Growing_Swizzle_XCTest_C classMethod]; + XCTAssertEqualObjects(self.swizzleString, @"B"); +} + +- (void)test03AlwaysSwizzlingMode { + // GrowingULSwizzleModeAlways的swizzle一直触发 + Class cls = Growing_Swizzle_XCTest.class; + Class cls2 = Growing_Swizzle_XCTest_B.class; + SEL selector = @selector(instanceMethod); + for (int i = 3; i > 0; --i) { + [self guSwizzleClass:cls selector:selector key:NULL mode:GrowingULSwizzleModeAlways]; + [self guSwizzleClass:cls2 selector:selector key:NULL mode:GrowingULSwizzleModeAlways]; } + NSObject *test = [cls2 new]; + [test performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"BBBBBB"); +} - { - [GrowingULSwizzler growingul_swizzleSelector:@selector(respondsToSelector:) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - b = 12; - } - named:@"xctest"]; +- (void)test04SwizzleOncePerClassMode { + // GrowingULSwizzleModeOncePerClass只能保证分别对父类和子类只swizzle一次 + Class cls = Growing_Swizzle_XCTest.class; + Class cls2 = Growing_Swizzle_XCTest_B.class; + SEL selector = @selector(instanceMethod); + static const void *key = &key; + for (int i = 3; i > 0; --i) { + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClass]; + [self guSwizzleClass:cls2 selector:selector key:key mode:GrowingULSwizzleModeOncePerClass]; } + NSObject *test = [cls2 new]; + [test performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"BB"); +} - { - XCTAssertThrows([GrowingULSwizzler growingul_swizzleSelector:@selector(cannotFindMethod) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - } - named:@"xctest"]); - - XCTAssertThrows([GrowingULSwizzler growingul_swizzleSelector:@selector(instanceMethod:arg2:arg3:arg4:) - onClass:Growing_Swizzle_XCTest.class - withBlock:^{ - } - named:@"xctest"]); +- (void)test05SwizzleOncePerClassOrSuperClassesMode { + // 先swizzle父类,再swizzle子类,GrowingULSwizzleModeOncePerClassAndSuperclasses保证只swizzle一次 + Class cls = Growing_Swizzle_XCTest.class; + Class cls2 = Growing_Swizzle_XCTest_B.class; + SEL selector = @selector(instanceMethod); + static const void *key = &key; + for (int i = 3; i > 0; --i) { + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + [self guSwizzleClass:cls2 selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; } + NSObject *test = [cls2 new]; + [test performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"B"); +} - XCTAssertNoThrow([GrowingULSwizzler growing_printSwizzles]); -#pragma clang diagnostic pop +- (void)test06SwizzleOncePerClassOrSuperClassesMode2 { + // 先swizzle子类,再swizzle父类,GrowingULSwizzleModeOncePerClassAndSuperclasses就只能保证分别对父类和子类只swizzle一次 + Class cls = Growing_Swizzle_XCTest.class; + Class cls2 = Growing_Swizzle_XCTest_B.class; + SEL selector = @selector(instanceMethod); + static const void *key = &key; + for (int i = 3; i > 0; --i) { + [self guSwizzleClass:cls2 selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + } + NSObject *test = [cls2 new]; + [test performSelector:selector]; + XCTAssertEqualObjects(self.swizzleString, @"BB"); } -- (void)test0GrowingULSwizzlerRealDelegate { +- (void)test07GrowingULSwizzlerRealDelegate { // NSProxy id proxy = nil; id proxy1 = [[Growing_Swizzle_Proxy_XCTest alloc] initWithTarget:nil]; id proxy2 = [[Growing_Swizzle_Proxy_XCTest2 alloc] initWithTarget:proxy1]; { - XCTAssertNoThrow([GrowingULSwizzler realDelegate:proxy toSelector:@selector(delegateSelector)]); + XCTAssertNoThrow([GrowingULSwizzle realDelegate:proxy toSelector:@selector(delegateSelector)]); // proxy 本身实现了 - id result = [GrowingULSwizzler realDelegate:proxy1 toSelector:@selector(delegateSelector)]; + id result = [GrowingULSwizzle realDelegate:proxy1 toSelector:@selector(delegateSelector)]; XCTAssertEqualObjects(proxy1, result); - XCTAssertTrue([GrowingULSwizzler realDelegateClass:((NSObject *)result).class + XCTAssertTrue([GrowingULSwizzle realDelegateClass:((NSObject *)result).class respondsToSelector:@selector(delegateSelector)]); // proxy 在 resolveInstanceMethod 增加了实现 - id result2 = [GrowingULSwizzler realDelegate:proxy1 toSelector:@selector(delegateSelector2)]; + id result2 = [GrowingULSwizzle realDelegate:proxy1 toSelector:@selector(delegateSelector2)]; XCTAssertEqualObjects(proxy1, result2); - XCTAssertTrue([GrowingULSwizzler realDelegateClass:((NSObject *)result2).class + XCTAssertTrue([GrowingULSwizzle realDelegateClass:((NSObject *)result2).class respondsToSelector:@selector(delegateSelector2)]); } { // proxy 在 forwardingTargetForSelector 转发给了另一个对象 - id result = [GrowingULSwizzler realDelegate:proxy2 toSelector:@selector(delegateSelector)]; + id result = [GrowingULSwizzle realDelegate:proxy2 toSelector:@selector(delegateSelector)]; XCTAssertEqualObjects(proxy1, result); - XCTAssertTrue([GrowingULSwizzler realDelegateClass:((NSObject *)result).class + XCTAssertTrue([GrowingULSwizzle realDelegateClass:((NSObject *)result).class respondsToSelector:@selector(delegateSelector)]); } } -- (void)test1GrowingULSwizzle { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wundeclared-selector" +- (void)test08SwizzleCompatibility { + // 先执行generalSwizzle + Class cls = Growing_Swizzle_XCTest.class; + SEL selector = @selector(instanceMethod); + + __weak typeof(self) weakSelf = self; + void(^checkBlock)(NSString *) = ^(NSString *string) { + weakSelf.swizzleString.string = @""; + [[cls new] performSelector:selector]; + XCTAssertEqualObjects(weakSelf.swizzleString, string); + }; + + // generalSwizzleImp -> originImp + // A + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"A"); + + // rsSwizzleImp -> generalSwizzleImp -> originImp + // B <- A + static const void *key = &key; + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + checkBlock(@"AB"); + + // generalSwizzleImp -> rsSwizzleImp -> generalSwizzleImp -> originImp + // A <- B <- A + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"ABA"); + + // generalSwizzleImp -> rsSwizzleImp -> generalSwizzleImp -> originImp + // A <- B <- A + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + checkBlock(@"ABA"); + + // generalSwizzleImp -> generalSwizzleImp -> rsSwizzleImp -> generalSwizzleImp -> originImp + // A <- A <- B <- A + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"ABAA"); +} + +- (void)test09SwizzleCompatibility { + // 先执行rsSwizzle + Class cls = Growing_Swizzle_XCTest.class; + SEL selector = @selector(instanceMethod); + + __weak typeof(self) weakSelf = self; + void(^checkBlock)(NSString *) = ^(NSString *string) { + weakSelf.swizzleString.string = @""; + [[cls new] performSelector:selector]; + XCTAssertEqualObjects(weakSelf.swizzleString, string); + }; + + // rsSwizzleImp -> originImp + // B + static const void *key = &key; + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + checkBlock(@"B"); + + // generalSwizzleImp -> rsSwizzleImp -> originImp + // A <- B + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"BA"); + + // generalSwizzleImp -> rsSwizzleImp -> originImp + // A <- B + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + checkBlock(@"BA"); + + // generalSwizzleImp -> generalSwizzleImp -> rsSwizzleImp -> originImp + // A <- A <- B + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"BAA"); +} + +- (void)test10SwizzleCompatibility { + // isaSwizzler + Class cls = Growing_Swizzle_XCTest.class; + SEL selector = @selector(instanceMethod); + + Growing_Swizzle_XCTest *instance = [cls new]; + __weak typeof(self) weakSelf = self; + void(^checkBlock)(NSString *) = ^(NSString *string) { + weakSelf.swizzleString.string = @""; + [instance performSelector:selector]; + XCTAssertEqualObjects(weakSelf.swizzleString, string); + }; + + NSString *newClassName = [NSString stringWithFormat:@"%@_%@", [NSUUID UUID].UUIDString, + NSStringFromClass(cls)]; + Class generatedClass = objc_allocateClassPair(cls, newClassName.UTF8String, 0); + objc_registerClassPair(generatedClass); + object_setClass(instance, generatedClass); + + // isaSwizzler最后还是需要在动态子类中重写并调用父类方法,因此只要保证对父类的swizzler正常生效即可 + + // rsSwizzleImp -> originImp + // B + static const void *key = &key; + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + checkBlock(@"B"); + + // generalSwizzleImp -> rsSwizzleImp -> originImp + // A <- B + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"BA"); + + // generalSwizzleImp -> rsSwizzleImp -> originImp + // A <- B + [self guSwizzleClass:cls selector:selector key:key mode:GrowingULSwizzleModeOncePerClassAndSuperclasses]; + checkBlock(@"BA"); + + // generalSwizzleImp -> generalSwizzleImp -> rsSwizzleImp -> originImp + // A <- A <- B + [self generalSwizzleClass:cls selector:selector]; + checkBlock(@"BAA"); +} + +- (void)test11GrowingULSwizzle { NSError *error = nil; [Growing_Swizzle_XCTest growingul_swizzleMethod:@selector(undefinedSelector) withMethod:@selector(swizzle_instanceMethod) @@ -352,7 +547,7 @@ - (void)test1GrowingULSwizzle { XCTAssertNil(error); Growing_Swizzle_XCTest *test = Growing_Swizzle_XCTest.new; [test instanceMethod]; - XCTAssertEqual(b, 6); + XCTAssertEqual(b, 1); error = nil; [Growing_Swizzle_XCTest growingul_swizzleClassMethod:@selector(classMethod) @@ -360,8 +555,9 @@ - (void)test1GrowingULSwizzle { error:&error]; XCTAssertNil(error); [Growing_Swizzle_XCTest classMethod]; - XCTAssertEqual(b, 7); -#pragma clang diagnostic pop + XCTAssertEqual(b, 3); } @end + +#pragma clang diagnostic pop diff --git a/Example/Podfile.lock b/Example/Podfile.lock index b5d9ae1e2..e8bb6ce1a 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -1,91 +1,91 @@ PODS: - - GrowingAnalytics-cdp/Autotracker (3.7.1): - - GrowingAnalytics/AutotrackerCore (= 3.7.1) - - GrowingAnalytics/DefaultServices (= 3.7.1) - - GrowingAnalytics/Hybrid (= 3.7.1) - - GrowingAnalytics/MobileDebugger (= 3.7.1) - - GrowingAnalytics/WebCircle (= 3.7.1) - - GrowingAnalytics-cdp/Tracker (3.7.1): - - GrowingAnalytics/DefaultServices (= 3.7.1) - - GrowingAnalytics/MobileDebugger (= 3.7.1) - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingAnalytics/Advert (3.7.1): - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingAnalytics/APM (3.7.1): - - GrowingAnalytics/TrackerCore (= 3.7.1) + - GrowingAnalytics-cdp/Autotracker (3.8.1): + - GrowingAnalytics/AutotrackerCore (= 3.8.1) + - GrowingAnalytics/DefaultServices (= 3.8.1) + - GrowingAnalytics/Hybrid (= 3.8.1) + - GrowingAnalytics/MobileDebugger (= 3.8.1) + - GrowingAnalytics/WebCircle (= 3.8.1) + - GrowingAnalytics-cdp/Tracker (3.8.1): + - GrowingAnalytics/DefaultServices (= 3.8.1) + - GrowingAnalytics/MobileDebugger (= 3.8.1) + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingAnalytics/Advert (3.8.1): + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingAnalytics/APM (3.8.1): + - GrowingAnalytics/TrackerCore (= 3.8.1) - GrowingAPM/Core - - GrowingAnalytics/Autotracker (3.7.1): - - GrowingAnalytics/AutotrackerCore (= 3.7.1) - - GrowingAnalytics/DefaultServices (= 3.7.1) - - GrowingAnalytics/Hybrid (= 3.7.1) - - GrowingAnalytics/MobileDebugger (= 3.7.1) - - GrowingAnalytics/WebCircle (= 3.7.1) - - GrowingAnalytics/AutotrackerCore (3.7.1): - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingUtils/AutotrackerCore (= 0.0.7) - - GrowingAnalytics/Compression (3.7.1): - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingAnalytics/Database (3.7.1): - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingAnalytics/DefaultServices (3.7.1): - - GrowingAnalytics/Compression (= 3.7.1) - - GrowingAnalytics/Database (= 3.7.1) - - GrowingAnalytics/Encryption (= 3.7.1) - - GrowingAnalytics/Network (= 3.7.1) - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingAnalytics/Encryption (3.7.1): - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingAnalytics/Hybrid (3.7.1): - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingAnalytics/MobileDebugger (3.7.1): - - GrowingAnalytics/Screenshot (= 3.7.1) - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingAnalytics/WebSocket (= 3.7.1) - - GrowingAnalytics/Network (3.7.1): - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingAnalytics/Protobuf (3.7.1): - - GrowingAnalytics/Database (= 3.7.1) - - GrowingAnalytics/Protobuf/Proto (= 3.7.1) - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingAnalytics/Protobuf/Proto (3.7.1): - - GrowingAnalytics/Database (= 3.7.1) - - GrowingAnalytics/TrackerCore (= 3.7.1) + - GrowingAnalytics/Autotracker (3.8.1): + - GrowingAnalytics/AutotrackerCore (= 3.8.1) + - GrowingAnalytics/DefaultServices (= 3.8.1) + - GrowingAnalytics/Hybrid (= 3.8.1) + - GrowingAnalytics/MobileDebugger (= 3.8.1) + - GrowingAnalytics/WebCircle (= 3.8.1) + - GrowingAnalytics/AutotrackerCore (3.8.1): + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingUtils/AutotrackerCore (~> 1.2.3) + - GrowingAnalytics/Compression (3.8.1): + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingAnalytics/Database (3.8.1): + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingAnalytics/DefaultServices (3.8.1): + - GrowingAnalytics/Compression (= 3.8.1) + - GrowingAnalytics/Database (= 3.8.1) + - GrowingAnalytics/Encryption (= 3.8.1) + - GrowingAnalytics/Network (= 3.8.1) + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingAnalytics/Encryption (3.8.1): + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingAnalytics/Hybrid (3.8.1): + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingAnalytics/MobileDebugger (3.8.1): + - GrowingAnalytics/Screenshot (= 3.8.1) + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingAnalytics/WebSocket (= 3.8.1) + - GrowingAnalytics/Network (3.8.1): + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingAnalytics/Protobuf (3.8.1): + - GrowingAnalytics/Database (= 3.8.1) + - GrowingAnalytics/Protobuf/Proto (= 3.8.1) + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingAnalytics/Protobuf/Proto (3.8.1): + - GrowingAnalytics/Database (= 3.8.1) + - GrowingAnalytics/TrackerCore (= 3.8.1) - Protobuf - - GrowingAnalytics/Screenshot (3.7.1): + - GrowingAnalytics/Screenshot (3.8.1): - GrowingAnalytics/TrackerCore - - GrowingAnalytics/Tracker (3.7.1): - - GrowingAnalytics/DefaultServices (= 3.7.1) - - GrowingAnalytics/MobileDebugger (= 3.7.1) - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingAnalytics/TrackerCore (3.7.1): - - GrowingUtils/TrackerCore (= 0.0.7) - - GrowingAnalytics/WebCircle (3.7.1): - - GrowingAnalytics/AutotrackerCore (= 3.7.1) - - GrowingAnalytics/Hybrid (= 3.7.1) - - GrowingAnalytics/Screenshot (= 3.7.1) - - GrowingAnalytics/WebSocket (= 3.7.1) - - GrowingAnalytics/WebSocket (3.7.1): - - GrowingAnalytics/TrackerCore (= 3.7.1) - - GrowingAPM (1.0.0): - - GrowingAPM/Core (= 1.0.0) - - GrowingAPM/CrashMonitor (= 1.0.0) - - GrowingAPM/UIMonitor (= 1.0.0) - - GrowingAPM/Core (1.0.0): + - GrowingAnalytics/Tracker (3.8.1): + - GrowingAnalytics/DefaultServices (= 3.8.1) + - GrowingAnalytics/MobileDebugger (= 3.8.1) + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingAnalytics/TrackerCore (3.8.1): + - GrowingUtils/TrackerCore (~> 1.2.3) + - GrowingAnalytics/WebCircle (3.8.1): + - GrowingAnalytics/AutotrackerCore (= 3.8.1) + - GrowingAnalytics/Hybrid (= 3.8.1) + - GrowingAnalytics/Screenshot (= 3.8.1) + - GrowingAnalytics/WebSocket (= 3.8.1) + - GrowingAnalytics/WebSocket (3.8.1): + - GrowingAnalytics/TrackerCore (= 3.8.1) + - GrowingAPM (1.0.1): + - GrowingAPM/Core (= 1.0.1) + - GrowingAPM/CrashMonitor (= 1.0.1) + - GrowingAPM/UIMonitor (= 1.0.1) + - GrowingAPM/Core (1.0.1): - GrowingUtils/TrackerCore - - GrowingAPM/CrashMonitor (1.0.0): + - GrowingAPM/CrashMonitor (1.0.1): - GrowingAPM/Core - - GrowingAPM/UIMonitor (1.0.0): + - GrowingAPM/UIMonitor (1.0.1): - GrowingAPM/Core - - GrowingToolsKit (1.2.1): - - GrowingToolsKit/Default (= 1.2.1) - - GrowingToolsKit/APMCore (1.2.1): + - GrowingToolsKit (2.0.2): + - GrowingToolsKit/Default (= 2.0.2) + - GrowingToolsKit/APMCore (2.0.2): - GrowingAPM/Core - GrowingToolsKit/Core - - GrowingToolsKit/Core (1.2.1) - - GrowingToolsKit/CrashMonitor (1.2.1): + - GrowingToolsKit/Core (2.0.2) + - GrowingToolsKit/CrashMonitor (2.0.2): - GrowingAPM/CrashMonitor - GrowingToolsKit/APMCore - - GrowingToolsKit/Default (1.2.1): + - GrowingToolsKit/Default (2.0.2): - GrowingToolsKit/Core - GrowingToolsKit/CrashMonitor - GrowingToolsKit/EventsList @@ -95,24 +95,24 @@ PODS: - GrowingToolsKit/SDKInfo - GrowingToolsKit/Settings - GrowingToolsKit/XPathTrack - - GrowingToolsKit/EventsList (1.2.1): + - GrowingToolsKit/EventsList (2.0.2): - GrowingToolsKit/Core - - GrowingToolsKit/LaunchTime (1.2.1): + - GrowingToolsKit/LaunchTime (2.0.2): - GrowingAPM/UIMonitor - GrowingToolsKit/APMCore - - GrowingToolsKit/NetFlow (1.2.1): + - GrowingToolsKit/NetFlow (2.0.2): - GrowingToolsKit/Core - - GrowingToolsKit/Realtime (1.2.1): + - GrowingToolsKit/Realtime (2.0.2): - GrowingToolsKit/Core - - GrowingToolsKit/SDKInfo (1.2.1): + - GrowingToolsKit/SDKInfo (2.0.2): - GrowingToolsKit/Core - - GrowingToolsKit/Settings (1.2.1): + - GrowingToolsKit/Settings (2.0.2): - GrowingToolsKit/Core - - GrowingToolsKit/XPathTrack (1.2.1): + - GrowingToolsKit/XPathTrack (2.0.2): - GrowingToolsKit/Core - - GrowingUtils/AutotrackerCore (0.0.7): + - GrowingUtils/AutotrackerCore (1.2.3): - GrowingUtils/TrackerCore - - GrowingUtils/TrackerCore (0.0.7) + - GrowingUtils/TrackerCore (1.2.3) - KIF (3.8.9): - KIF/Core (= 3.8.9) - KIF/Core (3.8.9) @@ -121,12 +121,12 @@ PODS: - LBXScan/Types (2.3) - LBXScan/UI (2.3): - LBXScan/Types (~> 2.2) - - Protobuf (3.24.4) + - Protobuf (3.26.1) - SDCycleScrollView (1.82): - SDWebImage (>= 5.0.0) - - SDWebImage (5.18.3): - - SDWebImage/Core (= 5.18.3) - - SDWebImage/Core (5.18.3) + - SDWebImage (5.19.1): + - SDWebImage/Core (= 5.19.1) + - SDWebImage/Core (5.19.1) DEPENDENCIES: - GrowingAnalytics-cdp/Autotracker (from `../`) @@ -161,17 +161,17 @@ EXTERNAL SOURCES: :path: "../" SPEC CHECKSUMS: - GrowingAnalytics: 734101fa51d84f0fbc3e893f3a397965249752a7 - GrowingAnalytics-cdp: b2a609e471bc4092d507ccb5f5037057e2e44e53 - GrowingAPM: 6750d66ca6876c2c7d22c1c087625bc9ccc3430c - GrowingToolsKit: 134a78b023c4ab7da51e0a1111e9956a96e42dab - GrowingUtils: e8ba72794651ade9ad60a71662d11baa08d526c8 + GrowingAnalytics: 28f1b5015dcf6d9dd1964e9f653924defbad6868 + GrowingAnalytics-cdp: 5e72936a1db9979fcd650ec712c5ffa4f0e5693e + GrowingAPM: 3c4de0384935b654e6798b95606f47883a99418b + GrowingToolsKit: 53160d19690da0b78e04a9242abde7af86442922 + GrowingUtils: 68aee2c96849bf9b674740503da30c2da468e79d KIF: 7660c626b0f2d4562533590960db70a36d640558 LBXScan: e51449f0832d1fe17da632af0d22adeb3cfa3543 - Protobuf: 351e9022fe13a6e2af00e9aefc22077cb88520f8 + Protobuf: a53f5173a603075b3522a5c50be63a67a5f3353a SDCycleScrollView: a0d74c3384caa72bdfc81470bdbc8c14b3e1fbcf - SDWebImage: 96e0c18ef14010b7485210e92fac888587ebb958 + SDWebImage: 40b0b4053e36c660a764958bff99eed16610acbb PODFILE CHECKSUM: 8b74d64200d8437dbd5c21a406bd3513fc0eebd0 -COCOAPODS: 1.14.2 +COCOAPODS: 1.15.2 diff --git a/GrowingAnalytics-cdp.podspec b/GrowingAnalytics-cdp.podspec index e8a2afef5..df0ed07df 100644 --- a/GrowingAnalytics-cdp.podspec +++ b/GrowingAnalytics-cdp.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GrowingAnalytics-cdp' - s.version = '3.8.0' + s.version = '3.8.1' s.summary = 'iOS SDK of GrowingIO.' s.description = <<-DESC GrowingAnalytics-cdp基于GrowingAnalytics,同样具备自动采集基本的用户行为事件,比如访问和行为数据等。 diff --git a/GrowingAnalytics.podspec b/GrowingAnalytics.podspec index 957a29d2c..335fe5e3a 100644 --- a/GrowingAnalytics.podspec +++ b/GrowingAnalytics.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'GrowingAnalytics' - s.version = '3.8.0' + s.version = '3.8.1' s.summary = 'iOS SDK of GrowingIO.' s.description = <<-DESC GrowingAnalytics具备自动采集基本的用户行为事件,比如访问和行为数据等。目前支持代码埋点、无埋点、可视化圈选、热图等功能。 @@ -40,7 +40,7 @@ GrowingAnalytics具备自动采集基本的用户行为事件,比如访问和 end s.subspec 'TrackerCore' do |trackerCore| - trackerCore.dependency 'GrowingUtils/TrackerCore', '0.0.7' + trackerCore.dependency 'GrowingUtils/TrackerCore', '~> 1.2.3' trackerCore.source_files = 'GrowingTrackerCore/**/*{.h,.m,.c,.cpp,.mm}' trackerCore.exclude_files = 'GrowingTrackerCore/Utils/UserIdentifier/GrowingUserIdentifier_NoIDFA.m' trackerCore.public_header_files = 'GrowingTrackerCore/Public/*.h' @@ -51,7 +51,7 @@ GrowingAnalytics具备自动采集基本的用户行为事件,比如访问和 s.subspec 'AutotrackerCore' do |autotrackerCore| autotrackerCore.ios.deployment_target = '10.0' - autotrackerCore.dependency 'GrowingUtils/AutotrackerCore', '0.0.7' + autotrackerCore.dependency 'GrowingUtils/AutotrackerCore', '~> 1.2.3' autotrackerCore.source_files = 'GrowingAutotrackerCore/**/*{.h,.m,.c,.cpp,.mm}' autotrackerCore.public_header_files = 'GrowingAutotrackerCore/Public/*.h' autotrackerCore.dependency 'GrowingAnalytics/TrackerCore', s.version.to_s diff --git a/GrowingAutotracker-cdp/GrowingAutotracker.h b/GrowingAutotracker-cdp/GrowingAutotracker.h index 56f95e680..b92ea1f78 100644 --- a/GrowingAutotracker-cdp/GrowingAutotracker.h +++ b/GrowingAutotracker-cdp/GrowingAutotracker.h @@ -18,7 +18,7 @@ // limitations under the License. @import UIKit; -#if __has_include() // Cocoapods or Manual +#if __has_include() // Cocoapods or Manual @import GrowingAnalytics; #else #import "GrowingAttributesBuilder.h" diff --git a/GrowingAutotrackerCore/Autotrack/UICollectionView+GrowingAutotracker.m b/GrowingAutotrackerCore/Autotrack/UICollectionView+GrowingAutotracker.m index 3a168af52..fa7c9ee29 100644 --- a/GrowingAutotrackerCore/Autotrack/UICollectionView+GrowingAutotracker.m +++ b/GrowingAutotrackerCore/Autotrack/UICollectionView+GrowingAutotracker.m @@ -27,23 +27,26 @@ @implementation UICollectionView (GrowingAutotracker) - (void)growing_setDelegate:(id)delegate { SEL selector = @selector(collectionView:didSelectItemAtIndexPath:); - id realDelegate = [GrowingULSwizzler realDelegate:delegate toSelector:selector]; + id realDelegate = [GrowingULSwizzle realDelegate:delegate toSelector:selector]; Class class = realDelegate.class; - if ([GrowingULSwizzler realDelegateClass:class respondsToSelector:selector]) { - void (^didSelectItemBlock)(id, SEL, id, id) = - ^(id view, SEL command, UICollectionView *collectionView, NSIndexPath *indexPath) { - if (collectionView && indexPath) { - UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath]; - if (cell) { - [GrowingViewClickProvider viewOnClick:cell]; - } - } - }; - - [GrowingULSwizzler growingul_swizzleSelector:selector - onClass:class - withBlock:didSelectItemBlock - named:@"growing_collectionView_didSelect"]; + if ([GrowingULSwizzle realDelegateClass:class respondsToSelector:selector]) { + static const void *key = &key; + GrowingULSwizzleInstanceMethod(class, + selector, + GUSWReturnType(void), + GUSWArguments(UICollectionView * collectionView, NSIndexPath * indexPath), + GUSWReplacement({ + if (collectionView && indexPath) { + UICollectionViewCell *cell = + [collectionView cellForItemAtIndexPath:indexPath]; + if (cell) { + [GrowingViewClickProvider viewOnClick:cell]; + } + } + GUSWCallOriginal(collectionView, indexPath); + }), + GrowingULSwizzleModeOncePerClassAndSuperclasses, + key); } [self growing_setDelegate:delegate]; diff --git a/GrowingAutotrackerCore/Autotrack/UITableView+GrowingAutotracker.m b/GrowingAutotrackerCore/Autotrack/UITableView+GrowingAutotracker.m index 16209acdc..90d854aa6 100644 --- a/GrowingAutotrackerCore/Autotrack/UITableView+GrowingAutotracker.m +++ b/GrowingAutotrackerCore/Autotrack/UITableView+GrowingAutotracker.m @@ -27,22 +27,25 @@ @implementation UITableView (GrowingAutotracker) - (void)growing_setDelegate:(id)delegate { SEL selector = @selector(tableView:didSelectRowAtIndexPath:); - id realDelegate = [GrowingULSwizzler realDelegate:delegate toSelector:selector]; + id realDelegate = [GrowingULSwizzle realDelegate:delegate toSelector:selector]; Class class = realDelegate.class; - if ([GrowingULSwizzler realDelegateClass:class respondsToSelector:selector]) { - void (^didSelectBlock)(id, SEL, id, id) = - ^(id view, SEL command, UITableView *tableView, NSIndexPath *indexPath) { - if (tableView && indexPath) { - UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; - if (cell) { - [GrowingViewClickProvider viewOnClick:cell]; - } - } - }; - [GrowingULSwizzler growingul_swizzleSelector:selector - onClass:class - withBlock:didSelectBlock - named:@"growing_tableView_didSelect"]; + if ([GrowingULSwizzle realDelegateClass:class respondsToSelector:selector]) { + static const void *key = &key; + GrowingULSwizzleInstanceMethod(class, + selector, + GUSWReturnType(void), + GUSWArguments(UITableView * tableView, NSIndexPath * indexPath), + GUSWReplacement({ + if (tableView && indexPath) { + UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; + if (cell) { + [GrowingViewClickProvider viewOnClick:cell]; + } + } + GUSWCallOriginal(tableView, indexPath); + }), + GrowingULSwizzleModeOncePerClassAndSuperclasses, + key); } [self growing_setDelegate:delegate]; diff --git a/GrowingTracker-cdp/GrowingTracker.h b/GrowingTracker-cdp/GrowingTracker.h index 284bd1a92..9c1da8780 100644 --- a/GrowingTracker-cdp/GrowingTracker.h +++ b/GrowingTracker-cdp/GrowingTracker.h @@ -17,12 +17,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -#if __has_include() // Cocoapods or Manual +#if __has_include() // Cocoapods or Manual @import GrowingAnalytics; #else #import "GrowingAttributesBuilder.h" -#import "GrowingTrackConfiguration.h" #import "GrowingDynamicProxy.h" +#import "GrowingTrackConfiguration.h" #endif NS_ASSUME_NONNULL_BEGIN diff --git a/GrowingTrackerCore/Event/GrowingEventChannel.h b/GrowingTrackerCore/Event/GrowingEventChannel.h index 5229d501f..376c5eb36 100644 --- a/GrowingTrackerCore/Event/GrowingEventChannel.h +++ b/GrowingTrackerCore/Event/GrowingEventChannel.h @@ -31,8 +31,7 @@ NS_ASSUME_NONNULL_BEGIN isCustomEvent:(BOOL)isCustomEvent isUploading:(BOOL)isUploading; -+ (instancetype)eventChannelWithEventTypes:(NSArray *_Nullable)eventTypes - isCustomEvent:(BOOL)isCustomEvent; ++ (instancetype)eventChannelWithEventTypes:(NSArray *_Nullable)eventTypes isCustomEvent:(BOOL)isCustomEvent; /// 所有的channels集合 + (NSMutableArray *)eventChannels; /// 深拷贝Channels集合,并自动添加一个EventType为nil的Channels diff --git a/GrowingTrackerCore/Event/GrowingEventChannel.m b/GrowingTrackerCore/Event/GrowingEventChannel.m index 0ebf22dd1..e2fee111d 100644 --- a/GrowingTrackerCore/Event/GrowingEventChannel.m +++ b/GrowingTrackerCore/Event/GrowingEventChannel.m @@ -33,11 +33,8 @@ - (instancetype)initWithTypes:(NSArray *)eventTypes return self; } -+ (instancetype)eventChannelWithEventTypes:(NSArray *)eventTypes - isCustomEvent:(BOOL)isCustomEvent { - return [[GrowingEventChannel alloc] initWithTypes:eventTypes - isCustomEvent:isCustomEvent - isUploading:NO]; ++ (instancetype)eventChannelWithEventTypes:(NSArray *)eventTypes isCustomEvent:(BOOL)isCustomEvent { + return [[GrowingEventChannel alloc] initWithTypes:eventTypes isCustomEvent:isCustomEvent isUploading:NO]; } static NSMutableArray *eventChannels = nil; @@ -65,8 +62,7 @@ + (instancetype)eventChannelWithEventTypes:(NSArray *)eventTypes + (NSArray *)buildAllEventChannels { NSMutableArray *channels = [[self eventChannels] mutableCopy]; eventChannels = nil; - [channels addObject:[GrowingEventChannel eventChannelWithEventTypes:nil - isCustomEvent:NO]]; + [channels addObject:[GrowingEventChannel eventChannelWithEventTypes:nil isCustomEvent:NO]]; return channels; } diff --git a/GrowingTrackerCore/GrowingRealTracker.m b/GrowingTrackerCore/GrowingRealTracker.m index 732abae92..87050ee71 100644 --- a/GrowingTrackerCore/GrowingRealTracker.m +++ b/GrowingTrackerCore/GrowingRealTracker.m @@ -38,8 +38,8 @@ #import "GrowingTrackerCore/Utils/GrowingDeviceInfo.h" #import "GrowingULAppLifecycle.h" -NSString *const GrowingTrackerVersionName = @"3.8.0"; -const int GrowingTrackerVersionCode = 30800; +NSString *const GrowingTrackerVersionName = @"3.8.1"; +const int GrowingTrackerVersionCode = 30801; @interface GrowingRealTracker () diff --git a/Modules/Advert/GrowingAdvertising.m b/Modules/Advert/GrowingAdvertising.m index 91feef95a..c36000392 100644 --- a/Modules/Advert/GrowingAdvertising.m +++ b/Modules/Advert/GrowingAdvertising.m @@ -104,8 +104,7 @@ - (BOOL)growingHandlerUrl:(NSURL *)url { #pragma mark - GrowingEventInterceptor - (void)growingEventManagerChannels:(NSMutableArray *)channels { - [channels addObject:[GrowingEventChannel eventChannelWithEventTypes:@[GrowingEventTypeActivate] - isCustomEvent:NO]]; + [channels addObject:[GrowingEventChannel eventChannelWithEventTypes:@[GrowingEventTypeActivate] isCustomEvent:NO]]; } #pragma mark - GrowingULAppLifecycleDelegate diff --git a/Modules/SwiftProtobuf/SwiftProtobuf.swift b/Modules/SwiftProtobuf/SwiftProtobuf.swift index eb7913b0c..86f851001 100644 --- a/Modules/SwiftProtobuf/SwiftProtobuf.swift +++ b/Modules/SwiftProtobuf/SwiftProtobuf.swift @@ -26,7 +26,7 @@ public class SwiftProtobufWrapper: NSObject { @objc public let data: Data? init(_ unbox: EventV3Dto) { self.unbox = unbox - self.data = try? unbox.serializedData() + data = try? unbox.serializedData() } @objc(parseFromData:) @@ -70,10 +70,10 @@ public class SwiftProtobufWrapper: NSObject { } } -extension SwiftProtobufWrapper { +public extension SwiftProtobufWrapper { // For GrowingToolsKit NetFlow @objc(convertProtobufDataToJsonArray:) - public static func convertProtobufDataToJsonArray(from data: Data) -> [[String: AnyObject]]? { + static func convertProtobufDataToJsonArray(from data: Data) -> [[String: AnyObject]]? { do { let list = try EventV3List(serializedData: data) var array = [[String: AnyObject]]() @@ -91,36 +91,36 @@ extension SwiftProtobufWrapper { } } -extension GrowingBaseEvent { - @objc public func toProtobuf() -> SwiftProtobufWrapper { +public extension GrowingBaseEvent { + @objc func toProtobuf() -> SwiftProtobufWrapper { var dto = EventV3Dto() - dto.dataSourceID = self.dataSourceId ?? "" - dto.gioID = self.gioId ?? "" - dto.sessionID = self.sessionId ?? "" - dto.timestamp = self.timestamp - dto.domain = self.domain - dto.userID = self.userId ?? "" - dto.deviceID = self.deviceId - dto.platform = self.platform - dto.platformVersion = self.platformVersion - dto.globalSequenceID = self.globalSequenceId - dto.eventSequenceID = Int32(self.eventSequenceId) - dto.appState = self.appState == GrowingAppState.foreground.rawValue ? "FOREGROUND" : "BACKGROUND" - dto.urlScheme = self.urlScheme - dto.networkState = self.networkState ?? "" - dto.screenWidth = Int32(self.screenWidth) - dto.screenHeight = Int32(self.screenHeight) - dto.deviceBrand = self.deviceBrand - dto.deviceModel = self.deviceModel - dto.deviceType = self.deviceType - dto.appName = self.appName - dto.appVersion = self.appVersion - dto.language = self.language - dto.latitude = self.latitude - dto.longitude = self.longitude - dto.sdkVersion = self.sdkVersion - dto.userKey = self.userKey ?? "" + dto.dataSourceID = dataSourceId ?? "" + dto.gioID = gioId ?? "" + dto.sessionID = sessionId ?? "" + dto.timestamp = timestamp + dto.domain = domain + dto.userID = userId ?? "" + dto.deviceID = deviceId + dto.platform = platform + dto.platformVersion = platformVersion + dto.globalSequenceID = globalSequenceId + dto.eventSequenceID = Int32(eventSequenceId) + dto.appState = appState == GrowingAppState.foreground.rawValue ? "FOREGROUND" : "BACKGROUND" + dto.urlScheme = urlScheme + dto.networkState = networkState ?? "" + dto.screenWidth = Int32(screenWidth) + dto.screenHeight = Int32(screenHeight) + dto.deviceBrand = deviceBrand + dto.deviceModel = deviceModel + dto.deviceType = deviceType + dto.appName = appName + dto.appVersion = appVersion + dto.language = language + dto.latitude = latitude + dto.longitude = longitude + dto.sdkVersion = sdkVersion + dto.userKey = userKey ?? "" dto.eventType = eventType() dto.idfa = idfa() @@ -144,184 +144,184 @@ extension GrowingBaseEvent { } } -extension GrowingBaseEvent { - fileprivate func eventType() -> EventType { - if self.eventType == "VISIT" { +private extension GrowingBaseEvent { + func eventType() -> EventType { + if eventType == "VISIT" { return .visit - } else if self.eventType == "CUSTOM" { + } else if eventType == "CUSTOM" { return .custom - } else if self.eventType == "VISITOR_ATTRIBUTES" { + } else if eventType == "VISITOR_ATTRIBUTES" { return .visitorAttributes - } else if self.eventType == "LOGIN_USER_ATTRIBUTES" { + } else if eventType == "LOGIN_USER_ATTRIBUTES" { return .loginUserAttributes - } else if self.eventType == "CONVERSION_VARIABLES" { + } else if eventType == "CONVERSION_VARIABLES" { return .conversionVariables - } else if self.eventType == "APP_CLOSED" { + } else if eventType == "APP_CLOSED" { return .appClosed - } else if self.eventType == "PAGE" { + } else if eventType == "PAGE" { return .page - } else if self.eventType == "VIEW_CLICK" { + } else if eventType == "VIEW_CLICK" { return .viewClick - } else if self.eventType == "VIEW_CHANGE" { + } else if eventType == "VIEW_CHANGE" { return .viewChange - } else if self.eventType == "FORM_SUBMIT" { + } else if eventType == "FORM_SUBMIT" { return .formSubmit - } else if self.eventType == "ACTIVATE" { + } else if eventType == "ACTIVATE" { return .activate } return .UNRECOGNIZED(100) } - fileprivate func idfa() -> String { + func idfa() -> String { let selector = Selector(("idfa")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" } return "" } - fileprivate func idfv() -> String { + func idfv() -> String { let selector = Selector(("idfv")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" } return "" } - fileprivate func extraSdk() -> [String: String] { + func extraSdk() -> [String: String] { let selector = Selector(("extraSdk")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> [String: String]?).self)(self, selector) ?? [:] + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> [String: String]?).self)(self, selector) ?? [:] } return [:] } - fileprivate func path() -> String { - if self.responds(to: Selector(("pageName"))) { + func path() -> String { + if responds(to: Selector(("pageName"))) { let selector = Selector(("pageName")) let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" - } else if self.responds(to: Selector(("path"))) { + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + } else if responds(to: Selector(("path"))) { let selector = Selector(("path")) let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" } return "" } - fileprivate func pageShowTimestamp() -> Int64 { + func pageShowTimestamp() -> Int64 { let selector = Selector(("pageShowTimestamp")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - let result = unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> Int64).self)(self, selector) + let result = unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> Int64).self)(self, selector) return result > 0 ? result : 0 } return 0 } - fileprivate func textValue() -> String { + func textValue() -> String { let selector = Selector(("textValue")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" } return "" } - fileprivate func xpath() -> String { + func xpath() -> String { let selector = Selector(("xpath")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" } return "" } - fileprivate func index() -> Int32 { + func index() -> Int32 { let selector = Selector(("index")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - let result = unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> Int32).self)(self, selector) + let result = unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> Int32).self)(self, selector) return result > 0 ? result : 0 } return 0 } - fileprivate func query() -> String { + func query() -> String { let selector = Selector(("query")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" } return "" } - fileprivate func hyperlink() -> String { + func hyperlink() -> String { let selector = Selector(("hyperlink")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" } return "" } - fileprivate func attributes() -> [String: String] { + func attributes() -> [String: String] { let selector = Selector(("attributes")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - let result = unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> [String: AnyObject]?).self)(self, selector) + let result = unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> [String: AnyObject]?).self)(self, selector) if let result = result { - return result.filter({ $0.value is String }) as? [String: String] ?? [:] + return result.filter { $0.value is String } as? [String: String] ?? [:] } } return [:] } - fileprivate func orientation() -> String { + func orientation() -> String { let selector = Selector(("orientation")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" } return "" } - fileprivate func title() -> String { + func title() -> String { let selector = Selector(("title")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" } return "" } - fileprivate func referralPage() -> String { + func referralPage() -> String { let selector = Selector(("referralPage")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" } return "" } - fileprivate func protocolType() -> String { + func protocolType() -> String { let selector = Selector(("protocolType")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" } return "" } - fileprivate func eventName() -> String { + func eventName() -> String { let selector = Selector(("eventName")) - if self.responds(to: selector) { + if responds(to: selector) { let imp: IMP = method_getImplementation(class_getInstanceMethod(type(of: self), selector)!) - return unsafeBitCast(imp, to: (@convention(c)(GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" + return unsafeBitCast(imp, to: (@convention(c) (GrowingBaseEvent, Selector) -> String?).self)(self, selector) ?? "" } return "" } diff --git a/Package.swift b/Package.swift index 074144b03..1bb63db52 100644 --- a/Package.swift +++ b/Package.swift @@ -78,11 +78,11 @@ let package = Package( dependencies: [ .package( url: "https://github.com/growingio/growingio-sdk-ios-utilities.git", - "0.0.7" ..< "1.0.0" + "1.2.3" ..< "1.3.0" ), .package( url: "https://github.com/growingio/growingio-sdk-ios-performance-ext.git", - "0.0.15" ..< "1.0.0" + "1.0.1" ..< "1.1.0" ), .package( url: "https://github.com/apple/swift-protobuf.git",