1// Copyright 2018-present 650 Industries. All rights reserved.
2
3#import <ExpoModulesCore/EXJSIInstaller.h>
4#import <ExpoModulesCore/EXJavaScriptRuntime.h>
5#import <ExpoModulesCore/ExpoModulesHostObject.h>
6#import <ExpoModulesCore/LazyObject.h>
7#import <ExpoModulesCore/Swift.h>
8
9namespace jsi = facebook::jsi;
10
11/**
12 Property name used to define the modules host object in the main object of the Expo JS runtime.
13 */
14static NSString *modulesHostObjectPropertyName = @"modules";
15
16/**
17 Property name used to define the modules host object in the global object of the Expo JS runtime (legacy).
18 */
19static NSString *modulesHostObjectLegacyPropertyName = @"ExpoModules";
20
21@interface RCTBridge (ExpoBridgeWithRuntime)
22
23- (void *)runtime;
24- (std::shared_ptr<facebook::react::CallInvoker>)jsCallInvoker;
25
26@end
27
28@implementation EXJavaScriptRuntimeManager
29
30+ (nullable EXRuntime *)runtimeFromBridge:(nonnull RCTBridge *)bridge
31{
32  jsi::Runtime *jsiRuntime = [bridge respondsToSelector:@selector(runtime)] ? reinterpret_cast<jsi::Runtime *>(bridge.runtime) : nullptr;
33  return jsiRuntime ? [[EXRuntime alloc] initWithRuntime:jsiRuntime callInvoker:bridge.jsCallInvoker] : nil;
34}
35
36+ (BOOL)installExpoModulesHostObject:(nonnull EXAppContext *)appContext
37{
38  EXRuntime *runtime = [appContext _runtime];
39
40  // The runtime may be unavailable, e.g. remote debugger is enabled or it hasn't been set yet.
41  if (!runtime) {
42    return false;
43  }
44
45  EXJavaScriptObject *global = [runtime global];
46  EXJavaScriptObject *coreObject = [runtime coreObject];
47
48  if ([coreObject hasProperty:modulesHostObjectPropertyName]) {
49    return false;
50  }
51
52  std::shared_ptr<expo::ExpoModulesHostObject> modulesHostObjectPtr = std::make_shared<expo::ExpoModulesHostObject>(appContext);
53  EXJavaScriptObject *modulesHostObject = [runtime createHostObject:modulesHostObjectPtr];
54
55  // Define the `global.expo.modules` object as a non-configurable, read-only and enumerable property.
56  [coreObject defineProperty:modulesHostObjectPropertyName
57                       value:modulesHostObject
58                     options:EXJavaScriptObjectPropertyDescriptorEnumerable];
59
60  // Also define `global.ExpoModules` for backwards compatibility (used before SDK47, can be removed in SDK48).
61  [global defineProperty:modulesHostObjectLegacyPropertyName
62                   value:modulesHostObject
63                 options:EXJavaScriptObjectPropertyDescriptorEnumerable];
64  return true;
65}
66
67@end
68