Skip to content

Commit

Permalink
[feat]iOS交换实现统一切到RSSwizzle,保证方案稳定性。
Browse files Browse the repository at this point in the history
  • Loading branch information
Hulk committed Sep 22, 2023
1 parent 0d880b5 commit 9ad32c4
Show file tree
Hide file tree
Showing 12 changed files with 376 additions and 220 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
//

#import "UIGestureRecognizer+PrismExtends.h"
// Util
#import "PrismRuntimeUtil.h"
#import <objc/runtime.h>

@implementation UIGestureRecognizer (PrismExtends)
#pragma mark - property
Expand Down
77 changes: 52 additions & 25 deletions iOS/DiDiPrism/Src/Core/Intercept/UIControl+PrismIntercept.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
//

#import "UIControl+PrismIntercept.h"
#import <objc/runtime.h>
#import <RSSwizzle/RSSwizzle.h>
// Dispatcher
#import "PrismEventDispatcher.h"
// Util
#import "PrismRuntimeUtil.h"
// Category
#import "NSDictionary+PrismExtends.h"

Expand All @@ -19,27 +19,61 @@ @implementation UIControl (PrismIntercept)
+ (void)prism_swizzleMethodIMP {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[PrismRuntimeUtil hookClass:[self class] originalSelector:@selector(sendAction:to:forEvent:) swizzledSelector:@selector(prism_autoDot_sendAction:to:forEvent:)];
[PrismRuntimeUtil hookClass:[self class] originalSelector:@selector(addTarget:action:forControlEvents:) swizzledSelector:@selector(prism_autoDot_addTarget:action:forControlEvents:)];
[PrismRuntimeUtil hookClass:[self class] originalSelector:@selector(removeTarget:action:forControlEvents:) swizzledSelector:@selector(prism_autoDot_removeTarget:action:forControlEvents:)];
// Swizzle sendAction:to:forEvent:
RSSwizzleInstanceMethod(UIControl, @selector(sendAction:to:forEvent:),
RSSWReturnType(void),
RSSWArguments(SEL action, id target, UIEvent *event),
RSSWReplacement({
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"target"] = target;
params[@"action"] = NSStringFromSelector(action);
[[PrismEventDispatcher sharedInstance] dispatchEvent:PrismDispatchEventUIControlSendAction_Start withSender:self params:[params copy]];

RSSWCallOriginal(action, target, event);
}),
RSSwizzleModeAlways,
NULL);

// Swizzle addTarget:action:forControlEvents:
RSSwizzleInstanceMethod(UIControl, @selector(addTarget:action:forControlEvents:),
RSSWReturnType(void),
RSSWArguments(id target, SEL action, UIControlEvents controlEvents),
RSSWReplacement({
RSSWCallOriginal(target, action, controlEvents);

SEL swizzleSelector = NSSelectorFromString(@"prism_autoDot_addTarget:action:forControlEvents:");
Method swizzleMethod = class_getInstanceMethod([UIControl class], swizzleSelector);
IMP swizzleMethodImp = method_getImplementation(swizzleMethod);
void (*functionPointer)(id, SEL, id, SEL, UIControlEvents) = (void (*)(id, SEL, id, SEL, UIControlEvents))swizzleMethodImp;
functionPointer(self, _cmd, target, action, controlEvents);

RSSWCallOriginal(self, [self prism_autoDot_selectorForControlEvents:controlEvents], controlEvents);
}),
RSSwizzleModeAlways,
NULL);

// Swizzle removeTarget:action:forControlEvents:
RSSwizzleInstanceMethod(UIControl, @selector(removeTarget:action:forControlEvents:),
RSSWReturnType(void),
RSSWArguments(id target, SEL action, UIControlEvents controlEvents),
RSSWReplacement({
RSSWCallOriginal(target, action, controlEvents);

SEL swizzleSelector = NSSelectorFromString(@"prism_autoDot_removeTarget:action:forControlEvents:");
Method swizzleMethod = class_getInstanceMethod([UIControl class], swizzleSelector);
IMP swizzleMethodImp = method_getImplementation(swizzleMethod);
void (*functionPointer)(id, SEL, id, SEL, UIControlEvents) = (void (*)(id, SEL, id, SEL, UIControlEvents))swizzleMethodImp;
functionPointer(self, _cmd, target, action, controlEvents);

RSSWCallOriginal(self, [self prism_autoDot_selectorForControlEvents:controlEvents], controlEvents);
}),
RSSwizzleModeAlways,
NULL);
});
}

#pragma mark - private method
- (void)prism_autoDot_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event {
NSMutableDictionary *params = [NSMutableDictionary dictionary];
params[@"target"] = target;
params[@"action"] = NSStringFromSelector(action);
[[PrismEventDispatcher sharedInstance] dispatchEvent:PrismDispatchEventUIControlSendAction_Start withSender:self params:[params copy]];

//原始逻辑
[self prism_autoDot_sendAction:action to:target forEvent:event];
}

- (void)prism_autoDot_addTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents {
//原始逻辑
[self prism_autoDot_addTarget:target action:action forControlEvents:controlEvents];

NSString *controlEventsStr = [NSString stringWithFormat:@"%ld", controlEvents];
BOOL isTouchEvent = (controlEvents & UIControlEventAllTouchEvents) || (controlEvents & UIControlEventPrimaryActionTriggered);
// 忽略用户输入过程
Expand All @@ -53,18 +87,11 @@ - (void)prism_autoDot_addTarget:(id)target action:(SEL)action forControlEvents:(
self.prismAutoDotTargetAndSelector[controlEventsStr] = [NSString stringWithFormat:@"%@_&_%@", classString, actionString];
}
}

[self prism_autoDot_addTarget:self action:[self prism_autoDot_selectorForControlEvents:controlEvents] forControlEvents:controlEvents];
}

- (void)prism_autoDot_removeTarget:(id)target action:(SEL)action forControlEvents:(UIControlEvents)controlEvents {
//原始逻辑
[self prism_autoDot_removeTarget:target action:action forControlEvents:controlEvents];

NSString *controlEventsStr = [NSString stringWithFormat:@"%ld", controlEvents];
self.prismAutoDotTargetAndSelector[controlEventsStr] = @"";

[self prism_autoDot_removeTarget:self action:[self prism_autoDot_selectorForControlEvents:controlEvents] forControlEvents:controlEvents];
}

#pragma mark - property
Expand Down
88 changes: 48 additions & 40 deletions iOS/DiDiPrism/Src/Core/Intercept/UIImage+PrismIntercept.m
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,64 @@
//

#import "UIImage+PrismIntercept.h"
// Util
#import "PrismRuntimeUtil.h"
#import <objc/runtime.h>
#import <RSSwizzle/RSSwizzle.h>

@implementation UIImage (PrismIntercept)
#pragma mark - public method
+ (void)prism_swizzleMethodIMP {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[PrismRuntimeUtil hookClass:object_getClass(self) originalSelector:@selector(imageNamed:) swizzledSelector:@selector(prism_autoDot_imageNamed:) isClassMethod:YES];
#if __has_include(<UIKit/UITraitCollection.h>)
[PrismRuntimeUtil hookClass:object_getClass(self) originalSelector:@selector(imageNamed:inBundle:compatibleWithTraitCollection:) swizzledSelector:@selector(prism_autoDot_imageNamed:inBundle:compatibleWithTraitCollection:) isClassMethod:YES];
#endif
[PrismRuntimeUtil hookClass:object_getClass(self) originalSelector:@selector(imageWithContentsOfFile:) swizzledSelector:@selector(prism_autoDot_imageWithContentsOfFile:) isClassMethod:YES];
[PrismRuntimeUtil hookClass:[self class] originalSelector:@selector(initWithContentsOfFile:) swizzledSelector:@selector(prism_autoDot_initWithContentsOfFile:)];
// Swizzle imageNamed:
RSSwizzleClassMethod(UIImage, @selector(imageNamed:),
RSSWReturnType(UIImage *),
RSSWArguments(NSString *name),
RSSWReplacement({
UIImage *image = RSSWCallOriginal(name);
image.prismAutoDotImageName = [self getImageNameFromPath:name];
return image;
})
);

#if __has_include(<UIKit/UITraitCollection.h>)
// Swizzle imageNamed:inBundle:compatibleWithTraitCollection:
RSSwizzleClassMethod(UIImage, @selector(imageNamed:inBundle:compatibleWithTraitCollection:),
RSSWReturnType(UIImage *),
RSSWArguments(NSString *name, NSBundle *bundle, UITraitCollection *traitCollection),
RSSWReplacement({
UIImage *image = RSSWCallOriginal(name, bundle, traitCollection);
image.prismAutoDotImageName = [self getImageNameFromPath:name];
return image;
})
);
#endif

// Swizzle imageWithContentsOfFile:
RSSwizzleClassMethod(UIImage, @selector(imageWithContentsOfFile:),
RSSWReturnType(UIImage *),
RSSWArguments(NSString *path),
RSSWReplacement({
UIImage *image = RSSWCallOriginal(path);
image.prismAutoDotImageName = [self getImageNameFromPath:path];
return image;
})
);

// Swizzle initWithContentsOfFile:
RSSwizzleInstanceMethod(UIImage, @selector(initWithContentsOfFile:),
RSSWReturnType(UIImage *),
RSSWArguments(NSString *path),
RSSWReplacement({
UIImage *image = RSSWCallOriginal(path);
image.prismAutoDotImageName = [UIImage getImageNameFromPath:path];
return image;
}),
RSSwizzleModeAlways,
NULL);
});
}

#pragma mark - private method
+ (UIImage *)prism_autoDot_imageNamed:(NSString *)name {
UIImage *image = [self prism_autoDot_imageNamed:name];

image.prismAutoDotImageName = [self getImageNameFromPath:name];

return image;
}

+ (UIImage *)prism_autoDot_imageNamed:(NSString *)name inBundle:(NSBundle *)bundle compatibleWithTraitCollection:(UITraitCollection *)traitCollection {
UIImage *image = [self prism_autoDot_imageNamed:name inBundle:bundle compatibleWithTraitCollection:traitCollection];

image.prismAutoDotImageName = [self getImageNameFromPath:name];

return image;
}

+ (UIImage *)prism_autoDot_imageWithContentsOfFile:(NSString *)path {
UIImage *image = [self prism_autoDot_imageWithContentsOfFile:path];

image.prismAutoDotImageName = [self getImageNameFromPath:path];

return image;
}

- (instancetype)prism_autoDot_initWithContentsOfFile:(NSString *)path {
UIImage *image = [self prism_autoDot_initWithContentsOfFile:path];

image.prismAutoDotImageName = [UIImage getImageNameFromPath:path];

return image;
}

+ (NSString*)getImageNameFromPath:(NSString*)path {
static NSString *separator = @"/";
if ([path containsString:separator]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
//

#import "UILongPressGestureRecognizer+PrismIntercept.h"
#import <objc/runtime.h>
#import <RSSwizzle/RSSwizzle.h>
// Dispatcher
#import "PrismEventDispatcher.h"
// Util
#import "PrismRuntimeUtil.h"
#import "PrismInstructionAreaInfoUtil.h"
#import "PrismInstructionResponseChainInfoUtil.h"
// Category
Expand All @@ -22,6 +22,7 @@ @implementation UILongPressGestureRecognizer (PrismIntercept)
+ (void)prism_swizzleMethodIMP {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// Swizzle setState:
RSSwizzleInstanceMethod(UILongPressGestureRecognizer, @selector(setState:),
RSSWReturnType(void),
RSSWArguments(UIGestureRecognizerState state),
Expand All @@ -36,10 +37,60 @@ + (void)prism_swizzleMethodIMP {
RSSwizzleModeAlways,
NULL);

// Swizzle initWithTarget:action:
RSSwizzleInstanceMethod(UILongPressGestureRecognizer, @selector(initWithTarget:action:),
RSSWReturnType(UILongPressGestureRecognizer *),
RSSWArguments(id target, SEL action),
RSSWReplacement({
UILongPressGestureRecognizer *gesture = RSSWCallOriginal(target, action);

[gesture addTarget:self action:@selector(prism_autoDot_longPressAction:)];
// 通过[[xxx alloc] init]初始化时,target和action为nil,影响生成结果,故作此判断。
if (target && action) {
gesture.prismAutoDotTargetAndSelector = [NSString stringWithFormat:@"%@_&_%@", NSStringFromClass([target class]), NSStringFromSelector(action)];
}
else {
gesture.prismAutoDotTargetAndSelector = @"";
}

return gesture;
}),
RSSwizzleModeAlways,
NULL);

// Swizzle addTarget:action:
RSSwizzleInstanceMethod(UILongPressGestureRecognizer, @selector(addTarget:action:),
RSSWReturnType(void),
RSSWArguments(id target, SEL action),
RSSWReplacement({
RSSWCallOriginal(target, action);

RSSWCallOriginal(self, @selector(prism_autoDot_longPressAction:));
SEL swizzleSelector = NSSelectorFromString(@"prism_autoDot_addTarget:action:");
Method swizzleMethod = class_getInstanceMethod([UITapGestureRecognizer class], swizzleSelector);
IMP swizzleMethodImp = method_getImplementation(swizzleMethod);
void (*functionPointer)(id, SEL, id, SEL) = (void (*)(id, SEL, id, SEL))swizzleMethodImp;
functionPointer(self, _cmd, target, action);
}),
RSSwizzleModeAlways,
NULL);

[PrismRuntimeUtil hookClass:[self class] originalSelector:@selector(initWithTarget:action:) swizzledSelector:@selector(prism_autoDot_initWithTarget:action:)];
[PrismRuntimeUtil hookClass:[self class] originalSelector:@selector(addTarget:action:) swizzledSelector:@selector(prism_autoDot_addTarget:action:)];
[PrismRuntimeUtil hookClass:[self class] originalSelector:@selector(removeTarget:action:) swizzledSelector:@selector(prism_autoDot_removeTarget:action:)];
// Swizzle removeTarget:action:
RSSwizzleInstanceMethod(UILongPressGestureRecognizer, @selector(removeTarget:action:),
RSSWReturnType(void),
RSSWArguments(id target, SEL action),
RSSWReplacement({
RSSWCallOriginal(target, action);

RSSWCallOriginal(self, @selector(prism_autoDot_longPressAction:));
SEL swizzleSelector = NSSelectorFromString(@"prism_autoDot_removeTarget:action:");
Method swizzleMethod = class_getInstanceMethod([UITapGestureRecognizer class], swizzleSelector);
IMP swizzleMethodImp = method_getImplementation(swizzleMethod);
void (*functionPointer)(id, SEL, id, SEL) = (void (*)(id, SEL, id, SEL))swizzleMethodImp;
functionPointer(self, _cmd, target, action);
}),
RSSwizzleModeAlways,
NULL);
});
}

Expand All @@ -62,38 +113,13 @@ - (void)prism_autoDot_setState:(UIGestureRecognizerState)state {
}
}


- (instancetype)prism_autoDot_initWithTarget:(id)target action:(SEL)action {
//原始逻辑
UILongPressGestureRecognizer *gesture = [self prism_autoDot_initWithTarget:target action:action];

[gesture addTarget:self action:@selector(prism_autoDot_longPressAction:)];
// 通过[[xxx alloc] init]初始化时,target和action为nil,影响生成结果,故作此判断。
if (target && action) {
gesture.prismAutoDotTargetAndSelector = [NSString stringWithFormat:@"%@_&_%@", NSStringFromClass([target class]), NSStringFromSelector(action)];
}
else {
gesture.prismAutoDotTargetAndSelector = @"";
}

return gesture;
}

- (void)prism_autoDot_addTarget:(id)target action:(SEL)action {
//原始逻辑
[self prism_autoDot_addTarget:target action:action];

[self prism_autoDot_addTarget:self action:@selector(prism_autoDot_longPressAction:)];
if (!self.prismAutoDotTargetAndSelector.length) {
self.prismAutoDotTargetAndSelector = [NSString stringWithFormat:@"%@_&_%@", NSStringFromClass([target class]), NSStringFromSelector(action)];
}
}

- (void)prism_autoDot_removeTarget:(id)target action:(SEL)action {
//原始逻辑
[self prism_autoDot_removeTarget:target action:action];

[self prism_autoDot_removeTarget:self action:@selector(prism_autoDot_longPressAction:)];
self.prismAutoDotTargetAndSelector = @"";
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
//

#import "UIResponder+PrismIntercept.h"
// Util
#import "PrismRuntimeUtil.h"
#import <objc/runtime.h>

@implementation UIResponder (PrismIntercept)

Expand Down
Loading

0 comments on commit 9ad32c4

Please sign in to comment.