LKS_RequestHandler.m 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. #ifdef SHOULD_COMPILE_LOOKIN_SERVER
  2. //
  3. // LKS_RequestHandler.m
  4. // LookinServer
  5. //
  6. // Created by Li Kai on 2019/1/15.
  7. // https://lookin.work
  8. //
  9. #import "LKS_RequestHandler.h"
  10. #import "NSObject+LookinServer.h"
  11. #import "UIImage+LookinServer.h"
  12. #import "LKS_ConnectionManager.h"
  13. #import "LookinConnectionResponseAttachment.h"
  14. #import "LookinAttributeModification.h"
  15. #import "LookinDisplayItemDetail.h"
  16. #import "LookinHierarchyInfo.h"
  17. #import "LookinServerDefines.h"
  18. #import <objc/runtime.h>
  19. #import "LookinObject.h"
  20. #import "LookinAppInfo.h"
  21. #import "LKS_AttrGroupsMaker.h"
  22. #import "LKS_InbuiltAttrModificationHandler.h"
  23. #import "LKS_CustomAttrModificationHandler.h"
  24. #import "LKS_AttrModificationPatchHandler.h"
  25. #import "LKS_HierarchyDetailsHandler.h"
  26. #import "LookinStaticAsyncUpdateTask.h"
  27. @interface LKS_RequestHandler ()
  28. @property(nonatomic, strong) NSMutableSet<LKS_HierarchyDetailsHandler *> *activeDetailHandlers;
  29. @end
  30. @implementation LKS_RequestHandler {
  31. NSSet *_validRequestTypes;
  32. }
  33. - (instancetype)init {
  34. if (self = [super init]) {
  35. _validRequestTypes = [NSSet setWithObjects:@(LookinRequestTypePing),
  36. @(LookinRequestTypeApp),
  37. @(LookinRequestTypeHierarchy),
  38. @(LookinRequestTypeInbuiltAttrModification),
  39. @(LookinRequestTypeCustomAttrModification),
  40. @(LookinRequestTypeAttrModificationPatch),
  41. @(LookinRequestTypeHierarchyDetails),
  42. @(LookinRequestTypeFetchObject),
  43. @(LookinRequestTypeAllAttrGroups),
  44. @(LookinRequestTypeAllSelectorNames),
  45. @(LookinRequestTypeInvokeMethod),
  46. @(LookinRequestTypeFetchImageViewImage),
  47. @(LookinRequestTypeModifyRecognizerEnable),
  48. @(LookinPush_CanceHierarchyDetails),
  49. nil];
  50. self.activeDetailHandlers = [NSMutableSet set];
  51. }
  52. return self;
  53. }
  54. - (BOOL)canHandleRequestType:(uint32_t)requestType {
  55. if ([_validRequestTypes containsObject:@(requestType)]) {
  56. return YES;
  57. }
  58. return NO;
  59. }
  60. - (void)handleRequestType:(uint32_t)requestType tag:(uint32_t)tag object:(id)object {
  61. if (requestType == LookinRequestTypePing) {
  62. LookinConnectionResponseAttachment *responseAttachment = [LookinConnectionResponseAttachment new];
  63. // 当 app 处于后台时,可能可以执行代码也可能不能执行代码,如果运气好了可以执行代码,则这里直接主动使用 appIsInBackground 标识 app 处于后台,不要让 Lookin 客户端傻傻地等待超时了
  64. if (![LKS_ConnectionManager sharedInstance].applicationIsActive) {
  65. responseAttachment.appIsInBackground = YES;
  66. }
  67. [[LKS_ConnectionManager sharedInstance] respond:responseAttachment requestType:requestType tag:tag];
  68. } else if (requestType == LookinRequestTypeApp) {
  69. // 请求可用设备信息
  70. if (![object isKindOfClass:[NSDictionary class]]) {
  71. [self _submitResponseWithError:LookinErr_Inner requestType:requestType tag:tag];
  72. return;
  73. }
  74. NSDictionary<NSString *, id> *params = object;
  75. BOOL needImages = ((NSNumber *)params[@"needImages"]).boolValue;
  76. NSArray<NSNumber *> *localIdentifiers = params[@"local"];
  77. LookinAppInfo *appInfo = [LookinAppInfo currentInfoWithScreenshot:needImages icon:needImages localIdentifiers:localIdentifiers];
  78. LookinConnectionResponseAttachment *responseAttachment = [LookinConnectionResponseAttachment new];
  79. responseAttachment.data = appInfo;
  80. [[LKS_ConnectionManager sharedInstance] respond:responseAttachment requestType:requestType tag:tag];
  81. } else if (requestType == LookinRequestTypeHierarchy) {
  82. // 从 LookinClient 1.0.4 开始有这个参数,之前是 nil
  83. NSString *clientVersion = nil;
  84. if ([object isKindOfClass:[NSDictionary class]]) {
  85. NSDictionary<NSString *, id> *params = object;
  86. NSString *version = params[@"clientVersion"];
  87. if ([version isKindOfClass:[NSString class]]) {
  88. clientVersion = version;
  89. }
  90. }
  91. LookinConnectionResponseAttachment *responseAttachment = [LookinConnectionResponseAttachment new];
  92. responseAttachment.data = [LookinHierarchyInfo staticInfoWithLookinVersion:clientVersion];
  93. [[LKS_ConnectionManager sharedInstance] respond:responseAttachment requestType:requestType tag:tag];
  94. } else if (requestType == LookinRequestTypeInbuiltAttrModification) {
  95. // 请求修改某个属性
  96. [LKS_InbuiltAttrModificationHandler handleModification:object completion:^(LookinDisplayItemDetail *data, NSError *error) {
  97. LookinConnectionResponseAttachment *attachment = [LookinConnectionResponseAttachment new];
  98. if (error) {
  99. attachment.error = error;
  100. } else {
  101. attachment.data = data;
  102. }
  103. [[LKS_ConnectionManager sharedInstance] respond:attachment requestType:requestType tag:tag];
  104. }];
  105. } else if (requestType == LookinRequestTypeCustomAttrModification) {
  106. BOOL succ = [LKS_CustomAttrModificationHandler handleModification:object];
  107. if (succ) {
  108. [self _submitResponseWithData:nil requestType:requestType tag:tag];
  109. } else {
  110. [self _submitResponseWithError:LookinErr_Inner requestType:requestType tag:tag];
  111. }
  112. } else if (requestType == LookinRequestTypeAttrModificationPatch) {
  113. NSArray<LookinStaticAsyncUpdateTask *> *tasks = object;
  114. NSUInteger dataTotalCount = tasks.count;
  115. [LKS_InbuiltAttrModificationHandler handlePatchWithTasks:tasks block:^(LookinDisplayItemDetail *data) {
  116. LookinConnectionResponseAttachment *attrAttachment = [LookinConnectionResponseAttachment new];
  117. attrAttachment.data = data;
  118. attrAttachment.dataTotalCount = dataTotalCount;
  119. attrAttachment.currentDataCount = 1;
  120. [[LKS_ConnectionManager sharedInstance] respond:attrAttachment requestType:LookinRequestTypeAttrModificationPatch tag:tag];
  121. }];
  122. } else if (requestType == LookinRequestTypeHierarchyDetails) {
  123. NSArray<LookinStaticAsyncUpdateTasksPackage *> *packages = object;
  124. NSUInteger responsesDataTotalCount = [packages lookin_reduceInteger:^NSInteger(NSInteger accumulator, NSUInteger idx, LookinStaticAsyncUpdateTasksPackage *package) {
  125. accumulator += package.tasks.count;
  126. return accumulator;
  127. } initialAccumlator:0];
  128. LKS_HierarchyDetailsHandler *handler = [LKS_HierarchyDetailsHandler new];
  129. [self.activeDetailHandlers addObject:handler];
  130. [handler startWithPackages:packages block:^(NSArray<LookinDisplayItemDetail *> *details) {
  131. LookinConnectionResponseAttachment *attachment = [LookinConnectionResponseAttachment new];
  132. attachment.data = details;
  133. attachment.dataTotalCount = responsesDataTotalCount;
  134. attachment.currentDataCount = details.count;
  135. [[LKS_ConnectionManager sharedInstance] respond:attachment requestType:LookinRequestTypeHierarchyDetails tag:tag];
  136. } finishedBlock:^{
  137. [self.activeDetailHandlers removeObject:handler];
  138. }];
  139. } else if (requestType == LookinRequestTypeFetchObject) {
  140. unsigned long oid = ((NSNumber *)object).unsignedLongValue;
  141. NSObject *object = [NSObject lks_objectWithOid:oid];
  142. LookinObject *lookinObj = [LookinObject instanceWithObject:object];
  143. LookinConnectionResponseAttachment *attach = [LookinConnectionResponseAttachment new];
  144. attach.data = lookinObj;
  145. [[LKS_ConnectionManager sharedInstance] respond:attach requestType:requestType tag:tag];
  146. } else if (requestType == LookinRequestTypeAllAttrGroups) {
  147. unsigned long oid = ((NSNumber *)object).unsignedLongValue;
  148. CALayer *layer = (CALayer *)[NSObject lks_objectWithOid:oid];
  149. if (![layer isKindOfClass:[CALayer class]]) {
  150. [self _submitResponseWithError:LookinErr_ObjNotFound requestType:LookinRequestTypeAllAttrGroups tag:tag];
  151. return;
  152. }
  153. NSArray<LookinAttributesGroup *> *list = [LKS_AttrGroupsMaker attrGroupsForLayer:layer];
  154. [self _submitResponseWithData:list requestType:LookinRequestTypeAllAttrGroups tag:tag];
  155. } else if (requestType == LookinRequestTypeAllSelectorNames) {
  156. if (![object isKindOfClass:[NSDictionary class]]) {
  157. [self _submitResponseWithError:LookinErr_Inner requestType:requestType tag:tag];
  158. return;
  159. }
  160. NSDictionary *params = object;
  161. Class targetClass = NSClassFromString(params[@"className"]);
  162. BOOL hasArg = [(NSNumber *)params[@"hasArg"] boolValue];
  163. if (!targetClass) {
  164. NSString *errorMsg = [NSString stringWithFormat:LKS_Localized(@"Didn't find the class named \"%@\". Please input another class and try again."), object];
  165. [self _submitResponseWithError:LookinErrorMake(errorMsg, @"") requestType:requestType tag:tag];
  166. return;
  167. }
  168. NSArray<NSString *> *selNames = [self _methodNameListForClass:targetClass hasArg:hasArg];
  169. [self _submitResponseWithData:selNames requestType:requestType tag:tag];
  170. } else if (requestType == LookinRequestTypeInvokeMethod) {
  171. if (![object isKindOfClass:[NSDictionary class]]) {
  172. [self _submitResponseWithError:LookinErr_Inner requestType:requestType tag:tag];
  173. return;
  174. }
  175. NSDictionary *param = object;
  176. unsigned long oid = [param[@"oid"] unsignedLongValue];
  177. NSString *text = param[@"text"];
  178. if (!text.length) {
  179. [self _submitResponseWithError:LookinErr_Inner requestType:requestType tag:tag];
  180. return;
  181. }
  182. NSObject *targerObj = [NSObject lks_objectWithOid:oid];
  183. if (!targerObj) {
  184. [self _submitResponseWithError:LookinErr_ObjNotFound requestType:requestType tag:tag];
  185. return;
  186. }
  187. SEL targetSelector = NSSelectorFromString(text);
  188. if (targetSelector && [targerObj respondsToSelector:targetSelector]) {
  189. NSString *resultDescription;
  190. NSObject *resultObject;
  191. NSError *error;
  192. [self _handleInvokeWithObject:targerObj selector:targetSelector resultDescription:&resultDescription resultObject:&resultObject error:&error];
  193. if (error) {
  194. [self _submitResponseWithError:error requestType:requestType tag:tag];
  195. return;
  196. }
  197. NSMutableDictionary *responseData = [NSMutableDictionary dictionaryWithCapacity:2];
  198. if (resultDescription) {
  199. responseData[@"description"] = resultDescription;
  200. }
  201. if (resultObject) {
  202. responseData[@"object"] = resultObject;
  203. }
  204. [self _submitResponseWithData:responseData requestType:requestType tag:tag];
  205. } else {
  206. NSString *errMsg = [NSString stringWithFormat:LKS_Localized(@"%@ doesn't have an instance method called \"%@\"."), NSStringFromClass(targerObj.class), text];
  207. [self _submitResponseWithError:LookinErrorMake(errMsg, @"") requestType:requestType tag:tag];
  208. }
  209. } else if (requestType == LookinPush_CanceHierarchyDetails) {
  210. [self.activeDetailHandlers enumerateObjectsUsingBlock:^(LKS_HierarchyDetailsHandler * _Nonnull handler, BOOL * _Nonnull stop) {
  211. [handler cancel];
  212. }];
  213. [self.activeDetailHandlers removeAllObjects];
  214. } else if (requestType == LookinRequestTypeFetchImageViewImage) {
  215. if (![object isKindOfClass:[NSNumber class]]) {
  216. [self _submitResponseWithError:LookinErr_Inner requestType:requestType tag:tag];
  217. return;
  218. }
  219. unsigned long imageViewOid = [(NSNumber *)object unsignedLongValue];
  220. UIImageView *imageView = (UIImageView *)[NSObject lks_objectWithOid:imageViewOid];
  221. if (!imageView) {
  222. [self _submitResponseWithError:LookinErr_ObjNotFound requestType:requestType tag:tag];
  223. return;
  224. }
  225. if (![imageView isKindOfClass:[UIImageView class]]) {
  226. [self _submitResponseWithError:LookinErr_Inner requestType:requestType tag:tag];
  227. return;
  228. }
  229. UIImage *image = imageView.image;
  230. NSData *imageData = [image lookin_data];
  231. [self _submitResponseWithData:imageData requestType:requestType tag:tag];
  232. } else if (requestType == LookinRequestTypeModifyRecognizerEnable) {
  233. if (![object isKindOfClass:[NSDictionary class]]) {
  234. [self _submitResponseWithError:LookinErr_Inner requestType:requestType tag:tag];
  235. return;
  236. }
  237. NSDictionary<NSString *, NSNumber *> *params = object;
  238. unsigned long recognizerOid = ((NSNumber *)params[@"oid"]).unsignedLongValue;
  239. BOOL shouldBeEnabled = ((NSNumber *)params[@"enable"]).boolValue;
  240. UIGestureRecognizer *recognizer = (UIGestureRecognizer *)[NSObject lks_objectWithOid:recognizerOid];
  241. if (!recognizer) {
  242. [self _submitResponseWithError:LookinErr_ObjNotFound requestType:requestType tag:tag];
  243. return;
  244. }
  245. if (![recognizer isKindOfClass:[UIGestureRecognizer class]]) {
  246. [self _submitResponseWithError:LookinErr_Inner requestType:requestType tag:tag];
  247. return;
  248. }
  249. recognizer.enabled = shouldBeEnabled;
  250. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
  251. // dispatch 以确保拿到的 enabled 是比较新的
  252. [self _submitResponseWithData:@(recognizer.enabled) requestType:requestType tag:tag];
  253. });
  254. }
  255. }
  256. - (NSArray<NSString *> *)_methodNameListForClass:(Class)aClass hasArg:(BOOL)hasArg {
  257. NSSet<NSString *> *prefixesToVoid = [NSSet setWithObjects:@"_", @"CA_", @"cpl", @"mf_", @"vs_", @"pep_", @"isNS", @"avkit_", @"PG_", @"px_", @"pl_", @"nsli_", @"pu_", @"pxg_", nil];
  258. NSMutableArray<NSString *> *array = [NSMutableArray array];
  259. Class currentClass = aClass;
  260. while (currentClass) {
  261. NSString *className = NSStringFromClass(currentClass);
  262. BOOL isSystemClass = ([className hasPrefix:@"UI"] || [className hasPrefix:@"CA"] || [className hasPrefix:@"NS"]);
  263. unsigned int methodCount = 0;
  264. Method *methods = class_copyMethodList(currentClass, &methodCount);
  265. for (unsigned int i = 0; i < methodCount; i++) {
  266. NSString *selName = NSStringFromSelector(method_getName(methods[i]));
  267. if (!hasArg && [selName containsString:@":"]) {
  268. continue;
  269. }
  270. if (isSystemClass) {
  271. BOOL invalid = [prefixesToVoid lookin_any:^BOOL(NSString *prefix) {
  272. return [selName hasPrefix:prefix];
  273. }];
  274. if (invalid) {
  275. continue;
  276. }
  277. }
  278. if (selName.length && ![array containsObject:selName]) {
  279. [array addObject:selName];
  280. }
  281. }
  282. if (methods) free(methods);
  283. currentClass = [currentClass superclass];
  284. }
  285. return [array lookin_sortedArrayByStringLength];
  286. }
  287. - (void)_handleInvokeWithObject:(NSObject *)obj selector:(SEL)selector resultDescription:(NSString **)description resultObject:(LookinObject **)resultObject error:(NSError **)error {
  288. NSMethodSignature *signature = [obj methodSignatureForSelector:selector];
  289. if (signature.numberOfArguments > 2) {
  290. *error = LookinErrorMake(LKS_Localized(@"Lookin doesn't support invoking methods with arguments yet."), @"");
  291. return;
  292. }
  293. NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
  294. [invocation setTarget:obj];
  295. [invocation setSelector:selector];
  296. [invocation invoke];
  297. const char *returnType = [signature methodReturnType];
  298. if (strcmp(returnType, @encode(void)) == 0) {
  299. //void, do nothing
  300. *description = LookinStringFlag_VoidReturn;
  301. } else if (strcmp(returnType, @encode(char)) == 0) {
  302. char charValue;
  303. [invocation getReturnValue:&charValue];
  304. *description = [NSString stringWithFormat:@"%@", @(charValue)];
  305. } else if (strcmp(returnType, @encode(int)) == 0) {
  306. int intValue;
  307. [invocation getReturnValue:&intValue];
  308. if (intValue == INT_MAX) {
  309. *description = @"INT_MAX";
  310. } else if (intValue == INT_MIN) {
  311. *description = @"INT_MIN";
  312. } else {
  313. *description = [NSString stringWithFormat:@"%@", @(intValue)];
  314. }
  315. } else if (strcmp(returnType, @encode(short)) == 0) {
  316. short shortValue;
  317. [invocation getReturnValue:&shortValue];
  318. if (shortValue == SHRT_MAX) {
  319. *description = @"SHRT_MAX";
  320. } else if (shortValue == SHRT_MIN) {
  321. *description = @"SHRT_MIN";
  322. } else {
  323. *description = [NSString stringWithFormat:@"%@", @(shortValue)];
  324. }
  325. } else if (strcmp(returnType, @encode(long)) == 0) {
  326. long longValue;
  327. [invocation getReturnValue:&longValue];
  328. if (longValue == NSNotFound) {
  329. *description = @"NSNotFound";
  330. } else if (longValue == LONG_MAX) {
  331. *description = @"LONG_MAX";
  332. } else if (longValue == LONG_MIN) {
  333. *description = @"LONG_MAX";
  334. } else {
  335. *description = [NSString stringWithFormat:@"%@", @(longValue)];
  336. }
  337. } else if (strcmp(returnType, @encode(long long)) == 0) {
  338. long long longLongValue;
  339. [invocation getReturnValue:&longLongValue];
  340. if (longLongValue == LLONG_MAX) {
  341. *description = @"LLONG_MAX";
  342. } else if (longLongValue == LLONG_MIN) {
  343. *description = @"LLONG_MIN";
  344. } else {
  345. *description = [NSString stringWithFormat:@"%@", @(longLongValue)];
  346. }
  347. } else if (strcmp(returnType, @encode(unsigned char)) == 0) {
  348. unsigned char ucharValue;
  349. [invocation getReturnValue:&ucharValue];
  350. if (ucharValue == UCHAR_MAX) {
  351. *description = @"UCHAR_MAX";
  352. } else {
  353. *description = [NSString stringWithFormat:@"%@", @(ucharValue)];
  354. }
  355. } else if (strcmp(returnType, @encode(unsigned int)) == 0) {
  356. unsigned int uintValue;
  357. [invocation getReturnValue:&uintValue];
  358. if (uintValue == UINT_MAX) {
  359. *description = @"UINT_MAX";
  360. } else {
  361. *description = [NSString stringWithFormat:@"%@", @(uintValue)];
  362. }
  363. } else if (strcmp(returnType, @encode(unsigned short)) == 0) {
  364. unsigned short ushortValue;
  365. [invocation getReturnValue:&ushortValue];
  366. if (ushortValue == USHRT_MAX) {
  367. *description = @"USHRT_MAX";
  368. } else {
  369. *description = [NSString stringWithFormat:@"%@", @(ushortValue)];
  370. }
  371. } else if (strcmp(returnType, @encode(unsigned long)) == 0) {
  372. unsigned long ulongValue;
  373. [invocation getReturnValue:&ulongValue];
  374. if (ulongValue == ULONG_MAX) {
  375. *description = @"ULONG_MAX";
  376. } else {
  377. *description = [NSString stringWithFormat:@"%@", @(ulongValue)];
  378. }
  379. } else if (strcmp(returnType, @encode(unsigned long long)) == 0) {
  380. unsigned long long ulongLongValue;
  381. [invocation getReturnValue:&ulongLongValue];
  382. if (ulongLongValue == ULONG_LONG_MAX) {
  383. *description = @"ULONG_LONG_MAX";
  384. } else {
  385. *description = [NSString stringWithFormat:@"%@", @(ulongLongValue)];
  386. }
  387. } else if (strcmp(returnType, @encode(float)) == 0) {
  388. float floatValue;
  389. [invocation getReturnValue:&floatValue];
  390. if (floatValue == FLT_MAX) {
  391. *description = @"FLT_MAX";
  392. } else if (floatValue == FLT_MIN) {
  393. *description = @"FLT_MIN";
  394. } else {
  395. *description = [NSString stringWithFormat:@"%@", @(floatValue)];
  396. }
  397. } else if (strcmp(returnType, @encode(double)) == 0) {
  398. double doubleValue;
  399. [invocation getReturnValue:&doubleValue];
  400. if (doubleValue == DBL_MAX) {
  401. *description = @"DBL_MAX";
  402. } else if (doubleValue == DBL_MIN) {
  403. *description = @"DBL_MIN";
  404. } else {
  405. *description = [NSString stringWithFormat:@"%@", @(doubleValue)];
  406. }
  407. } else if (strcmp(returnType, @encode(BOOL)) == 0) {
  408. BOOL boolValue;
  409. [invocation getReturnValue:&boolValue];
  410. *description = boolValue ? @"YES" : @"NO";
  411. } else if (strcmp(returnType, @encode(SEL)) == 0) {
  412. SEL selValue;
  413. [invocation getReturnValue:&selValue];
  414. *description = [NSString stringWithFormat:@"SEL(%@)", NSStringFromSelector(selValue)];
  415. } else if (strcmp(returnType, @encode(Class)) == 0) {
  416. Class classValue;
  417. [invocation getReturnValue:&classValue];
  418. *description = [NSString stringWithFormat:@"<%@>", NSStringFromClass(classValue)];
  419. } else if (strcmp(returnType, @encode(CGPoint)) == 0) {
  420. CGPoint targetValue;
  421. [invocation getReturnValue:&targetValue];
  422. *description = NSStringFromCGPoint(targetValue);
  423. } else if (strcmp(returnType, @encode(CGVector)) == 0) {
  424. CGVector targetValue;
  425. [invocation getReturnValue:&targetValue];
  426. *description = NSStringFromCGVector(targetValue);
  427. } else if (strcmp(returnType, @encode(CGSize)) == 0) {
  428. CGSize targetValue;
  429. [invocation getReturnValue:&targetValue];
  430. *description = NSStringFromCGSize(targetValue);
  431. } else if (strcmp(returnType, @encode(CGRect)) == 0) {
  432. CGRect rectValue;
  433. [invocation getReturnValue:&rectValue];
  434. *description = NSStringFromCGRect(rectValue);
  435. } else if (strcmp(returnType, @encode(CGAffineTransform)) == 0) {
  436. CGAffineTransform rectValue;
  437. [invocation getReturnValue:&rectValue];
  438. *description = NSStringFromCGAffineTransform(rectValue);
  439. } else if (strcmp(returnType, @encode(UIEdgeInsets)) == 0) {
  440. UIEdgeInsets targetValue;
  441. [invocation getReturnValue:&targetValue];
  442. *description = NSStringFromUIEdgeInsets(targetValue);
  443. } else if (strcmp(returnType, @encode(UIOffset)) == 0) {
  444. UIOffset targetValue;
  445. [invocation getReturnValue:&targetValue];
  446. *description = NSStringFromUIOffset(targetValue);
  447. } else {
  448. if (@available(iOS 11.0, tvOS 11.0, *)) {
  449. if (strcmp(returnType, @encode(NSDirectionalEdgeInsets)) == 0) {
  450. NSDirectionalEdgeInsets targetValue;
  451. [invocation getReturnValue:&targetValue];
  452. *description = NSStringFromDirectionalEdgeInsets(targetValue);
  453. return;
  454. }
  455. }
  456. NSString *argType_string = [[NSString alloc] lookin_safeInitWithUTF8String:returnType];
  457. if ([argType_string hasPrefix:@"@"] || [argType_string hasPrefix:@"^{"]) {
  458. __unsafe_unretained id returnObjValue;
  459. [invocation getReturnValue:&returnObjValue];
  460. if (returnObjValue) {
  461. *description = [NSString stringWithFormat:@"%@", returnObjValue];
  462. LookinObject *parsedLookinObj = [LookinObject instanceWithObject:returnObjValue];
  463. *resultObject = parsedLookinObj;
  464. } else {
  465. *description = @"nil";
  466. }
  467. } else {
  468. *description = [NSString stringWithFormat:LKS_Localized(@"%@ was invoked successfully, but Lookin can't parse the return value:%@"), NSStringFromSelector(selector), argType_string];
  469. }
  470. }
  471. }
  472. - (void)_submitResponseWithError:(NSError *)error requestType:(uint32_t)requestType tag:(uint32_t)tag {
  473. LookinConnectionResponseAttachment *attachment = [LookinConnectionResponseAttachment new];
  474. attachment.error = error;
  475. [[LKS_ConnectionManager sharedInstance] respond:attachment requestType:requestType tag:tag];
  476. }
  477. - (void)_submitResponseWithData:(NSObject *)data requestType:(uint32_t)requestType tag:(uint32_t)tag {
  478. LookinConnectionResponseAttachment *attachment = [LookinConnectionResponseAttachment new];
  479. attachment.data = data;
  480. [[LKS_ConnectionManager sharedInstance] respond:attachment requestType:requestType tag:tag];
  481. }
  482. @end
  483. #endif /* SHOULD_COMPILE_LOOKIN_SERVER */