Ta android + ios

This commit is contained in:
LYP
2024-08-07 20:22:28 +08:00
parent 69fee08c61
commit 76458664d8
722 changed files with 41709 additions and 1 deletions

View File

@@ -0,0 +1,29 @@
#import <Foundation/Foundation.h>
#import "TDDelegateProxyObject.h"
NS_ASSUME_NONNULL_BEGIN
@interface NSObject (TDDelegateProxy)
@property (nonatomic, copy, nullable) NSSet<NSString *> *thinkingdata_optionalSelectors;
@property (nonatomic, strong, nullable) TDDelegateProxyObject *thinkingdata_delegateObject;
/// hook respondsToSelector to resolve optional selectors
/// @param aSelector selector
- (BOOL)thinkingdata_respondsToSelector:(SEL)aSelector;
@end
@interface NSProxy (TDDelegateProxy)
@property (nonatomic, copy, nullable) NSSet<NSString *> *thinkingdata_optionalSelectors;
@property (nonatomic, strong, nullable) TDDelegateProxyObject *thinkingdata_delegateObject;
/// hook respondsToSelector to resolve optional selectors
/// @param aSelector selector
- (BOOL)thinkingdata_respondsToSelector:(SEL)aSelector;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: b9402120bfa12c849bdbf985c51c0535
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,69 @@
#import "NSObject+TDDelegateProxy.h"
#import <objc/runtime.h>
static void *const kTDNSObjectDelegateOptionalSelectorsKey = (void *)&kTDNSObjectDelegateOptionalSelectorsKey;
static void *const kTDNSObjectDelegateObjectKey = (void *)&kTDNSObjectDelegateObjectKey;
static void *const kTDNSProxyDelegateOptionalSelectorsKey = (void *)&kTDNSProxyDelegateOptionalSelectorsKey;
static void *const kTDNSProxyDelegateObjectKey = (void *)&kTDNSProxyDelegateObjectKey;
@implementation NSObject (TDDelegateProxy)
- (NSSet<NSString *> *)thinkingdata_optionalSelectors {
return objc_getAssociatedObject(self, kTDNSObjectDelegateOptionalSelectorsKey);
}
- (void)setThinkingdata_optionalSelectors:(NSSet<NSString *> *)thinkingdata_optionalSelectors {
objc_setAssociatedObject(self, kTDNSObjectDelegateOptionalSelectorsKey, thinkingdata_optionalSelectors, OBJC_ASSOCIATION_COPY);
}
- (TDDelegateProxyObject *)thinkingdata_delegateObject {
return objc_getAssociatedObject(self, kTDNSObjectDelegateObjectKey);
}
- (void)setThinkingdata_delegateObject:(TDDelegateProxyObject *)thinkingdata_delegateObject {
objc_setAssociatedObject(self, kTDNSObjectDelegateObjectKey, thinkingdata_delegateObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)thinkingdata_respondsToSelector:(SEL)aSelector {
if ([self thinkingdata_respondsToSelector:aSelector]) {
return YES;
}
if ([self.thinkingdata_optionalSelectors containsObject:NSStringFromSelector(aSelector)]) {
return YES;
}
return NO;
}
@end
@implementation NSProxy (TDDelegateProxy)
- (NSSet<NSString *> *)thinkingdata_optionalSelectors {
return objc_getAssociatedObject(self, kTDNSProxyDelegateOptionalSelectorsKey);
}
- (void)setThinkingdata_optionalSelectors:(NSSet<NSString *> *)thinkingdata_optionalSelectors {
objc_setAssociatedObject(self, kTDNSProxyDelegateOptionalSelectorsKey, thinkingdata_optionalSelectors, OBJC_ASSOCIATION_COPY);
}
- (TDDelegateProxyObject *)thinkingdata_delegateObject {
return objc_getAssociatedObject(self, kTDNSProxyDelegateObjectKey);
}
- (void)setThinkingdata_delegateObject:(TDDelegateProxyObject *)thinkingdata_delegateObject {
objc_setAssociatedObject(self, kTDNSProxyDelegateObjectKey, thinkingdata_delegateObject, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (BOOL)thinkingdata_respondsToSelector:(SEL)aSelector {
if ([self thinkingdata_respondsToSelector:aSelector]) {
return YES;
}
if ([self.thinkingdata_optionalSelectors containsObject:NSStringFromSelector(aSelector)]) {
return YES;
}
return NO;
}
@end

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 7c8d3b9224659564b9fe4db839be6c5b
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,16 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TDClassHelper : NSObject
+ (Class _Nullable)allocateClassWithObject:(id)object className:(NSString *)className;
+ (void)registerClass:(Class)cla;
+ (BOOL)setObject:(id)object toClass:(Class)cla;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 7e6c0a59660b31f419175804f218c192
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,36 @@
#import "TDClassHelper.h"
#import <objc/runtime.h>
@implementation TDClassHelper
+ (Class _Nullable)allocateClassWithObject:(id)object className:(NSString *)className {
if (!object || className.length <= 0) {
return nil;
}
Class originalClass = object_getClass(object);
Class subclass = NSClassFromString(className);
if (subclass) {
return nil;
}
subclass = objc_allocateClassPair(originalClass, className.UTF8String, 0);
if (class_getInstanceSize(originalClass) != class_getInstanceSize(subclass)) {
return nil;
}
return subclass;
}
+ (void)registerClass:(Class)cla {
if (cla) {
objc_registerClassPair(cla);
}
}
+ (BOOL)setObject:(id)object toClass:(Class)cla {
if (cla && object && object_getClass(object) != cla) {
return object_setClass(object, cla);
}
return NO;
}
@end

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 420d8a217a542bf4981ba78f9aed757c
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,25 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@protocol TDHookDelegateProtocol <NSObject>
@optional
+ (NSSet<NSString *> *)optionalSelectors;
@end
@interface TDDelegateProxy : NSObject <TDHookDelegateProtocol>
+ (void)proxyDelegate:(id)delegate selectors:(NSSet<NSString *>*)selectors;
+ (void)invokeWithTarget:(NSObject *)target selector:(SEL)selector, ...;
+ (BOOL)invokeReturnBOOLWithTarget:(NSObject *)target selector:(SEL)selector arg1:(id)arg1 arg2:(id)arg2;
+ (BOOL)invokeReturnBOOLWithTarget:(NSObject *)target selector:(SEL)selector arg1:(id)arg1 arg2:(id)arg2 arg3:(id)arg3;
+ (void)resolveOptionalSelectorsForDelegate:(id)delegate;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 4777c08c43760724ab9649b8c1a1752d
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,200 @@
#import "TDDelegateProxy.h"
#import "TDClassHelper.h"
#import "TDMethodHelper.h"
#import "NSObject+TDDelegateProxy.h"
#import <objc/message.h>
static NSString * const kTDNSObjectRemoveObserverSelector = @"removeObserver:forKeyPath:";
static NSString * const kTDNSObjectAddObserverSelector = @"addObserver:forKeyPath:options:context:";
static NSString * const kTDNSObjectClassSelector = @"class";
@implementation TDDelegateProxy
+ (void)proxyDelegate:(id)delegate selectors:(NSSet<NSString *> *)selectors {
if (object_isClass(delegate) || selectors.count == 0) {
return;
}
Class proxyClass = [self class];
NSMutableSet *delegateSelectors = [NSMutableSet setWithSet:selectors];
TDDelegateProxyObject *object = [delegate thinkingdata_delegateObject];
if (!object) {
object = [[TDDelegateProxyObject alloc] initWithDelegate:delegate proxy:proxyClass];
[delegate setThinkingdata_delegateObject:object];
}
[delegateSelectors minusSet:object.selectors];
if (delegateSelectors.count == 0) {
return;
}
if (object.thinkingClass) {
[self addInstanceMethodWithSelectors:delegateSelectors fromClass:proxyClass toClass:object.thinkingClass];
[object.selectors unionSet:delegateSelectors];
if (![object_getClass(delegate) isSubclassOfClass:object.thinkingClass]) {
[TDClassHelper setObject:delegate toClass:object.thinkingClass];
}
return;
}
if (object.kvoClass) {
if ([delegate isKindOfClass:NSObject.class] && ![object.selectors containsObject:kTDNSObjectRemoveObserverSelector]) {
[delegateSelectors addObject:kTDNSObjectRemoveObserverSelector];
}
[self addInstanceMethodWithSelectors:delegateSelectors fromClass:proxyClass toClass:object.kvoClass];
[object.selectors unionSet:delegateSelectors];
return;
}
Class thinkingClass = [TDClassHelper allocateClassWithObject:delegate className:object.thinkingClassName];
[TDClassHelper registerClass:thinkingClass];
if ([delegate isKindOfClass:NSObject.class] && ![object.selectors containsObject:kTDNSObjectAddObserverSelector]) {
[delegateSelectors addObject:kTDNSObjectAddObserverSelector];
}
if (![object.selectors containsObject:kTDNSObjectClassSelector]) {
[delegateSelectors addObject:kTDNSObjectClassSelector];
}
[self addInstanceMethodWithSelectors:delegateSelectors fromClass:proxyClass toClass:thinkingClass];
[object.selectors unionSet:delegateSelectors];
[TDClassHelper setObject:delegate toClass:thinkingClass];
}
+ (void)addInstanceMethodWithSelectors:(NSSet<NSString *> *)selectors fromClass:(Class)fromClass toClass:(Class)toClass {
for (NSString *selector in selectors) {
SEL sel = NSSelectorFromString(selector);
[TDMethodHelper addInstanceMethodWithSelector:sel fromClass:fromClass toClass:toClass];
}
}
+ (BOOL)invokeReturnBOOLWithTarget:(NSObject *)target selector:(SEL)selector arg1:(id)arg1 arg2:(id)arg2 arg3:(id)arg3 {
Class originalClass = target.thinkingdata_delegateObject.delegateISA;
struct objc_super targetSuper = {
.receiver = target,
.super_class = originalClass
};
BOOL returnValue = NO;
@try {
returnValue = ((BOOL (*)(struct objc_super *, SEL, id, id, id))objc_msgSendSuper)(&targetSuper, selector, arg1, arg2, arg3);
} @catch (NSException *exception) {
NSLog(@"msgSendSuper with exception: %@", exception);
} @finally {
}
return returnValue;
}
+ (BOOL)invokeReturnBOOLWithTarget:(NSObject *)target selector:(SEL)selector arg1:(id)arg1 arg2:(id)arg2 {
Class originalClass = target.thinkingdata_delegateObject.delegateISA;
struct objc_super targetSuper = {
.receiver = target,
.super_class = originalClass
};
BOOL returnValue = NO;
@try {
returnValue = ((BOOL (*)(struct objc_super *, SEL, id, id))objc_msgSendSuper)(&targetSuper, selector, arg1, arg2);
} @catch (NSException *exception) {
NSLog(@"msgSendSuper with exception: %@", exception);
} @finally {
}
return returnValue;
}
+ (void)invokeWithTarget:(NSObject *)target selector:(SEL)selector, ... {
Class originalClass = target.thinkingdata_delegateObject.delegateISA;
va_list args;
va_start(args, selector);
id arg1 = nil, arg2 = nil, arg3 = nil, arg4 = nil;
NSInteger count = [NSStringFromSelector(selector) componentsSeparatedByString:@":"].count - 1;
for (NSInteger i = 0; i < count; i++) {
i == 0 ? (arg1 = va_arg(args, id)) : nil;
i == 1 ? (arg2 = va_arg(args, id)) : nil;
i == 2 ? (arg3 = va_arg(args, id)) : nil;
i == 3 ? (arg4 = va_arg(args, id)) : nil;
}
struct objc_super targetSuper = {
.receiver = target,
.super_class = originalClass
};
@try {
void (*func)(struct objc_super *, SEL, id, id, id, id) = (void *)&objc_msgSendSuper;
func(&targetSuper, selector, arg1, arg2, arg3, arg4);
} @catch (NSException *exception) {
NSLog(@"msgSendSuper with exception: %@", exception);
} @finally {
va_end(args);
}
}
+ (void)resolveOptionalSelectorsForDelegate:(id)delegate {
if (object_isClass(delegate)) {
return;
}
NSSet *currentOptionalSelectors = ((NSObject *)delegate).thinkingdata_optionalSelectors;
NSMutableSet *optionalSelectors = [[NSMutableSet alloc] init];
if (currentOptionalSelectors) {
[optionalSelectors unionSet:currentOptionalSelectors];
}
if ([self respondsToSelector:@selector(optionalSelectors)] &&[self optionalSelectors]) {
[optionalSelectors unionSet:[self optionalSelectors]];
}
((NSObject *)delegate).thinkingdata_optionalSelectors = [optionalSelectors copy];
}
@end
#pragma mark - Class
@implementation TDDelegateProxy (Class)
- (Class)class {
if (self.thinkingdata_delegateObject.delegateClass) {
return self.thinkingdata_delegateObject.delegateClass;
}
return [super class];
}
@end
#pragma mark - KVO
@implementation TDDelegateProxy (KVO)
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context {
[super addObserver:observer forKeyPath:keyPath options:options context:context];
if (self.thinkingdata_delegateObject) {
[TDMethodHelper replaceInstanceMethodWithDestinationSelector:@selector(class) sourceSelector:@selector(class) fromClass:TDDelegateProxy.class toClass:object_getClass(self)];
}
}
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath {
BOOL oldClassIsKVO = [TDDelegateProxyObject isKVOClass:object_getClass(self)];
[super removeObserver:observer forKeyPath:keyPath];
BOOL newClassIsKVO = [TDDelegateProxyObject isKVOClass:object_getClass(self)];
if (oldClassIsKVO && !newClassIsKVO) {
Class delegateProxy = self.thinkingdata_delegateObject.delegateProxy;
NSSet *selectors = [self.thinkingdata_delegateObject.selectors copy];
[self.thinkingdata_delegateObject removeKVO];
if ([delegateProxy respondsToSelector:@selector(proxyDelegate:selectors:)]) {
[delegateProxy proxyDelegate:self selectors:selectors];
}
}
}
@end

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 315c41452d35ed64aa832c93b52b2b3a
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,34 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TDDelegateProxyObject : NSObject
@property (nonatomic, strong) Class delegateISA;
@property (nonatomic, strong, nullable) Class kvoClass;
@property (nonatomic, copy, nullable) NSString *thinkingClassName;
@property (nonatomic, strong, readonly, nullable) Class thinkingClass;
@property (nonatomic, strong) id delegateClass;
@property (nonatomic, strong) Class delegateProxy;
@property (nonatomic, strong) NSMutableSet *selectors;
- (instancetype)initWithDelegate:(id)delegate proxy:(id)proxy;
- (void)removeKVO;
@end
@interface TDDelegateProxyObject (Utils)
+ (BOOL)isKVOClass:(Class _Nullable)cls;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 85ad8b65ff9356a47a3a7ae39c279ddb
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,56 @@
#import "TDDelegateProxyObject.h"
#import <objc/message.h>
NSString * const kTDDelegateClassThinkingSuffix = @"_TD.THINKINGDATA";
NSString * const kTDDelegateClassKVOPrefix = @"KVONotifying_";
@implementation TDDelegateProxyObject
- (instancetype)initWithDelegate:(id)delegate proxy:(id)proxy {
self = [super init];
if (self) {
_delegateProxy = proxy;
_selectors = [NSMutableSet set];
_delegateClass = [delegate class];
Class cla = object_getClass(delegate);
NSString *name = NSStringFromClass(cla);
if ([name containsString:kTDDelegateClassKVOPrefix]) {
_delegateISA = class_getSuperclass(cla);
_kvoClass = cla;
} else if ([name containsString:kTDDelegateClassThinkingSuffix]) {
_delegateISA = class_getSuperclass(cla);
_thinkingClassName = name;
} else {
_delegateISA = cla;
_thinkingClassName = [NSString stringWithFormat:@"%@%@", name, kTDDelegateClassThinkingSuffix];
}
}
return self;
}
- (Class)thinkingClass {
return NSClassFromString(self.thinkingClassName);
}
- (void)removeKVO {
self.kvoClass = nil;
self.thinkingClassName = [NSString stringWithFormat:@"%@%@", self.delegateISA, kTDDelegateClassThinkingSuffix];
[self.selectors removeAllObjects];
}
@end
#pragma mark - Utils
@implementation TDDelegateProxyObject (Utils)
+ (BOOL)isKVOClass:(Class _Nullable)cls {
return [NSStringFromClass(cls) containsString:kTDDelegateClassKVOPrefix];
}
@end

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: bc0971c2929b9c34095463469ddf31cd
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,24 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface TDMethodHelper : NSObject
+ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass;
+ (void)addInstanceMethodWithSelector:(SEL)methodSelector fromClass:(Class)fromClass toClass:(Class)toClass;
+ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector sourceSelector:(SEL)sourceSelector fromClass:(Class)fromClass toClass:(Class)toClass;
+ (void)addClassMethodWithDestinationSelector:(SEL)destinationSelector sourceSelector:(SEL)sourceSelector fromClass:(Class)fromClass toClass:(Class)toClass;
+ (IMP _Nullable)replaceInstanceMethodWithDestinationSelector:(SEL)destinationSelector sourceSelector:(SEL)sourceSelector fromClass:(Class)fromClass toClass:(Class)toClass;
/// swizzle respondsToSelector 方法
/// 用于处理未实现代理方法也能采集事件的逻辑
+ (void)swizzleRespondsToSelector;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 4b944f39f6447d9459b90a9b3dcf34e8
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,59 @@
#import "TDMethodHelper.h"
#import <objc/runtime.h>
#import "TDNewSwizzle.h"
#import "NSObject+TDDelegateProxy.h"
@implementation TDMethodHelper
+ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass {
Method aMethod = class_getInstanceMethod(aClass, selector);
return method_getImplementation(aMethod);
}
+ (void)addInstanceMethodWithSelector:(SEL)methodSelector fromClass:(Class)fromClass toClass:(Class)toClass {
[self addInstanceMethodWithDestinationSelector:methodSelector sourceSelector:methodSelector fromClass:fromClass toClass:toClass];
}
+ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector sourceSelector:(SEL)sourceSelector fromClass:(Class)fromClass toClass:(Class)toClass {
Method method = class_getInstanceMethod(fromClass, sourceSelector);
if (!method) {
return;
}
IMP methodIMP = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) {
IMP destinationIMP = [self implementationOfMethodSelector:destinationSelector fromClass:toClass];
if (destinationIMP == methodIMP) {
return;
}
class_replaceMethod(toClass, destinationSelector, methodIMP, types);
}
}
+ (void)addClassMethodWithDestinationSelector:(SEL)destinationSelector sourceSelector:(SEL)sourceSelector fromClass:(Class)fromClass toClass:(Class)toClass {
Method method = class_getClassMethod(fromClass, sourceSelector);
IMP methodIMP = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) {
class_replaceMethod(toClass, destinationSelector, methodIMP, types);
}
}
+ (IMP _Nullable)replaceInstanceMethodWithDestinationSelector:(SEL)destinationSelector sourceSelector:(SEL)sourceSelector fromClass:(Class)fromClass toClass:(Class)toClass {
Method method = class_getInstanceMethod(fromClass, sourceSelector);
IMP methodIMP = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
return class_replaceMethod(toClass, destinationSelector, methodIMP, types);
}
+ (void)swizzleRespondsToSelector {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
[NSObject td_new_swizzleMethod:@selector(respondsToSelector:)
withMethod:@selector(thinkingdata_respondsToSelector:)
error:NULL];
});
}
@end

View File

@@ -0,0 +1,33 @@
fileFormatVersion: 2
guid: 0b2861556d1c5c44eac95b8110fb3481
PluginImporter:
externalObjects: {}
serializedVersion: 2
iconMap: {}
executionOrder: {}
defineConstraints: []
isPreloaded: 0
isOverridable: 0
isExplicitlyReferenced: 0
validateReferences: 1
platformData:
- first:
Any:
second:
enabled: 0
settings: {}
- first:
Editor: Editor
second:
enabled: 0
settings:
DefaultValueInitialized: true
- first:
iPhone: iOS
second:
enabled: 1
settings:
AddToEmbeddedBinaries: false
userData:
assetBundleName:
assetBundleVariant: