LKS_AttrModificationHandler.m 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #ifdef SHOULD_COMPILE_LOOKIN_SERVER
  2. //
  3. // LKS_AttrModificationHandler.m
  4. // LookinServer
  5. //
  6. // Created by Li Kai on 2019/6/12.
  7. // https://lookin.work
  8. //
  9. #import "LKS_AttrModificationHandler.h"
  10. #import "UIColor+LookinServer.h"
  11. #import "LookinAttributeModification.h"
  12. #import "LKS_AttrGroupsMaker.h"
  13. #import "LookinDisplayItemDetail.h"
  14. #import "LookinStaticAsyncUpdateTask.h"
  15. #import "LookinServerDefines.h"
  16. @implementation LKS_AttrModificationHandler
  17. + (void)handleModification:(LookinAttributeModification *)modification completion:(void (^)(LookinDisplayItemDetail *data, NSError *error))completion {
  18. if (!completion) {
  19. NSAssert(NO, @"");
  20. return;
  21. }
  22. if (!modification || ![modification isKindOfClass:[LookinAttributeModification class]]) {
  23. completion(nil, LookinErr_Inner);
  24. return;
  25. }
  26. NSObject *receiver = [NSObject lks_objectWithOid:modification.targetOid];
  27. if (!receiver) {
  28. completion(nil, LookinErr_ObjNotFound);
  29. return;
  30. }
  31. NSMethodSignature *setterSignature = [receiver methodSignatureForSelector:modification.setterSelector];
  32. NSInvocation *setterInvocation = [NSInvocation invocationWithMethodSignature:setterSignature];
  33. setterInvocation.target = receiver;
  34. setterInvocation.selector = modification.setterSelector;
  35. if (setterSignature.numberOfArguments != 3 || ![receiver respondsToSelector:modification.setterSelector]) {
  36. completion(nil, LookinErr_Inner);
  37. return;
  38. }
  39. switch (modification.attrType) {
  40. case LookinAttrTypeNone:
  41. case LookinAttrTypeVoid: {
  42. completion(nil, LookinErr_Inner);
  43. return;
  44. }
  45. case LookinAttrTypeChar: {
  46. char expectedValue = [(NSNumber *)modification.value charValue];
  47. [setterInvocation setArgument:&expectedValue atIndex:2];
  48. break;
  49. }
  50. case LookinAttrTypeInt:
  51. case LookinAttrTypeEnumInt: {
  52. int expectedValue = [(NSNumber *)modification.value intValue];
  53. [setterInvocation setArgument:&expectedValue atIndex:2];
  54. break;
  55. }
  56. case LookinAttrTypeShort: {
  57. short expectedValue = [(NSNumber *)modification.value shortValue];
  58. [setterInvocation setArgument:&expectedValue atIndex:2];
  59. break;
  60. }
  61. case LookinAttrTypeLong:
  62. case LookinAttrTypeEnumLong: {
  63. long expectedValue = [(NSNumber *)modification.value longValue];
  64. [setterInvocation setArgument:&expectedValue atIndex:2];
  65. break;
  66. }
  67. case LookinAttrTypeLongLong: {
  68. long long expectedValue = [(NSNumber *)modification.value longLongValue];
  69. [setterInvocation setArgument:&expectedValue atIndex:2];
  70. break;
  71. }
  72. case LookinAttrTypeUnsignedChar: {
  73. unsigned char expectedValue = [(NSNumber *)modification.value unsignedCharValue];
  74. [setterInvocation setArgument:&expectedValue atIndex:2];
  75. break;
  76. }
  77. case LookinAttrTypeUnsignedInt: {
  78. unsigned int expectedValue = [(NSNumber *)modification.value unsignedIntValue];
  79. [setterInvocation setArgument:&expectedValue atIndex:2];
  80. break;
  81. }
  82. case LookinAttrTypeUnsignedShort: {
  83. unsigned short expectedValue = [(NSNumber *)modification.value unsignedShortValue];
  84. [setterInvocation setArgument:&expectedValue atIndex:2];
  85. break;
  86. }
  87. case LookinAttrTypeUnsignedLong: {
  88. unsigned long expectedValue = [(NSNumber *)modification.value unsignedLongValue];
  89. [setterInvocation setArgument:&expectedValue atIndex:2];
  90. break;
  91. }
  92. case LookinAttrTypeUnsignedLongLong: {
  93. unsigned long long expectedValue = [(NSNumber *)modification.value unsignedLongLongValue];
  94. [setterInvocation setArgument:&expectedValue atIndex:2];
  95. break;
  96. }
  97. case LookinAttrTypeFloat: {
  98. float expectedValue = [(NSNumber *)modification.value floatValue];
  99. [setterInvocation setArgument:&expectedValue atIndex:2];
  100. break;
  101. }
  102. case LookinAttrTypeDouble: {
  103. double expectedValue = [(NSNumber *)modification.value doubleValue];
  104. [setterInvocation setArgument:&expectedValue atIndex:2];
  105. break;
  106. }
  107. case LookinAttrTypeBOOL: {
  108. BOOL expectedValue = [(NSNumber *)modification.value boolValue];
  109. [setterInvocation setArgument:&expectedValue atIndex:2];
  110. break;
  111. }
  112. case LookinAttrTypeSel: {
  113. SEL expectedValue = NSSelectorFromString(modification.value);
  114. [setterInvocation setArgument:&expectedValue atIndex:2];
  115. break;
  116. }
  117. case LookinAttrTypeClass: {
  118. Class expectedValue = NSClassFromString(modification.value);
  119. [setterInvocation setArgument:&expectedValue atIndex:2];
  120. break;
  121. }
  122. case LookinAttrTypeCGPoint: {
  123. CGPoint expectedValue = [(NSValue *)modification.value CGPointValue];
  124. [setterInvocation setArgument:&expectedValue atIndex:2];
  125. break;
  126. }
  127. case LookinAttrTypeCGVector: {
  128. CGVector expectedValue = [(NSValue *)modification.value CGVectorValue];
  129. [setterInvocation setArgument:&expectedValue atIndex:2];
  130. break;
  131. }
  132. case LookinAttrTypeCGSize: {
  133. CGSize expectedValue = [(NSValue *)modification.value CGSizeValue];
  134. [setterInvocation setArgument:&expectedValue atIndex:2];
  135. break;
  136. }
  137. case LookinAttrTypeCGRect: {
  138. CGRect expectedValue = [(NSValue *)modification.value CGRectValue];
  139. [setterInvocation setArgument:&expectedValue atIndex:2];
  140. break;
  141. }
  142. case LookinAttrTypeCGAffineTransform: {
  143. CGAffineTransform expectedValue = [(NSValue *)modification.value CGAffineTransformValue];
  144. [setterInvocation setArgument:&expectedValue atIndex:2];
  145. break;
  146. }
  147. case LookinAttrTypeUIEdgeInsets: {
  148. UIEdgeInsets expectedValue = [(NSValue *)modification.value UIEdgeInsetsValue];
  149. [setterInvocation setArgument:&expectedValue atIndex:2];
  150. break;
  151. }
  152. case LookinAttrTypeUIOffset: {
  153. UIOffset expectedValue = [(NSValue *)modification.value UIOffsetValue];
  154. [setterInvocation setArgument:&expectedValue atIndex:2];
  155. break;
  156. }
  157. case LookinAttrTypeCustomObj:
  158. case LookinAttrTypeNSString: {
  159. NSObject *expectedValue = modification.value;
  160. [setterInvocation setArgument:&expectedValue atIndex:2];
  161. [setterInvocation retainArguments];
  162. break;
  163. }
  164. case LookinAttrTypeUIColor: {
  165. NSArray<NSNumber *> *rgba = modification.value;
  166. UIColor *expectedValue = [UIColor lks_colorFromRGBAComponents:rgba];
  167. [setterInvocation setArgument:&expectedValue atIndex:2];
  168. [setterInvocation retainArguments];
  169. break;
  170. }
  171. default: {
  172. completion(nil, LookinErr_Inner);
  173. return;
  174. }
  175. }
  176. NSError *error = nil;
  177. @try {
  178. [setterInvocation invoke];
  179. } @catch (NSException *exception) {
  180. NSString *errorMsg = [NSString stringWithFormat:LKS_Localized(@"<%@: %p>: an exception was raised when invoking %@. (%@)"), NSStringFromClass(receiver.class), receiver, NSStringFromSelector(modification.setterSelector), exception.reason];
  181. error = [NSError errorWithDomain:LookinErrorDomain code:LookinErrCode_Exception userInfo:@{NSLocalizedDescriptionKey:LKS_Localized(@"The modification may failed."), NSLocalizedRecoverySuggestionErrorKey:errorMsg}];
  182. } @finally {
  183. }
  184. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  185. CALayer *layer = nil;
  186. if ([receiver isKindOfClass:[CALayer class]]) {
  187. layer = (CALayer *)receiver;
  188. } else if ([receiver isKindOfClass:[UIView class]]) {
  189. layer = ((UIView *)receiver).layer;
  190. } else {
  191. completion(nil, LookinErr_ObjNotFound);
  192. return;
  193. }
  194. // 比如试图更改 frame 时,这个改动很有可能触发用户业务的 relayout,因此这时 dispatch 一下以确保拿到的 attrGroups 数据是最新的
  195. LookinDisplayItemDetail *detail = [LookinDisplayItemDetail new];
  196. detail.displayItemOid = modification.targetOid;
  197. detail.attributesGroupList = [LKS_AttrGroupsMaker attrGroupsForLayer:layer];
  198. detail.frameValue = [NSValue valueWithCGRect:layer.frame];
  199. detail.boundsValue = [NSValue valueWithCGRect:layer.bounds];
  200. detail.hiddenValue = [NSNumber numberWithBool:layer.isHidden];
  201. detail.alphaValue = @(layer.opacity);
  202. completion(detail, error);
  203. });
  204. }
  205. + (void)handlePatchWithTasks:(NSArray<LookinStaticAsyncUpdateTask *> *)tasks block:(void (^)(LookinDisplayItemDetail *data))block {
  206. if (!block) {
  207. NSAssert(NO, @"");
  208. return;
  209. }
  210. [tasks enumerateObjectsUsingBlock:^(LookinStaticAsyncUpdateTask * _Nonnull task, NSUInteger idx, BOOL * _Nonnull stop) {
  211. LookinDisplayItemDetail *itemDetail = [LookinDisplayItemDetail new];
  212. itemDetail.displayItemOid = task.oid;
  213. id object = [NSObject lks_objectWithOid:task.oid];
  214. if (!object || ![object isKindOfClass:[CALayer class]]) {
  215. block(itemDetail);
  216. return;
  217. }
  218. CALayer *layer = object;
  219. if (task.taskType == LookinStaticAsyncUpdateTaskTypeSoloScreenshot) {
  220. UIImage *image = [layer lks_soloScreenshotWithLowQuality:NO];
  221. itemDetail.soloScreenshot = image;
  222. } else if (task.taskType == LookinStaticAsyncUpdateTaskTypeGroupScreenshot) {
  223. UIImage *image = [layer lks_groupScreenshotWithLowQuality:NO];
  224. itemDetail.groupScreenshot = image;
  225. }
  226. block(itemDetail);
  227. }];
  228. }
  229. @end
  230. #endif /* SHOULD_COMPILE_LOOKIN_SERVER */