LKS_CustomAttrGroupsMaker.m 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. #ifdef SHOULD_COMPILE_LOOKIN_SERVER
  2. //
  3. // LKS_CustomAttrGroupsMaker.m
  4. // LookinServer
  5. //
  6. // Created by LikaiMacStudioWork on 2023/10/31.
  7. //
  8. #import "LKS_CustomAttrGroupsMaker.h"
  9. #import "LKS_AttrGroupsMaker.h"
  10. #import "LookinAttributesGroup.h"
  11. #import "LookinAttributesSection.h"
  12. #import "LookinAttribute.h"
  13. #import "LookinDashboardBlueprint.h"
  14. #import "LookinIvarTrace.h"
  15. #import "UIColor+LookinServer.h"
  16. #import "LookinServerDefines.h"
  17. #import "LKS_CustomAttrSetterManager.h"
  18. @interface LKS_CustomAttrGroupsMaker ()
  19. /// key 是 section title
  20. @property(nonatomic, strong) NSMutableDictionary<NSString *, NSMutableArray<LookinAttribute *> *> *sectionAndAttrs;
  21. @property(nonatomic, copy) NSString *resolvedCustomDisplayTitle;
  22. @property(nonatomic, copy) NSString *resolvedDanceUISource;
  23. @property(nonatomic, strong) NSMutableArray *resolvedGroups;
  24. @property(nonatomic, weak) CALayer *layer;
  25. @end
  26. @implementation LKS_CustomAttrGroupsMaker
  27. - (instancetype)initWithLayer:(CALayer *)layer {
  28. if (self = [super init]) {
  29. self.sectionAndAttrs = [NSMutableDictionary dictionary];
  30. self.layer = layer;
  31. }
  32. return self;
  33. }
  34. - (void)execute {
  35. if (!self.layer) {
  36. NSAssert(NO, @"");
  37. return;
  38. }
  39. NSMutableArray<NSString *> *selectors = [NSMutableArray array];
  40. [selectors addObject:@"lookin_customDebugInfos"];
  41. for (int i = 0; i < 5; i++) {
  42. [selectors addObject:[NSString stringWithFormat:@"lookin_customDebugInfos_%@", @(i)]];
  43. }
  44. for (NSString *name in selectors) {
  45. [self makeAttrsForViewOrLayer:self.layer selectorName:name];
  46. UIView *view = self.layer.lks_hostView;
  47. if (view) {
  48. [self makeAttrsForViewOrLayer:view selectorName:name];
  49. }
  50. }
  51. if ([self.sectionAndAttrs count] == 0) {
  52. return;
  53. }
  54. NSMutableArray<LookinAttributesGroup *> *groups = [NSMutableArray array];
  55. [self.sectionAndAttrs enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull groupTitle, NSMutableArray<LookinAttribute *> * _Nonnull attrs, BOOL * _Nonnull stop) {
  56. LookinAttributesGroup *group = [LookinAttributesGroup new];
  57. group.userCustomTitle = groupTitle;
  58. group.identifier = LookinAttrGroup_UserCustom;
  59. NSMutableArray<LookinAttributesSection *> *sections = [NSMutableArray array];
  60. [attrs enumerateObjectsUsingBlock:^(LookinAttribute * _Nonnull attr, NSUInteger idx, BOOL * _Nonnull stop) {
  61. LookinAttributesSection *sec = [LookinAttributesSection new];
  62. sec.identifier = LookinAttrSec_UserCustom;
  63. sec.attributes = @[attr];
  64. [sections addObject:sec];
  65. }];
  66. group.attrSections = sections;
  67. [groups addObject:group];
  68. }];
  69. [groups sortedArrayUsingComparator:^NSComparisonResult(LookinAttributesGroup *obj1, LookinAttributesGroup *obj2) {
  70. return [obj1.userCustomTitle compare:obj2.userCustomTitle];
  71. }];
  72. self.resolvedGroups = groups;
  73. }
  74. - (void)makeAttrsForViewOrLayer:(id)viewOrLayer selectorName:(NSString *)selectorName {
  75. if (!viewOrLayer || !selectorName.length) {
  76. return;
  77. }
  78. if (![viewOrLayer isKindOfClass:[UIView class]] && ![viewOrLayer isKindOfClass:[CALayer class]]) {
  79. return;
  80. }
  81. SEL selector = NSSelectorFromString(selectorName);
  82. if (![viewOrLayer respondsToSelector:selector]) {
  83. return;
  84. }
  85. NSMethodSignature *signature = [viewOrLayer methodSignatureForSelector:selector];
  86. if (signature.numberOfArguments > 2) {
  87. NSAssert(NO, @"LookinServer - There should be no explicit parameters.");
  88. return;
  89. }
  90. NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
  91. [invocation setTarget:viewOrLayer];
  92. [invocation setSelector:selector];
  93. [invocation invoke];
  94. // 小心这里的内存管理
  95. NSDictionary<NSString *, id> * __unsafe_unretained tempRawData;
  96. [invocation getReturnValue:&tempRawData];
  97. if (!tempRawData || ![tempRawData isKindOfClass:[NSDictionary class]]) {
  98. return;
  99. }
  100. NSDictionary<NSString *, id> *rawData = tempRawData;
  101. NSArray *rawProperties = rawData[@"properties"];
  102. NSString *customTitle = rawData[@"title"];
  103. if (customTitle && [customTitle isKindOfClass:[NSString class]] && customTitle.length > 0) {
  104. self.resolvedCustomDisplayTitle = customTitle;
  105. }
  106. NSString *danceSource = rawData[@"lookin_source"];
  107. if (danceSource && [danceSource isKindOfClass:[NSString class]] && danceSource.length > 0) {
  108. self.resolvedDanceUISource = danceSource;
  109. }
  110. [self makeAttrsFromRawProperties:rawProperties];
  111. }
  112. - (void)makeAttrsFromRawProperties:(NSArray *)rawProperties {
  113. if (!rawProperties || ![rawProperties isKindOfClass:[NSArray class]]) {
  114. return;
  115. }
  116. for (NSDictionary<NSString *, id> *dict in rawProperties) {
  117. NSString *groupTitle;
  118. LookinAttribute *attr = [LKS_CustomAttrGroupsMaker attrFromRawDict:dict saveCustomSetter:YES groupTitle:&groupTitle];
  119. if (!attr) {
  120. continue;
  121. }
  122. if (!self.sectionAndAttrs[groupTitle]) {
  123. self.sectionAndAttrs[groupTitle] = [NSMutableArray array];
  124. }
  125. [self.sectionAndAttrs[groupTitle] addObject:attr];
  126. }
  127. }
  128. + (LookinAttribute *)attrFromRawDict:(NSDictionary *)dict saveCustomSetter:(BOOL)saveCustomSetter groupTitle:(inout NSString **)inoutGroupTitle {
  129. LookinAttribute *attr = [LookinAttribute new];
  130. attr.identifier = LookinAttr_UserCustom;
  131. NSString *title = dict[@"title"];
  132. NSString *type = dict[@"valueType"];
  133. NSString *section = dict[@"section"];
  134. id value = dict[@"value"];
  135. if (!title || ![title isKindOfClass:[NSString class]]) {
  136. NSLog(@"LookinServer - Wrong title");
  137. return nil;
  138. }
  139. if (!type || ![type isKindOfClass:[NSString class]]) {
  140. NSLog(@"LookinServer - Wrong valueType");
  141. return nil;
  142. }
  143. if (!section || ![section isKindOfClass:[NSString class]] || section.length == 0) {
  144. *inoutGroupTitle = @"Custom";
  145. } else {
  146. *inoutGroupTitle = section;
  147. }
  148. attr.displayTitle = title;
  149. NSString *fixedType = type.lowercaseString;
  150. if ([fixedType isEqualToString:@"string"]) {
  151. if (value != nil && ![value isKindOfClass:[NSString class]]) {
  152. // nil 是合法的
  153. NSLog(@"LookinServer - Wrong value type.");
  154. return nil;
  155. }
  156. attr.attrType = LookinAttrTypeNSString;
  157. attr.value = value;
  158. if (saveCustomSetter && dict[@"retainedSetter"]) {
  159. NSString *uniqueID = [[NSUUID new] UUIDString];
  160. LKS_StringSetter setter = dict[@"retainedSetter"];
  161. [[LKS_CustomAttrSetterManager sharedInstance] saveStringSetter:setter uniqueID:uniqueID];
  162. attr.customSetterID = uniqueID;
  163. }
  164. return attr;
  165. }
  166. if ([fixedType isEqualToString:@"number"]) {
  167. if (value == nil) {
  168. NSLog(@"LookinServer - No value.");
  169. return nil;
  170. }
  171. if (![value isKindOfClass:[NSNumber class]]) {
  172. NSLog(@"LookinServer - Wrong value type.");
  173. return nil;
  174. }
  175. attr.attrType = LookinAttrTypeDouble;
  176. attr.value = value;
  177. if (saveCustomSetter && dict[@"retainedSetter"]) {
  178. NSString *uniqueID = [[NSUUID new] UUIDString];
  179. LKS_NumberSetter setter = dict[@"retainedSetter"];
  180. [[LKS_CustomAttrSetterManager sharedInstance] saveNumberSetter:setter uniqueID:uniqueID];
  181. attr.customSetterID = uniqueID;
  182. }
  183. return attr;
  184. }
  185. if ([fixedType isEqualToString:@"bool"]) {
  186. if (value == nil) {
  187. NSLog(@"LookinServer - No value.");
  188. return nil;
  189. }
  190. if (![value isKindOfClass:[NSNumber class]]) {
  191. NSLog(@"LookinServer - Wrong value type.");
  192. return nil;
  193. }
  194. attr.attrType = LookinAttrTypeBOOL;
  195. attr.value = value;
  196. if (saveCustomSetter && dict[@"retainedSetter"]) {
  197. NSString *uniqueID = [[NSUUID new] UUIDString];
  198. LKS_BoolSetter setter = dict[@"retainedSetter"];
  199. [[LKS_CustomAttrSetterManager sharedInstance] saveBoolSetter:setter uniqueID:uniqueID];
  200. attr.customSetterID = uniqueID;
  201. }
  202. return attr;
  203. }
  204. if ([fixedType isEqualToString:@"color"]) {
  205. if (value != nil && ![value isKindOfClass:[UIColor class]]) {
  206. // nil 是合法的
  207. NSLog(@"LookinServer - Wrong value type.");
  208. return nil;
  209. }
  210. attr.attrType = LookinAttrTypeUIColor;
  211. attr.value = [(UIColor *)value lks_rgbaComponents];
  212. if (saveCustomSetter && dict[@"retainedSetter"]) {
  213. NSString *uniqueID = [[NSUUID new] UUIDString];
  214. LKS_ColorSetter setter = dict[@"retainedSetter"];
  215. [[LKS_CustomAttrSetterManager sharedInstance] saveColorSetter:setter uniqueID:uniqueID];
  216. attr.customSetterID = uniqueID;
  217. }
  218. return attr;
  219. }
  220. if ([fixedType isEqualToString:@"rect"]) {
  221. if (value == nil) {
  222. NSLog(@"LookinServer - No value.");
  223. return nil;
  224. }
  225. if (![value isKindOfClass:[NSValue class]]) {
  226. NSLog(@"LookinServer - Wrong value type.");
  227. return nil;
  228. }
  229. attr.attrType = LookinAttrTypeCGRect;
  230. attr.value = value;
  231. if (saveCustomSetter && dict[@"retainedSetter"]) {
  232. NSString *uniqueID = [[NSUUID new] UUIDString];
  233. LKS_RectSetter setter = dict[@"retainedSetter"];
  234. [[LKS_CustomAttrSetterManager sharedInstance] saveRectSetter:setter uniqueID:uniqueID];
  235. attr.customSetterID = uniqueID;
  236. }
  237. return attr;
  238. }
  239. if ([fixedType isEqualToString:@"size"]) {
  240. if (value == nil) {
  241. NSLog(@"LookinServer - No value.");
  242. return nil;
  243. }
  244. if (![value isKindOfClass:[NSValue class]]) {
  245. NSLog(@"LookinServer - Wrong value type.");
  246. return nil;
  247. }
  248. attr.attrType = LookinAttrTypeCGSize;
  249. attr.value = value;
  250. if (saveCustomSetter && dict[@"retainedSetter"]) {
  251. NSString *uniqueID = [[NSUUID new] UUIDString];
  252. LKS_SizeSetter setter = dict[@"retainedSetter"];
  253. [[LKS_CustomAttrSetterManager sharedInstance] saveSizeSetter:setter uniqueID:uniqueID];
  254. attr.customSetterID = uniqueID;
  255. }
  256. return attr;
  257. }
  258. if ([fixedType isEqualToString:@"point"]) {
  259. if (value == nil) {
  260. NSLog(@"LookinServer - No value.");
  261. return nil;
  262. }
  263. if (![value isKindOfClass:[NSValue class]]) {
  264. NSLog(@"LookinServer - Wrong value type.");
  265. return nil;
  266. }
  267. attr.attrType = LookinAttrTypeCGPoint;
  268. attr.value = value;
  269. if (saveCustomSetter && dict[@"retainedSetter"]) {
  270. NSString *uniqueID = [[NSUUID new] UUIDString];
  271. LKS_PointSetter setter = dict[@"retainedSetter"];
  272. [[LKS_CustomAttrSetterManager sharedInstance] savePointSetter:setter uniqueID:uniqueID];
  273. attr.customSetterID = uniqueID;
  274. }
  275. return attr;
  276. }
  277. if ([fixedType isEqualToString:@"insets"]) {
  278. if (value == nil) {
  279. NSLog(@"LookinServer - No value.");
  280. return nil;
  281. }
  282. if (![value isKindOfClass:[NSValue class]]) {
  283. NSLog(@"LookinServer - Wrong value type.");
  284. return nil;
  285. }
  286. attr.attrType = LookinAttrTypeUIEdgeInsets;
  287. attr.value = value;
  288. if (saveCustomSetter && dict[@"retainedSetter"]) {
  289. NSString *uniqueID = [[NSUUID new] UUIDString];
  290. LKS_InsetsSetter setter = dict[@"retainedSetter"];
  291. [[LKS_CustomAttrSetterManager sharedInstance] saveInsetsSetter:setter uniqueID:uniqueID];
  292. attr.customSetterID = uniqueID;
  293. }
  294. return attr;
  295. }
  296. if ([fixedType isEqualToString:@"shadow"]) {
  297. if (value == nil) {
  298. NSLog(@"LookinServer - No value.");
  299. return nil;
  300. }
  301. if (![value isKindOfClass:[NSDictionary class]]) {
  302. NSLog(@"LookinServer - Wrong value type.");
  303. return nil;
  304. }
  305. NSDictionary *shadowInfo = value;
  306. if (![shadowInfo[@"offset"] isKindOfClass:[NSValue class]]) {
  307. NSLog(@"LookinServer - Wrong value. No offset.");
  308. return nil;
  309. }
  310. if (![shadowInfo[@"opacity"] isKindOfClass:[NSNumber class]]) {
  311. NSLog(@"LookinServer - Wrong value. No opacity.");
  312. return nil;
  313. }
  314. if (![shadowInfo[@"radius"] isKindOfClass:[NSNumber class]]) {
  315. NSLog(@"LookinServer - Wrong value. No radius.");
  316. return nil;
  317. }
  318. NSMutableDictionary *checkedShadowInfo = [@{
  319. @"offset": shadowInfo[@"offset"],
  320. @"opacity": shadowInfo[@"opacity"],
  321. @"radius": shadowInfo[@"radius"]
  322. } mutableCopy];
  323. if ([shadowInfo[@"color"] isKindOfClass:[UIColor class]]) {
  324. checkedShadowInfo[@"color"] = [(UIColor *)shadowInfo[@"color"] lks_rgbaComponents];
  325. }
  326. attr.attrType = LookinAttrTypeShadow;
  327. attr.value = checkedShadowInfo;
  328. return attr;
  329. }
  330. if ([fixedType isEqualToString:@"enum"]) {
  331. if (value == nil) {
  332. NSLog(@"LookinServer - No value.");
  333. return nil;
  334. }
  335. if (![value isKindOfClass:[NSString class]]) {
  336. NSLog(@"LookinServer - Wrong value type.");
  337. return nil;
  338. }
  339. attr.attrType = LookinAttrTypeEnumString;
  340. attr.value = value;
  341. NSArray<NSString *> *allEnumCases = dict[@"allEnumCases"];
  342. if ([allEnumCases isKindOfClass:[NSArray class]]) {
  343. attr.extraValue = allEnumCases;
  344. }
  345. if (saveCustomSetter && dict[@"retainedSetter"]) {
  346. NSString *uniqueID = [[NSUUID new] UUIDString];
  347. LKS_EnumSetter setter = dict[@"retainedSetter"];
  348. [[LKS_CustomAttrSetterManager sharedInstance] saveEnumSetter:setter uniqueID:uniqueID];
  349. attr.customSetterID = uniqueID;
  350. }
  351. return attr;
  352. }
  353. if ([fixedType isEqualToString:@"json"]) {
  354. if (![value isKindOfClass:[NSString class]]) {
  355. NSLog(@"LookinServer - Wrong value type.");
  356. return nil;
  357. }
  358. attr.attrType = LookinAttrTypeJson;
  359. attr.value = value;
  360. return attr;
  361. }
  362. NSLog(@"LookinServer - Unsupported value type.");
  363. return nil;
  364. }
  365. - (NSArray<LookinAttributesGroup *> *)getGroups {
  366. return self.resolvedGroups;
  367. }
  368. - (NSString *)getCustomDisplayTitle {
  369. return self.resolvedCustomDisplayTitle;
  370. }
  371. - (NSString *)getDanceUISource {
  372. return self.resolvedDanceUISource;
  373. }
  374. + (NSArray<LookinAttributesGroup *> *)makeGroupsFromRawProperties:(NSArray *)rawProperties saveCustomSetter:(BOOL)saveCustomSetter {
  375. if (!rawProperties || ![rawProperties isKindOfClass:[NSArray class]]) {
  376. return nil;
  377. }
  378. // key 是 group title
  379. NSMutableDictionary<NSString *, NSMutableArray<LookinAttribute *> *> *groupTitleAndAttrs = [NSMutableDictionary dictionary];
  380. for (NSDictionary<NSString *, id> *dict in rawProperties) {
  381. NSString *groupTitle;
  382. LookinAttribute *attr = [LKS_CustomAttrGroupsMaker attrFromRawDict:dict saveCustomSetter:saveCustomSetter groupTitle:&groupTitle];
  383. if (!attr) {
  384. continue;
  385. }
  386. if (!groupTitleAndAttrs[groupTitle]) {
  387. groupTitleAndAttrs[groupTitle] = [NSMutableArray array];
  388. }
  389. [groupTitleAndAttrs[groupTitle] addObject:attr];
  390. }
  391. if ([groupTitleAndAttrs count] == 0) {
  392. return nil;
  393. }
  394. NSMutableArray<LookinAttributesGroup *> *groups = [NSMutableArray array];
  395. [groupTitleAndAttrs enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull groupTitle, NSMutableArray<LookinAttribute *> * _Nonnull attrs, BOOL * _Nonnull stop) {
  396. LookinAttributesGroup *group = [LookinAttributesGroup new];
  397. group.userCustomTitle = groupTitle;
  398. group.identifier = LookinAttrGroup_UserCustom;
  399. NSMutableArray<LookinAttributesSection *> *sections = [NSMutableArray array];
  400. [attrs enumerateObjectsUsingBlock:^(LookinAttribute * _Nonnull attr, NSUInteger idx, BOOL * _Nonnull stop) {
  401. LookinAttributesSection *sec = [LookinAttributesSection new];
  402. sec.identifier = LookinAttrSec_UserCustom;
  403. sec.attributes = @[attr];
  404. [sections addObject:sec];
  405. }];
  406. group.attrSections = sections;
  407. [groups addObject:group];
  408. }];
  409. [groups sortedArrayUsingComparator:^NSComparisonResult(LookinAttributesGroup *obj1, LookinAttributesGroup *obj2) {
  410. return [obj1.userCustomTitle compare:obj2.userCustomTitle];
  411. }];
  412. return [groups copy];
  413. }
  414. @end
  415. #endif /* SHOULD_COMPILE_LOOKIN_SERVER */