/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. */ #import "RCTObjcExecutor.h" #import #import #import #import #import #import #import #import #import #import #import namespace facebook { namespace react { namespace { class JSEException : public std::runtime_error { public: JSEException(NSError *error) : runtime_error([[error description] UTF8String]) {} }; class RCTObjcExecutor : public JSExecutor { public: RCTObjcExecutor(id jse, RCTJavaScriptCompleteBlock errorBlock, std::shared_ptr jsThread, std::shared_ptr delegate) : m_jse(jse) , m_errorBlock(errorBlock) , m_jsThread(std::move(jsThread)) , m_delegate(std::move(delegate)) { m_jsCallback = ^(id json, NSError *error) { if (error) { // Do not use "m_errorBlock" here as the bridge might be in the middle // of invalidation as a result of error handling and "this" can be // already deallocated. errorBlock(error); return; } m_jsThread->runOnQueue([this, json]{ m_delegate->callNativeModules(*this, convertIdToFollyDynamic(json), true); }); }; // Synchronously initialize the executor [jse setUp]; folly::dynamic nativeModuleConfig = folly::dynamic::array; auto moduleRegistry = m_delegate->getModuleRegistry(); for (const auto &name : moduleRegistry->moduleNames()) { auto config = moduleRegistry->getConfig(name); nativeModuleConfig.push_back(config ? config->config : nullptr); } folly::dynamic config = folly::dynamic::object("remoteModuleConfig", std::move(nativeModuleConfig)); setGlobalVariable( "__fbBatchedBridgeConfig", std::make_unique(folly::toJson(config))); } void loadApplicationScript( std::unique_ptr script, std::string sourceURL) override { RCTProfileBeginFlowEvent(); [m_jse executeApplicationScript:[NSData dataWithBytes:script->c_str() length:script->size()] sourceURL:[[NSURL alloc] initWithString:@(sourceURL.c_str())] onComplete:^(NSError *error) { RCTProfileEndFlowEvent(); if (error) { m_errorBlock(error); return; } [m_jse flushedQueue:m_jsCallback]; }]; } void setBundleRegistry(std::unique_ptr) override { RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor"); } void registerBundle(uint32_t bundleId, const std::string &bundlePath) override { RCTAssert(NO, @"RAM bundles are not supported in RCTObjcExecutor"); } void callFunction(const std::string &module, const std::string &method, const folly::dynamic &arguments) override { [m_jse callFunctionOnModule:@(module.c_str()) method:@(method.c_str()) arguments:convertFollyDynamicToId(arguments) callback:m_jsCallback]; } void invokeCallback(double callbackId, const folly::dynamic &arguments) override { [m_jse invokeCallbackID:@(callbackId) arguments:convertFollyDynamicToId(arguments) callback:m_jsCallback]; } virtual void setGlobalVariable( std::string propName, std::unique_ptr jsonValue) override { [m_jse injectJSONText:@(jsonValue->c_str()) asGlobalObjectNamed:@(propName.c_str()) callback:m_errorBlock]; } virtual std::string getDescription() override { return [NSStringFromClass([m_jse class]) UTF8String]; } private: id m_jse; RCTJavaScriptCompleteBlock m_errorBlock; std::shared_ptr m_delegate; std::shared_ptr m_jsThread; RCTJavaScriptCallback m_jsCallback; }; } RCTObjcExecutorFactory::RCTObjcExecutorFactory( id jse, RCTJavaScriptCompleteBlock errorBlock) : m_jse(jse) , m_errorBlock(errorBlock) {} std::unique_ptr RCTObjcExecutorFactory::createJSExecutor( std::shared_ptr delegate, std::shared_ptr jsQueue) { return std::unique_ptr( new RCTObjcExecutor(m_jse, m_errorBlock, jsQueue, delegate)); } } }