From b7520c357370a7171129bf757f1d2cb138570d95 Mon Sep 17 00:00:00 2001 From: andysheng Date: Fri, 6 Jan 2023 22:14:59 +0800 Subject: [PATCH 1/5] add: implement weak obj --- Src/Main/Server/Others/LKS_WeakObjContainer.h | 20 +++++++++++++++++++ Src/Main/Server/Others/LKS_WeakObjContainer.m | 18 +++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 Src/Main/Server/Others/LKS_WeakObjContainer.h create mode 100644 Src/Main/Server/Others/LKS_WeakObjContainer.m diff --git a/Src/Main/Server/Others/LKS_WeakObjContainer.h b/Src/Main/Server/Others/LKS_WeakObjContainer.h new file mode 100644 index 0000000..a2ffa03 --- /dev/null +++ b/Src/Main/Server/Others/LKS_WeakObjContainer.h @@ -0,0 +1,20 @@ +// +// LKS_WeakObjContainer.h +// LookinServer +// +// Created by andysheng on 2023/1/6. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface LKS_WeakObjContainer : NSObject + +@property (nonatomic, weak) ObjectType weakObj; + ++ (instancetype)containerWithObj:(ObjectType)obj; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Src/Main/Server/Others/LKS_WeakObjContainer.m b/Src/Main/Server/Others/LKS_WeakObjContainer.m new file mode 100644 index 0000000..348ab22 --- /dev/null +++ b/Src/Main/Server/Others/LKS_WeakObjContainer.m @@ -0,0 +1,18 @@ +// +// LKS_WeakObjContainer.m +// LookinServer +// +// Created by andysheng on 2023/1/6. +// + +#import "LKS_WeakObjContainer.h" + +@implementation LKS_WeakObjContainer + ++ (instancetype)containerWithObj:(id)obj { + LKS_WeakObjContainer *container = [LKS_WeakObjContainer new]; + container.weakObj = obj; + return container; +} + +@end From 5778d05b54760b687adb75bfcef6fa4df17cb825 Mon Sep 17 00:00:00 2001 From: andysheng Date: Fri, 6 Jan 2023 22:39:35 +0800 Subject: [PATCH 2/5] add: combine windows from different sources --- .../Server/Category/UIView+LookinServer.m | 5 +- .../Inspect/LKS_LocalInspectViewController.m | 3 +- .../Others/LKS_HierarchyDisplayItemsMaker.m | 3 +- Src/Main/Server/Others/LKS_TraceManager.m | 3 +- Src/Main/Server/Others/LKS_WindowDiscovery.h | 29 ++++++ Src/Main/Server/Others/LKS_WindowDiscovery.m | 88 +++++++++++++++++++ 6 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 Src/Main/Server/Others/LKS_WindowDiscovery.h create mode 100644 Src/Main/Server/Others/LKS_WindowDiscovery.m diff --git a/Src/Main/Server/Category/UIView+LookinServer.m b/Src/Main/Server/Category/UIView+LookinServer.m index 710502f..0552099 100644 --- a/Src/Main/Server/Category/UIView+LookinServer.m +++ b/Src/Main/Server/Category/UIView+LookinServer.m @@ -13,6 +13,7 @@ #import "LookinObject.h" #import "LookinAutoLayoutConstraint.h" #import "LookinServerDefines.h" +#import "LKS_WindowDiscovery.h" @implementation UIView (LookinServer) @@ -125,10 +126,10 @@ - (float)lks_horizontalContentCompressionResistancePriority { } + (void)lks_rebuildGlobalInvolvedRawConstraints { - [[[UIApplication sharedApplication].windows copy] enumerateObjectsUsingBlock:^(__kindof UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop) { + [[[LKS_WindowDiscovery sharedInstance].windows copy] enumerateObjectsUsingBlock:^(__kindof UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop) { [self lks_removeInvolvedRawConstraintsForViewsRootedByView:window]; }]; - [[[UIApplication sharedApplication].windows copy] enumerateObjectsUsingBlock:^(__kindof UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop) { + [[[LKS_WindowDiscovery sharedInstance].windows copy] enumerateObjectsUsingBlock:^(__kindof UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop) { [self lks_addInvolvedRawConstraintsForViewsRootedByView:window]; }]; } diff --git a/Src/Main/Server/Inspect/LKS_LocalInspectViewController.m b/Src/Main/Server/Inspect/LKS_LocalInspectViewController.m index e477506..eab76d8 100644 --- a/Src/Main/Server/Inspect/LKS_LocalInspectViewController.m +++ b/Src/Main/Server/Inspect/LKS_LocalInspectViewController.m @@ -15,6 +15,7 @@ #import "UIImage+LookinServer.h" #import "LookinServerDefines.h" #import "UIColor+LookinServer.h" +#import "LKS_WindowDiscovery.h" static CGRect const kInvalidRect = (CGRect){-2, -2, 0, 0}; @@ -557,7 +558,7 @@ - (void)_handleEnterForegound { - (UIView *)_targetViewAtPoint:(CGPoint)point { __block UIView *targetView = nil; - [[UIApplication sharedApplication].windows enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(__kindof UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop) { + [[LKS_WindowDiscovery sharedInstance].windows enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(__kindof UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop) { if (targetView) { *stop = YES; return; diff --git a/Src/Main/Server/Others/LKS_HierarchyDisplayItemsMaker.m b/Src/Main/Server/Others/LKS_HierarchyDisplayItemsMaker.m index e44a1be..33f7d2e 100644 --- a/Src/Main/Server/Others/LKS_HierarchyDisplayItemsMaker.m +++ b/Src/Main/Server/Others/LKS_HierarchyDisplayItemsMaker.m @@ -15,13 +15,14 @@ #import "LKS_EventHandlerMaker.h" #import "LookinServerDefines.h" #import "UIColor+LookinServer.h" +#import "LKS_WindowDiscovery.h" @implementation LKS_HierarchyDisplayItemsMaker + (NSArray *)itemsWithScreenshots:(BOOL)hasScreenshots attrList:(BOOL)hasAttrList lowImageQuality:(BOOL)lowQuality includedWindows:(NSArray *)includedWindows excludedWindows:(NSArray *)excludedWindows { [[LKS_TraceManager sharedInstance] reload]; - NSArray *windows = [[UIApplication sharedApplication].windows copy]; + NSArray *windows = [[LKS_WindowDiscovery sharedInstance].windows copy]; NSMutableArray *resultArray = [NSMutableArray arrayWithCapacity:windows.count]; [windows enumerateObjectsUsingBlock:^(__kindof UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop) { if (includedWindows.count) { diff --git a/Src/Main/Server/Others/LKS_TraceManager.m b/Src/Main/Server/Others/LKS_TraceManager.m index 2f3c793..ebe217a 100644 --- a/Src/Main/Server/Others/LKS_TraceManager.m +++ b/Src/Main/Server/Others/LKS_TraceManager.m @@ -13,6 +13,7 @@ #import "LookinIvarTrace.h" #import "LookinServerDefines.h" #import "LKS_LocalInspectManager.h" +#import "LKS_WindowDiscovery.h" #ifdef LOOKIN_SERVER_SWIFT_ENABLED @@ -50,7 +51,7 @@ - (void)reload { // 把旧的先都清理掉 [NSObject lks_clearAllObjectsTraces]; - [[[UIApplication sharedApplication].windows copy] enumerateObjectsUsingBlock:^(__kindof UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop) { + [[[LKS_WindowDiscovery sharedInstance].windows copy] enumerateObjectsUsingBlock:^(__kindof UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop) { [self _addTraceForLayersRootedByLayer:window.layer]; }]; } diff --git a/Src/Main/Server/Others/LKS_WindowDiscovery.h b/Src/Main/Server/Others/LKS_WindowDiscovery.h new file mode 100644 index 0000000..1c75cfe --- /dev/null +++ b/Src/Main/Server/Others/LKS_WindowDiscovery.h @@ -0,0 +1,29 @@ +// +// LKS_WindowDiscovery.h +// LookinServer +// +// Created by andysheng on 2023/1/6. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class UIWindow; +@interface LKS_WindowDiscovery : NSObject + +/// combine different source of windows: +/// 1. [UIApplication sharedApplication].windows +/// 2. customWindow +/// 3. customView.window +@property (nonatomic, readonly) NSArray *windows; + ++ (instancetype)sharedInstance; + +- (void)addCustomWindow:(UIWindow *)window; + +- (void)addCustomWindowWithView:(UIView *)view; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Src/Main/Server/Others/LKS_WindowDiscovery.m b/Src/Main/Server/Others/LKS_WindowDiscovery.m new file mode 100644 index 0000000..0f8f505 --- /dev/null +++ b/Src/Main/Server/Others/LKS_WindowDiscovery.m @@ -0,0 +1,88 @@ +// +// LKS_WindowDiscovery.m +// LookinServer +// +// Created by andysheng on 2023/1/6. +// + +#import "LKS_WindowDiscovery.h" +#import "LKS_WeakObjContainer.h" + +@interface LKS_WindowDiscovery () + +@property (nonatomic, strong) NSArray *> *customWindows; +@property (nonatomic, strong) NSArray *> *customViews; + +@end + +@implementation LKS_WindowDiscovery + ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static LKS_WindowDiscovery *instance = nil; + dispatch_once(&onceToken, ^{ + instance = [[super allocWithZone:NULL] init]; + }); + return instance; +} + +- (void)addCustomWindow:(UIWindow *)window { + if (!window) { + return; + } + @synchronized (self) { + NSMutableArray *> *mContainers = self.customWindows ? self.customWindows.mutableCopy : [NSMutableArray array]; + [mContainers enumerateObjectsWithOptions:NSEnumerationReverse + usingBlock:^(LKS_WeakObjContainer * _Nonnull container, NSUInteger idx, BOOL * _Nonnull stop) { + if (!container.weakObj || container.weakObj == window) { + [mContainers removeObject:container]; + } + }]; + [mContainers addObject:[LKS_WeakObjContainer containerWithObj:window]]; + self.customWindows = mContainers.copy; + } +} + +- (void)addCustomWindowWithView:(UIView *)view { + if (!view) { + return; + } + @synchronized (self) { + NSMutableArray *> *mContainers = self.customViews ? self.customViews.mutableCopy : NSMutableArray.array; + [mContainers enumerateObjectsWithOptions:NSEnumerationReverse + usingBlock:^(LKS_WeakObjContainer * _Nonnull container, NSUInteger idx, BOOL * _Nonnull stop) { + if (!container.weakObj || container.weakObj == view) { + [mContainers removeObject:container]; + } + }]; + [mContainers addObject:[LKS_WeakObjContainer containerWithObj:view]]; + self.customViews = mContainers.copy; + } +} + +- (NSArray *)windows { + NSMutableArray *retWindows = [[UIApplication sharedApplication].windows mutableCopy]; + NSSet *windowSet = [NSSet setWithArray:retWindows]; + + NSMutableArray *candidateCustomWindows = [NSMutableArray array]; + [self.customWindows enumerateObjectsUsingBlock:^(LKS_WeakObjContainer * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + UIWindow *window = (UIWindow *)obj.weakObj; + if (window) { + [candidateCustomWindows addObject:window]; + } + }]; + [self.customViews enumerateObjectsUsingBlock:^(LKS_WeakObjContainer * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { + UIWindow *window = ((UIView *)obj.weakObj).window; + if (window) { + [candidateCustomWindows addObject:window]; + } + }]; + [candidateCustomWindows enumerateObjectsUsingBlock:^(UIWindow * _Nonnull window, NSUInteger idx, BOOL * _Nonnull stop) { + if (![windowSet containsObject:window]) { + [retWindows addObject:window]; + } + }]; + return retWindows; +} + +@end From b969f0c859ecffd583db4732354ee59fd672d2d4 Mon Sep 17 00:00:00 2001 From: andysheng Date: Fri, 6 Jan 2023 22:41:00 +0800 Subject: [PATCH 3/5] add: trace UITextView.inputview/inputAccessoryView's window --- .../Server/Category/UITextView+LookinServer.m | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Src/Main/Server/Category/UITextView+LookinServer.m b/Src/Main/Server/Category/UITextView+LookinServer.m index bd81a8b..dcfb0d1 100644 --- a/Src/Main/Server/Category/UITextView+LookinServer.m +++ b/Src/Main/Server/Category/UITextView+LookinServer.m @@ -8,10 +8,25 @@ // https://lookin.work // +#import #import "UITextView+LookinServer.h" +#import "LKS_WindowDiscovery.h" @implementation UITextView (LookinServer) ++ (void)load { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Method oriMethod = class_getInstanceMethod([self class], @selector(setInputView:)); + Method newMethod = class_getInstanceMethod([self class], @selector(lks_setInputView:)); + method_exchangeImplementations(oriMethod, newMethod); + + oriMethod = class_getInstanceMethod([self class], @selector(setInputAccessoryView:)); + newMethod = class_getInstanceMethod([self class], @selector(lks_setInputAccessoryView:)); + method_exchangeImplementations(oriMethod, newMethod); + }); +} + - (CGFloat)lks_fontSize { return self.font.pointSize; } @@ -24,6 +39,16 @@ - (NSString *)lks_fontName { return self.font.fontName; } +- (void)lks_setInputView:(UIView *)inputView { + [self lks_setInputView:inputView]; + [[LKS_WindowDiscovery sharedInstance] addCustomWindowWithView:inputView]; +} + +- (void)lks_setInputAccessoryView:(UIView *)inputAccessoryView { + [self lks_setInputAccessoryView:inputAccessoryView]; + [[LKS_WindowDiscovery sharedInstance] addCustomWindowWithView:inputAccessoryView]; +} + @end #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ From 0326b914af7f4a8ca1810ae218751857c73ad56a Mon Sep 17 00:00:00 2001 From: andysheng Date: Fri, 6 Jan 2023 22:41:28 +0800 Subject: [PATCH 4/5] add: trace UITextField.inputview/inputAccessoryView's window --- .../Category/UITextField+LookinServer.m | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Src/Main/Server/Category/UITextField+LookinServer.m b/Src/Main/Server/Category/UITextField+LookinServer.m index 9e07a76..704376f 100644 --- a/Src/Main/Server/Category/UITextField+LookinServer.m +++ b/Src/Main/Server/Category/UITextField+LookinServer.m @@ -8,10 +8,25 @@ // https://lookin.work // +#import #import "UITextField+LookinServer.h" +#import "LKS_WindowDiscovery.h" @implementation UITextField (LookinServer) ++ (void)load { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + Method oriMethod = class_getInstanceMethod([self class], @selector(setInputView:)); + Method newMethod = class_getInstanceMethod([self class], @selector(lks_setInputView:)); + method_exchangeImplementations(oriMethod, newMethod); + + oriMethod = class_getInstanceMethod([self class], @selector(setInputAccessoryView:)); + newMethod = class_getInstanceMethod([self class], @selector(lks_setInputAccessoryView:)); + method_exchangeImplementations(oriMethod, newMethod); + }); +} + - (CGFloat)lks_fontSize { return self.font.pointSize; } @@ -24,6 +39,16 @@ - (NSString *)lks_fontName { return self.font.fontName; } +- (void)lks_setInputView:(UIView *)inputView { + [self lks_setInputView:inputView]; + [[LKS_WindowDiscovery sharedInstance] addCustomWindowWithView:inputView]; +} + +- (void)lks_setInputAccessoryView:(UIView *)inputAccessoryView { + [self lks_setInputAccessoryView:inputAccessoryView]; + [[LKS_WindowDiscovery sharedInstance] addCustomWindowWithView:inputAccessoryView]; +} + @end #endif /* SHOULD_COMPILE_LOOKIN_SERVER */ From 095afa85489e3e177f133aee7f3d8f42afa4879f Mon Sep 17 00:00:00 2001 From: andysheng Date: Sat, 7 Jan 2023 00:00:05 +0800 Subject: [PATCH 5/5] add: ability to trace windows which not in UIApplication.windows --- Src/Main/Server/Others/LKS_WeakObjContainer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Src/Main/Server/Others/LKS_WeakObjContainer.h b/Src/Main/Server/Others/LKS_WeakObjContainer.h index a2ffa03..2c25fd4 100644 --- a/Src/Main/Server/Others/LKS_WeakObjContainer.h +++ b/Src/Main/Server/Others/LKS_WeakObjContainer.h @@ -9,7 +9,7 @@ NS_ASSUME_NONNULL_BEGIN -@interface LKS_WeakObjContainer : NSObject +@interface LKS_WeakObjContainer<__covariant ObjectType> : NSObject @property (nonatomic, weak) ObjectType weakObj;