#import "NativeProxy.h" #import "REAIOSScheduler.h" #import "REAIOSErrorHandler.h" #import "REAModule.h" #import "REANodesManager.h" #import "NativeMethods.h" #import #import #import #if __has_include() #import #else #import #endif namespace reanimated { using namespace facebook; using namespace react; // COPIED FROM RCTTurboModule.mm static id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value); static NSString *convertJSIStringToNSString(jsi::Runtime &runtime, const jsi::String &value) { return [NSString stringWithUTF8String:value.utf8(runtime).c_str()]; } static NSDictionary *convertJSIObjectToNSDictionary(jsi::Runtime &runtime, const jsi::Object &value) { jsi::Array propertyNames = value.getPropertyNames(runtime); size_t size = propertyNames.size(runtime); NSMutableDictionary *result = [NSMutableDictionary new]; for (size_t i = 0; i < size; i++) { jsi::String name = propertyNames.getValueAtIndex(runtime, i).getString(runtime); NSString *k = convertJSIStringToNSString(runtime, name); id v = convertJSIValueToObjCObject(runtime, value.getProperty(runtime, name)); if (v) { result[k] = v; } } return [result copy]; } static NSArray * convertJSIArrayToNSArray(jsi::Runtime &runtime, const jsi::Array &value) { size_t size = value.size(runtime); NSMutableArray *result = [NSMutableArray new]; for (size_t i = 0; i < size; i++) { // Insert kCFNull when it's `undefined` value to preserve the indices. [result addObject:convertJSIValueToObjCObject(runtime, value.getValueAtIndex(runtime, i)) ?: (id)kCFNull]; } return [result copy]; } static id convertJSIValueToObjCObject(jsi::Runtime &runtime, const jsi::Value &value) { if (value.isUndefined() || value.isNull()) { return nil; } if (value.isBool()) { return @(value.getBool()); } if (value.isNumber()) { return @(value.getNumber()); } if (value.isString()) { return convertJSIStringToNSString(runtime, value.getString(runtime)); } if (value.isObject()) { jsi::Object o = value.getObject(runtime); if (o.isArray(runtime)) { return convertJSIArrayToNSArray(runtime, o.getArray(runtime)); } return convertJSIObjectToNSDictionary(runtime, o); } throw std::runtime_error("Unsupported jsi::jsi::Value kind"); } std::shared_ptr createReanimatedModule(std::shared_ptr jsInvoker) { RCTBridge *bridge = _bridge_reanimated; REAModule *reanimatedModule = [bridge moduleForClass:[REAModule class]]; auto propUpdater = [reanimatedModule](jsi::Runtime &rt, int viewTag, const jsi::Value& viewName, const jsi::Object &props) -> void { NSString *nsViewName = [NSString stringWithCString:viewName.asString(rt).utf8(rt).c_str() encoding:[NSString defaultCStringEncoding]]; NSDictionary *propsDict = convertJSIObjectToNSDictionary(rt, props); [reanimatedModule.nodesManager updateProps:propsDict ofViewWithTag:[NSNumber numberWithInt:viewTag] withName:nsViewName]; }; RCTUIManager *uiManager = reanimatedModule.nodesManager.uiManager; auto measuringFunction = [uiManager](int viewTag) -> std::vector> { return measure(viewTag, uiManager); }; auto scrollToFunction = [uiManager](int viewTag, double x, double y, bool animated) { scrollTo(viewTag, uiManager, x, y, animated); }; auto propObtainer = [reanimatedModule](jsi::Runtime &rt, const int viewTag, const jsi::String &propName) -> jsi::Value { NSString* propNameConverted = [NSString stringWithFormat:@"%s",propName.utf8(rt).c_str()]; std::string resultStr = std::string([[reanimatedModule.nodesManager obtainProp:[NSNumber numberWithInt:viewTag] propName:propNameConverted] UTF8String]); jsi::Value val = jsi::String::createFromUtf8(rt, resultStr); return val; }; #if __has_include() std::unique_ptr animatedRuntime = facebook::hermes::makeHermesRuntime(); #else std::unique_ptr animatedRuntime = facebook::jsc::makeJSCRuntime(); #endif std::shared_ptr scheduler = std::make_shared(jsInvoker); std::shared_ptr errorHandler = std::make_shared(scheduler); std::shared_ptr module; auto requestRender = [reanimatedModule, &module](std::function onRender, jsi::Runtime &rt) { [reanimatedModule.nodesManager postOnAnimation:^(CADisplayLink *displayLink) { double frameTimestamp = displayLink.targetTimestamp * 1000; rt.global().setProperty(rt, "_frameTimestamp", frameTimestamp); onRender(frameTimestamp); rt.global().setProperty(rt, "_frameTimestamp", jsi::Value::undefined()); }]; }; auto getCurrentTime = []() { return CACurrentMediaTime() * 1000; }; PlatformDepMethodsHolder platformDepMethodsHolder = { requestRender, propUpdater, scrollToFunction, measuringFunction, getCurrentTime, }; module = std::make_shared(jsInvoker, scheduler, std::move(animatedRuntime), errorHandler, propObtainer, platformDepMethodsHolder ); scheduler->setRuntimeManager(module); [reanimatedModule.nodesManager registerEventHandler:^(NSString *eventName, id event) { std::string eventNameString([eventName UTF8String]); std::string eventAsString = folly::toJson(convertIdToFollyDynamic([event arguments][2])); eventAsString = "{ NativeMap:" + eventAsString + "}"; module->runtime->global().setProperty(*module->runtime, "_eventTimestamp", CACurrentMediaTime() * 1000); module->onEvent(eventNameString, eventAsString); module->runtime->global().setProperty(*module->runtime, "_eventTimestamp", jsi::Value::undefined()); }]; return module; } }