LookinHierarchyInfo.m 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. //
  2. // LookinDisplayInfo.m
  3. // WeRead
  4. //
  5. // Created by Li Kai on 2018/10/22.
  6. // Copyright © 2018年 tencent. All rights reserved.
  7. //
  8. #import <objc/runtime.h>
  9. #import "LookinHierarchyInfo.h"
  10. #import "LookinAttributesGroup.h"
  11. #import "LookinDisplayItem.h"
  12. #import "LookinAppInfo.h"
  13. #import "NSArray+Lookin.h"
  14. #if TARGET_OS_IPHONE
  15. #import "LKS_HierarchyDisplayItemsMaker.h"
  16. #endif
  17. @implementation LookinHierarchyInfo
  18. #if TARGET_OS_IPHONE
  19. + (Class)configClass {
  20. static dispatch_once_t onceToken;
  21. static Class configClass = NULL;
  22. dispatch_once(&onceToken,^{
  23. NSString *rawName = @"LookinConfig";
  24. configClass = NSClassFromString(rawName);
  25. if (!configClass) {
  26. int numberOfClasses = objc_getClassList(NULL, 0);
  27. if (numberOfClasses > 0) {
  28. Class *classes = (__unsafe_unretained Class *)malloc(sizeof(Class) * numberOfClasses);
  29. numberOfClasses = objc_getClassList(classes, numberOfClasses);
  30. for (int i = 0; i < numberOfClasses; i++) {
  31. Class class = classes[i];
  32. if ([NSStringFromClass(class) hasSuffix:@"LookinConfig"]) {
  33. configClass = class;
  34. break;
  35. }
  36. }
  37. free(classes);
  38. }
  39. }
  40. });
  41. return configClass;
  42. }
  43. + (instancetype)staticInfo {
  44. LookinHierarchyInfo *info = [LookinHierarchyInfo new];
  45. info.serverVersion = LOOKIN_SERVER_VERSION;
  46. info.displayItems = [LKS_HierarchyDisplayItemsMaker itemsWithScreenshots:NO attrList:NO lowImageQuality:NO includedWindows:nil excludedWindows:nil];
  47. info.appInfo = [LookinAppInfo currentInfoWithScreenshot:NO icon:YES localIdentifiers:nil];
  48. info.collapsedClassList = [self collapsedClassList];
  49. info.colorAlias = [self colorAlias];
  50. info.serverSetupType = LOOKIN_SERVER_SETUP_TYPE;
  51. return info;
  52. }
  53. + (instancetype)exportedInfo {
  54. LookinHierarchyInfo *info = [LookinHierarchyInfo new];
  55. info.serverVersion = LOOKIN_SERVER_VERSION;
  56. info.displayItems = [LKS_HierarchyDisplayItemsMaker itemsWithScreenshots:YES attrList:YES lowImageQuality:YES includedWindows:nil excludedWindows:nil];
  57. info.appInfo = [LookinAppInfo currentInfoWithScreenshot:NO icon:YES localIdentifiers:nil];
  58. info.collapsedClassList = [self collapsedClassList];
  59. info.colorAlias = [self colorAlias];
  60. info.serverSetupType = LOOKIN_SERVER_SETUP_TYPE;
  61. return info;
  62. }
  63. + (instancetype)perspectiveInfoWithIncludedWindows:(NSArray<UIWindow *> *)includedWindows excludedWindows:(NSArray<UIWindow *> *)excludedWindows {
  64. LookinHierarchyInfo *info = [LookinHierarchyInfo new];
  65. info.serverVersion = LOOKIN_SERVER_VERSION;
  66. info.displayItems = [LKS_HierarchyDisplayItemsMaker itemsWithScreenshots:YES attrList:YES lowImageQuality:NO includedWindows:includedWindows excludedWindows:excludedWindows];
  67. info.appInfo = [LookinAppInfo currentInfoWithScreenshot:NO icon:YES localIdentifiers:nil];
  68. info.collapsedClassList = [self collapsedClassList];
  69. info.colorAlias = [self colorAlias];
  70. info.serverSetupType = LOOKIN_SERVER_SETUP_TYPE;
  71. return info;
  72. }
  73. + (NSArray<NSString *> *)collapsedClassList {
  74. Class configClass = [self configClass];
  75. if (!configClass) {
  76. return nil;
  77. }
  78. SEL selector = NSSelectorFromString(@"collapsedClasses");
  79. if (![configClass respondsToSelector:selector]) {
  80. return nil;
  81. }
  82. NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[configClass methodSignatureForSelector:selector]];
  83. [invocation setTarget:configClass];
  84. [invocation setSelector:selector];
  85. [invocation invoke];
  86. void *arrayValue;
  87. [invocation getReturnValue:&arrayValue];
  88. id classList = (__bridge id)(arrayValue);
  89. if ([classList isKindOfClass:[NSArray class]]) {
  90. NSArray *validClassList = [((NSArray *)classList) lookin_filter:^BOOL(id obj) {
  91. return [obj isKindOfClass:[NSString class]];
  92. }];
  93. return [validClassList copy];
  94. }
  95. return nil;
  96. }
  97. + (NSDictionary<NSString *, UIColor *> *)colorAlias {
  98. Class configClass = [self configClass];
  99. if (!configClass) {
  100. return nil;
  101. }
  102. SEL selector = NSSelectorFromString(@"colors");
  103. if (![configClass respondsToSelector:selector]) {
  104. return nil;
  105. }
  106. NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[configClass methodSignatureForSelector:selector]];
  107. [invocation setTarget:configClass];
  108. [invocation setSelector:selector];
  109. [invocation invoke];
  110. void *dictValue;
  111. [invocation getReturnValue:&dictValue];
  112. id colorAlias = (__bridge id)(dictValue);
  113. if ([colorAlias isKindOfClass:[NSDictionary class]]) {
  114. NSMutableDictionary *validDictionary = [NSMutableDictionary dictionary];
  115. [(NSDictionary *)colorAlias enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) {
  116. if ([key isKindOfClass:[NSString class]]) {
  117. if ([obj isKindOfClass:[UIColor class]]) {
  118. [validDictionary setObject:obj forKey:key];
  119. } else if ([obj isKindOfClass:[NSDictionary class]]) {
  120. __block BOOL isValidSubDict = YES;
  121. [((NSDictionary *)obj) enumerateKeysAndObjectsUsingBlock:^(id _Nonnull subKey, id _Nonnull subObj, BOOL * _Nonnull stop) {
  122. if (![subKey isKindOfClass:[NSString class]] || ![subObj isKindOfClass:[UIColor class]]) {
  123. isValidSubDict = NO;
  124. *stop = YES;
  125. }
  126. }];
  127. if (isValidSubDict) {
  128. [validDictionary setObject:obj forKey:key];
  129. }
  130. }
  131. }
  132. }];
  133. return [validDictionary copy];
  134. }
  135. return nil;
  136. }
  137. #endif
  138. #pragma mark - <NSSecureCoding>
  139. static NSString * const LookinHierarchyInfoCodingKey_DisplayItems = @"1";
  140. static NSString * const LookinHierarchyInfoCodingKey_AppInfo = @"2";
  141. static NSString * const LookinHierarchyInfoCodingKey_ColorAlias = @"3";
  142. static NSString * const LookinHierarchyInfoCodingKey_CollapsedClassList = @"4";
  143. - (void)encodeWithCoder:(NSCoder *)aCoder {
  144. [aCoder encodeObject:self.displayItems forKey:LookinHierarchyInfoCodingKey_DisplayItems];
  145. [aCoder encodeObject:self.colorAlias forKey:LookinHierarchyInfoCodingKey_ColorAlias];
  146. [aCoder encodeObject:self.collapsedClassList forKey:LookinHierarchyInfoCodingKey_CollapsedClassList];
  147. [aCoder encodeObject:self.appInfo forKey:LookinHierarchyInfoCodingKey_AppInfo];
  148. [aCoder encodeInt:self.serverVersion forKey:@"serverVersion"];
  149. [aCoder encodeInt:self.serverSetupType forKey:@"serverSetupType"];
  150. }
  151. - (instancetype)initWithCoder:(NSCoder *)aDecoder {
  152. if (self = [super init]) {
  153. self.displayItems = [aDecoder decodeObjectForKey:LookinHierarchyInfoCodingKey_DisplayItems];
  154. self.colorAlias = [aDecoder decodeObjectForKey:LookinHierarchyInfoCodingKey_ColorAlias];
  155. self.collapsedClassList = [aDecoder decodeObjectForKey:LookinHierarchyInfoCodingKey_CollapsedClassList];
  156. self.appInfo = [aDecoder decodeObjectForKey:LookinHierarchyInfoCodingKey_AppInfo];
  157. self.serverVersion = [aDecoder decodeIntForKey:@"serverVersion"];
  158. self.serverSetupType = [aDecoder decodeIntForKey:@"serverSetupType"];
  159. }
  160. return self;
  161. }
  162. + (BOOL)supportsSecureCoding {
  163. return YES;
  164. }
  165. #pragma mark - <NSCopying>
  166. - (id)copyWithZone:(NSZone *)zone {
  167. LookinHierarchyInfo *newAppInfo = [[LookinHierarchyInfo allocWithZone:zone] init];
  168. newAppInfo.serverVersion = self.serverVersion;
  169. newAppInfo.appInfo = self.appInfo.copy;
  170. newAppInfo.collapsedClassList = self.collapsedClassList;
  171. newAppInfo.colorAlias = self.colorAlias;
  172. newAppInfo.serverSetupType = self.serverSetupType;
  173. newAppInfo.displayItems = [self.displayItems lookin_map:^id(NSUInteger idx, LookinDisplayItem *oldItem) {
  174. return oldItem.copy;
  175. }];
  176. return newAppInfo;
  177. }
  178. @end