/* * Copyright [2019] [Doric.Pub] * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // // DoricShaderPlugin.m // Doric // // Created by pengfei.zhou on 2019/7/29. // #import "DoricShaderPlugin.h" #import "DoricRootNode.h" #import "DoricUtil.h" #import @implementation DoricShaderPlugin - (void)render:(NSDictionary *)argument withPromise:(DoricPromise *)promise { if (!argument) { return; } __weak typeof(self) _self = self; dispatch_async(dispatch_get_main_queue(), ^{ __strong typeof(_self) self = _self; NSString *viewId = argument[@"id"]; if (self.doricContext.rootNode.viewId == nil) { self.doricContext.rootNode.viewId = viewId; [self.doricContext.rootNode blend:argument[@"props"]]; [self.doricContext.rootNode requestLayout]; } else { DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId]; [viewNode blend:argument[@"props"]]; [viewNode requestLayout]; } [promise resolve:nil]; }); } - (void)command:(NSDictionary *)argument withPromise:(DoricPromise *)promise { dispatch_async(dispatch_get_main_queue(), ^{ NSArray *viewIds = argument[@"viewIds"]; id args = argument[@"args"]; NSString *name = argument[@"name"]; DoricViewNode *viewNode = nil; for (NSString *viewId in viewIds) { if (!viewNode) { viewNode = [self.doricContext targetViewNode:viewId]; } else { if ([viewNode isKindOfClass:[DoricSuperNode class]]) { viewNode = [((DoricSuperNode *) viewNode) subNodeWithViewId:viewId]; } } } if (!viewNode) { [promise reject:@"Cannot find opposite view"]; } else { [self findClass:[viewNode class] target:viewNode method:name promise:promise argument:args]; } }); } - (id)createParamWithMethodName:(NSString *)method promise:(DoricPromise *)promise argument:(id)argument { if ([method isEqualToString:@"withPromise"]) { return promise; } return argument; } - (void)findClass:(Class)clz target:(id)target method:(NSString *)name promise:(DoricPromise *)promise argument:(id)argument { unsigned int count; Method *methods = class_copyMethodList(clz, &count); BOOL isFound = NO; for (int i = 0; i < count; i++) { NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(methods[i])) encoding:NSUTF8StringEncoding]; NSArray *array = [methodName componentsSeparatedByString:@":"]; if (array && [array count] > 0) { if ([array[0] isEqualToString:name]) { isFound = YES; SEL selector = NSSelectorFromString(methodName); NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector]; if (methodSignature) { NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature]; [invocation retainArguments]; invocation.selector = selector; invocation.target = target; void *retValue; @try { NSMutableArray *tempArray = [NSMutableArray new]; for (NSUInteger idx = 2; idx < methodSignature.numberOfArguments; idx++) { if (idx - 2 > [array count]) { break; } id param = [self createParamWithMethodName:array[idx - 2] promise:promise argument:argument]; if (param) { [tempArray addObject:param]; } [invocation setArgument:¶m atIndex:idx]; } [invocation invoke]; } @catch (NSException *exception) { DoricLog(@"CallNative Error:%@", exception.reason); [self.doricContext.driver.registry onException:exception inContext:self.doricContext]; } const char *retType = methodSignature.methodReturnType; if (!strcmp(retType, @encode(void))) { } else { [invocation getReturnValue:&retValue]; id returnValue = (__bridge id) retValue; [promise resolve:returnValue]; } } break; } } } if (methods) { free(methods); } if (!isFound) { Class superclass = class_getSuperclass(clz); if (superclass && superclass != [NSObject class]) { [self findClass:superclass target:target method:name promise:promise argument:argument]; } } } @end