Skip to content

Commit

Permalink
Initial changes to build for iOS
Browse files Browse the repository at this point in the history
  • Loading branch information
kraenhansen committed Jun 10, 2021
1 parent bb09ab9 commit 53061e8
Show file tree
Hide file tree
Showing 8 changed files with 42 additions and 158 deletions.
3 changes: 3 additions & 0 deletions RealmJS.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ Pod::Spec.new do |s|
# Header search paths are prefixes to the path specified in #include macros
'HEADER_SEARCH_PATHS' => [
'"$(PODS_TARGET_SRCROOT)/react-native/ios/RealmReact/"',
'"$(PODS_TARGET_SRCROOT)/src/"',
'"$(PODS_TARGET_SRCROOT)/src/hermes/"',
'"$(PODS_ROOT)/Headers/Public/React-Core/"'
#"'#{app_path}/ios/Pods/Headers/Public/React-Core'" # Use this line instead of 👆 while linting
].join(' ')
Expand All @@ -66,6 +68,7 @@ Pod::Spec.new do |s|
s.ios.vendored_frameworks = 'react-native/ios/realm-js-ios.xcframework'

s.dependency 'React'
# s.dependency 'React-jsi'
# TODO: Ensure the same version of GCDWebServer is used for Android
s.dependency 'GCDWebServer'
end
171 changes: 21 additions & 150 deletions react-native/ios/RealmReact/RealmReact.mm
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
#import "RealmReact.h"
#import "RealmAnalytics.h"

#import <realm-js-ios/jsc_init.h>

#import <React/RCTBridge+Private.h>
#import <React/RCTJavaScriptExecutor.h>

Expand All @@ -30,17 +28,12 @@
#import <netdb.h>
#import <net/if.h>

#if DEBUG
#include <realm-js-ios/rpc.hpp>
#import "GCDWebServer.h"
#import "GCDWebServerDataRequest.h"
#import "GCDWebServerDataResponse.h"
#import "GCDWebServerErrorResponse.h"

#define WEB_SERVER_PORT 8083
#include <iostream>
#import "jsi/jsi.h"
//#import "hermes_init.hpp"

using namespace realm::rpc;
#endif
namespace jsi = facebook::jsi;
extern "C" void realm_hermes_init(jsi::Runtime& rt, jsi::Object& exports);

@interface NSObject ()
- (instancetype)initWithJSContext:(JSContext *)context;
Expand Down Expand Up @@ -84,11 +77,6 @@ @interface RealmReact () <RCTBridgeModule>

@implementation RealmReact {
NSMutableDictionary *_eventHandlers;

#if DEBUG
GCDWebServer *_webServer;
std::unique_ptr<RPCServer> _rpcServer;
#endif
}

@synthesize bridge = _bridge;
Expand Down Expand Up @@ -120,20 +108,7 @@ - (dispatch_queue_t)methodQueue {
}

- (NSDictionary *)constantsToExport {
#if DEBUG
#if TARGET_IPHONE_SIMULATOR
NSArray *hosts = @[@"localhost"];
#else
NSArray *hosts = [self getIPAddresses];
#endif

return @{
@"debugHosts": hosts,
@"debugPort": @(WEB_SERVER_PORT),
};
#else
return @{};
#endif
}

- (void)addListenerForEvent:(NSString *)eventName handler:(RealmReactEventHandler)handler {
Expand All @@ -155,120 +130,8 @@ - (void)removeListenerForEvent:(NSString *)eventName handler:(RealmReactEventHan
}
}

#if DEBUG
- (NSArray *)getIPAddresses {
static const char * const wifiInterface = "en0";

struct ifaddrs *ifaddrs;
if (getifaddrs(&ifaddrs)) {
NSLog(@"Failed to get interface addresses: %s", strerror(errno));
return @[];
}

NSMutableArray *ipAddresses = [[NSMutableArray alloc] init];
char host[INET6_ADDRSTRLEN];

for (struct ifaddrs *ifaddr = ifaddrs; ifaddr; ifaddr = ifaddr->ifa_next) {
if ((ifaddr->ifa_flags & IFF_LOOPBACK) || !(ifaddr->ifa_flags & IFF_UP)) {
// Ignore loopbacks and interfaces that aren't up.
continue;
}

struct sockaddr *addr = ifaddr->ifa_addr;
if (addr->sa_family == AF_INET) {
// Ignore link-local ipv4 addresses.
in_addr_t sin_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
if (IN_LOOPBACK(sin_addr) || IN_LINKLOCAL(sin_addr) || IN_ZERONET(sin_addr)) {
continue;
}
}
else if (addr->sa_family == AF_INET6) {
// Ignore link-local ipv6 addresses.
struct in6_addr *sin6_addr = &((struct sockaddr_in6 *)addr)->sin6_addr;
if (IN6_IS_ADDR_LOOPBACK(sin6_addr) || IN6_IS_ADDR_LINKLOCAL(sin6_addr) || IN6_IS_ADDR_UNSPECIFIED(sin6_addr)) {
continue;
}
}
else {
// Ignore addresses that are not ipv4 or ipv6.
continue;
}

if (strcmp(ifaddr->ifa_name, wifiInterface)) {
// Ignore non-wifi addresses.
continue;
}
if (int error = getnameinfo(addr, addr->sa_len, host, sizeof(host), NULL, 0, NI_NUMERICHOST)) {
NSLog(@"Couldn't resolve host name for address: %s", gai_strerror(error));
continue;
}

[ipAddresses addObject:@(host)];
}

freeifaddrs(ifaddrs);
return [ipAddresses copy];
}

- (void)startRPC {
[GCDWebServer setLogLevel:3];
_webServer = [[GCDWebServer alloc] init];
_rpcServer = std::make_unique<RPCServer>();
__weak __typeof__(self) weakSelf = self;

// Add a handler to respond to POST requests on any URL
[_webServer addDefaultHandlerForMethod:@"POST"
requestClass:[GCDWebServerDataRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
__typeof__(self) self = weakSelf;
RPCServer *rpcServer = self ? self->_rpcServer.get() : nullptr;
GCDWebServerResponse *response;

try {
NSData *responseData;

if (rpcServer) {
std::string args = [[(GCDWebServerDataRequest *)request text] UTF8String];
std::string responseText = rpcServer->perform_request(request.path.UTF8String, args);

responseData = [NSData dataWithBytes:responseText.c_str() length:responseText.length()];
}
else {
// we have been deallocated
responseData = [NSData data];
}

response = [[GCDWebServerDataResponse alloc] initWithData:responseData contentType:@"application/json"];
}
catch(std::exception &ex) {
NSLog(@"Invalid RPC request - %@", [(GCDWebServerDataRequest *)request text]);
response = [GCDWebServerErrorResponse responseWithClientError:kGCDWebServerHTTPStatusCode_UnprocessableEntity
underlyingError:nil
message:@"Invalid RPC request"];
}

[response setValue:@"http://localhost:8081" forAdditionalHeader:@"Access-Control-Allow-Origin"];
return response;
}];

[_webServer startWithPort:WEB_SERVER_PORT bonjourName:nil];
return;
}

- (void)shutdownRPC {
[_webServer stop];
[_webServer removeAllHandlers];
_webServer = nil;
_rpcServer.reset();
}
#endif

- (void)invalidate {
RJSInvalidateCaches();
#if DEBUG
// shutdown rpc if in chrome debug mode
[self shutdownRPC];
#endif
// RJSInvalidateCaches();
}

- (void)dealloc {
Expand All @@ -284,8 +147,10 @@ void _initializeOnJSThread(JSContextRefExtractor jsContextExtractor) {
[NSThread sleepForTimeInterval:0.1];
}
s_currentJSThread = [NSThread currentThread];

jsContextExtractor();

RJSInitializeInContext(jsContextExtractor());
// RJSInitializeInContext(jsContextExtractor());
}

- (void)setBridge:(RCTBridge *)bridge {
Expand All @@ -296,17 +161,22 @@ - (void)setBridge:(RCTBridge *)bridge {
s_currentModule = self;

if (objc_lookUpClass("RCTWebSocketExecutor") && [bridge executorClass] == objc_lookUpClass("RCTWebSocketExecutor")) {
#if DEBUG
[self startRPC];
#else
@throw [NSException exceptionWithName:@"Invalid Executor" reason:@"Chrome debug mode not supported in Release builds" userInfo:nil];
#endif
@throw [NSException exceptionWithName:@"Invalid Executor" reason:@"Chrome debug mode not supported" userInfo:nil];
} else if ([bridge isKindOfClass:objc_lookUpClass("RCTCxxBridge")] || [NSStringFromClass([bridge class]) isEqual: @"RCTCxxBridge"]) {
// probe for the new C++ bridge in React Native 0.45+

// auto& rt = *static_cast<facebook::jsi::Runtime*>(bridge.runtime);
// auto exports = jsi::Object(rt);
// realm_hermes_init(rt, exports);

__weak __typeof__(self) weakSelf = self;
__weak __typeof__(bridge) weakBridge = bridge;


// probe for the new C++ bridge in React Native 0.45+
auto& rt = *static_cast<facebook::jsi::Runtime*>(bridge.runtime);
auto exports = jsi::Object(rt);
realm_hermes_init(rt, exports);

[bridge dispatchBlock:^{
__typeof__(self) self = weakSelf;
__typeof__(bridge) bridge = weakBridge;
Expand All @@ -315,6 +185,7 @@ - (void)setBridge:(RCTBridge *)bridge {
}

_initializeOnJSThread(^{

// RN < 0.58 has a private method that returns the js context
if ([bridge respondsToSelector:@selector(jsContextRef)]) {
return [bridge jsContextRef];
Expand Down
3 changes: 2 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ elseif(ANDROID)
add_subdirectory(jsc)
add_subdirectory(android)
elseif(CMAKE_SYSTEM_NAME STREQUAL iOS)
add_subdirectory(jsc)
# add_subdirectory(jsc)
add_subdirectory(hermes)
add_subdirectory(ios)
endif()
7 changes: 7 additions & 0 deletions src/hermes/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
add_library(realm-js-hermes OBJECT
hermes_init.cpp
)

target_include_directories(realm-js-hermes PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

target_link_libraries(realm-js-hermes PUBLIC realm-js-shared)
4 changes: 2 additions & 2 deletions src/hermes/hermes_class.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ class ObjectWrap {
"nativeFunc",
util::format(R"(
return function %1(...args) {
"use strict";
//"use strict";
if (!nativeFunc)
throw TypeError("%1() cannot be constructed directly from javascript");
if (!new.target)
Expand Down Expand Up @@ -295,7 +295,7 @@ class ObjectWrap {
if (typeof(property) != 'string' || !isNumber.test(property))
return Reflect.get(target, property, receiver);
return getter(target, Number(property))
}
},
set(target, property, receiver, val) {
if (typeof(property) != 'string' || !isNumber.test(property))
return Reflect.set(target, property, receiver, val);
Expand Down
5 changes: 3 additions & 2 deletions src/hermes/hermes_init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@
#include "js_realm.hpp"

namespace realm::js::hermes {
void hermes_init(JsiEnv env, JsiObj& exports) {
extern "C" void realm_hermes_init(jsi::Runtime& rt, jsi::Object& exports) {
auto env = JsiEnv(rt);
jsi::Function realm_constructor = js::RealmClass<Types>::create_constructor(env);
auto name = realm_constructor.getProperty(env, "name").asString(env);
exports->setProperty(env, std::move(name), std::move(realm_constructor));
exports.setProperty(env, std::move(name), std::move(realm_constructor));

// Only calling to populate static cache. Eventually this should be stored somewhere non-static.
(void)js::ObjectWrap<Types, js::RealmObjectClass<Types>>::create_constructor(env);
Expand Down
2 changes: 1 addition & 1 deletion src/hermes/jsi/jsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class JSI_EXPORT Runtime {
/// different behaviors and limitations imposed by different VMs and APIs. By
/// the time this is written, An implementation may swallow exceptions (JSC),
/// may not pause (V8), and may not support bounded executions.
virtual bool drainMicrotasks(int maxMicrotasksHint = -1) = 0;
//virtual bool drainMicrotasks(int maxMicrotasksHint = -1) = 0;

/// \return the global object
virtual Object global() = 0;
Expand Down
5 changes: 3 additions & 2 deletions src/ios/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ add_library(realm-js-ios STATIC
platform.mm
)

target_link_libraries(realm-js-jsc PUBLIC "-framework JavaScriptCore")
target_link_libraries(realm-js-ios realm-js-jsc realm-js-shared)
# target_link_libraries(realm-js-jsc PUBLIC "-framework JavaScriptCore")
# target_link_libraries(realm-js-ios realm-js-jsc realm-js-shared)
target_link_libraries(realm-js-ios realm-js-hermes realm-js-shared)

0 comments on commit 53061e8

Please sign in to comment.