Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build option for mac platform #2

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ x.x.x Release notes (yyyy-MM-dd)
=============================================================
### Enhancements
* Add ability to listen to changes to `Realm.App` and `Realm.User`. ([#4455](https://github.com/realm/realm-js/issues/4455))
* Add support for react-native-macos ([#2907](https://github.com/realm/realm-js/issues/2907))

### Fixed
* Fixed issue where React Native apps would sometimes show stale Realm data until the user interacted with the app UI ([#4389](https://github.com/realm/realm-js/issues/4389), since v10.0.0)
Expand Down
6 changes: 4 additions & 2 deletions RealmJS.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Pod::Spec.new do |s|

s.authors = package['author']
s.homepage = package['homepage']
s.platform = :ios, '9.0'
s.platforms = { :ios => "9.0", :osx => "10.13" }

# The source field is a required field in the podspec, but it is not ment to be used.
# This is because the Podspec is not ment to be published into a CocoaPod repository, instead React Native uses a :path style dependency when adding this to the users projects Podfile.
Expand Down Expand Up @@ -63,7 +63,9 @@ Pod::Spec.new do |s|
}

# TODO: Consider providing an option to build with the -dbg binaries instead
s.vendored_frameworks = 'react-native/ios/realm-js-ios.xcframework'
s.ios.vendored_frameworks = 'react-native/ios/realm-js-ios.xcframework'
s.osx.vendored_libraries = 'react-native/ios/realm-js-ios.xcframework/macos-arm64_x86_64/librealm-js-ios.a'
s.osx.public_header_files = ['react-native/ios/realm-js-ios.xcframework/macos-arm64_x86_64/Headers/realm-js-ios/jsc_init.h', 'react-native/ios/realm-js-ios.xcframework/macos-arm64_x86_64/Headers/realm-js-ios/rpc.hpp']

s.dependency 'React'
# TODO: Ensure the same version of GCDWebServer is used for Android
Expand Down
8 changes: 8 additions & 0 deletions react-native/ios/RealmReact.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@
F606901D1CA2766F0003FB26 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../../../react-native/React/**",
Expand All @@ -501,12 +502,16 @@
);
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos";
SUPPORTS_MACCATALYST = YES;
TARGETED_DEVICE_FAMILY = "1,2,6";
};
name = Debug;
};
F606901E1CA2766F0003FB26 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../../../react-native/React/**",
Expand All @@ -520,6 +525,9 @@
);
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "watchsimulator watchos macosx iphonesimulator iphoneos driverkit appletvsimulator appletvos";
SUPPORTS_MACCATALYST = YES;
TARGETED_DEVICE_FAMILY = "1,2,6";
};
name = Release;
};
Expand Down
44 changes: 17 additions & 27 deletions react-native/ios/RealmReact/RealmReact.mm
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,11 @@

#import "RealmReact.h"

#if TARGET_OS_OSX
#import "jsc_init.h"
#else
#import <realm-js-ios/jsc_init.h>
#endif

#import <React/RCTBridge+Private.h>
#import <React/RCTJavaScriptExecutor.h>
Expand All @@ -34,7 +38,13 @@
#import <thread>

#if DEBUG

#if TARGET_OS_OSX
#include "rpc.hpp"
#else
#include <realm-js-ios/rpc.hpp>
#endif

#import "GCDWebServer.h"
#import "GCDWebServerDataRequest.h"
#import "GCDWebServerDataResponse.h"
Expand All @@ -59,29 +69,9 @@ - (void *)runtime;
- (std::shared_ptr<facebook::react::CallInvoker>)jsCallInvoker;
@end

// no longer needed in React Native > 0.44
extern "C" JSGlobalContextRef RealmReactGetJSGlobalContextForExecutor(id executor, bool create) {
Ivar contextIvar = class_getInstanceVariable([executor class], "_context");
if (!contextIvar) {
return NULL;
}

id rctJSContext = object_getIvar(executor, contextIvar);
if (!rctJSContext && create) {
Class RCTJavaScriptContext = NSClassFromString(@"RCTJavaScriptContext");
if ([RCTJavaScriptContext instancesRespondToSelector:@selector(initWithJSContext:onThread:)]) {
// for RN 0.28.0+
rctJSContext = [[RCTJavaScriptContext alloc] initWithJSContext:[JSContext new] onThread:[NSThread currentThread]];
}
else {
// for RN < 0.28.0
NSCAssert([RCTJavaScriptContext instancesRespondToSelector:@selector(initWithJSContext:)], @"React Native version too old");
rctJSContext = [[RCTJavaScriptContext alloc] initWithJSContext:[JSContext new]];
}

object_setIvar(executor, contextIvar, rctJSContext);
}

return [rctJSContext context].JSGlobalContextRef;
return NULL;
}

@interface RealmReact () <RCTBridgeModule, RCTInvalidating>
Expand Down Expand Up @@ -271,7 +261,7 @@ - (void)shutdownRPC {

- (void)invalidate {
#if DEBUG
// Immediately close any open sync sessions to prevent race condition with new JS thread
// Immediately close any open sync sessions to prevent race condition with new JS thread
// when hot reloading
RJSCloseSyncSessions();
#endif
Expand Down Expand Up @@ -322,7 +312,7 @@ - (void)setBridge:(RCTBridge *)bridge {
if (!self || !bridge) {
return;
}

_initializeOnJSThread(^{
// RN < 0.58 has a private method that returns the js context
if ([bridge respondsToSelector:@selector(jsContextRef)]) {
Expand All @@ -339,8 +329,8 @@ - (void)setBridge:(RCTBridge *)bridge {
return static_cast<RealmJSCRuntime*>(bridge.runtime)->ctx_;
}, ^{
// Calling jsCallInvokver->invokeAsync tells React Native to execute the lambda passed
// in on the JS thread, and then flush the internal "microtask queue", which has the
// effect of flushing any pending UI updates.
// in on the JS thread, and then flush the internal "microtask queue", which has the
// effect of flushing any pending UI updates.
//
// We call this after we have called into JS from C++, in order to ensure that the RN
// UI updates in response to any changes from Realm. We need to do this as we bypass
Expand All @@ -351,7 +341,7 @@ - (void)setBridge:(RCTBridge *)bridge {
// Calls are debounced using the waitingForUiFlush flag, so if an async flush is already
// pending when another JS to C++ call happens, we don't call invokeAsync again. This works
// because the work is performed before the microtask queue is flushed - see sequence
// diagram at https://bit.ly/3kexhHm. It might be possible to further optimize this,
// diagram at https://bit.ly/3kexhHm. It might be possible to further optimize this,
// e.g. only flush the queue a maximum of once per frame, but this seems reasonable.
if (!waitingForUiFlush) {
waitingForUiFlush = true;
Expand Down
21 changes: 17 additions & 4 deletions scripts/build-ios.sh
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ function usage {
echo ""
echo "Arguments:"
echo " -c : build configuration (Debug or Release)"
echo " <platforms> : platforms to build for (catalyst, ios, or simulator)"
echo " <platforms> : platforms to build for (catalyst, ios, macosx, or simulator)"
exit 1;
}

CONFIGURATION=Release
SUPPORT_PLATFORMS=(catalyst ios simulator)
SUPPORT_PLATFORMS=(catalyst ios macosx simulator)

function is_supported_platform(){
for platform in "${SUPPORT_PLATFORMS[@]}"; do
Expand All @@ -40,7 +40,7 @@ PLATFORMS=($@)

if [ -z ${PLATFORMS} ]; then
echo "No platform given. building all platforms...";
PLATFORMS=(ios catalyst simulator)
PLATFORMS=(ios catalyst macosx simulator)
else
echo "Building for...";
for check_platform in "${PLATFORMS[@]}"; do
Expand Down Expand Up @@ -68,6 +68,19 @@ for platform in "${PLATFORMS[@]}"; do
LIBRARIES+=(-library ./out/$CONFIGURATION-maccatalyst/librealm-js-ios.a -headers ./_include)
BUILD_LIB_CMDS+=("xcrun libtool -static -o ./out/$CONFIGURATION-maccatalyst/librealm-js-ios.a ./out/$CONFIGURATION-maccatalyst/*.a")
;;
macosx)
DESTINATIONS+=(-destination 'generic/platform=OS X')

# We are unable to use a specific archive output directory for macosx because \$EFFECTIVE_PLATFORM_NAME
# is not being emitted for the Mac OS X platform. Theoretically, this should work by adding
# `set_property(GLOBAL PROPERTY XCODE_EMIT_EFFECTIVE_PLATFORM_NAME ON)`
# to xcode.toolchain.cmake in realm-core, but have unable to make it work thus far.
# LIBRARIES+=(-library ./out/$CONFIGURATION-macosx/librealm-js-ios.a -headers ./_include)
# BUILD_LIB_CMDS+=("xcrun libtool -static -o ./out/$CONFIGURATION-macosx/librealm-js-ios.a ./out/$CONFIGURATION-macosx/*.a")

LIBRARIES+=(-library ./out/$CONFIGURATION/librealm-js-ios.a -headers ./_include)
BUILD_LIB_CMDS+=("xcrun libtool -static -o ./out/$CONFIGURATION/librealm-js-ios.a ./out/$CONFIGURATION/*.a")
;;
simulator)
DESTINATIONS+=(-destination 'generic/platform=iOS Simulator')
LIBRARIES+=(-library ./out/$CONFIGURATION-iphonesimulator/librealm-js-ios.a -headers ./_include)
Expand All @@ -89,7 +102,7 @@ pushd build
# Configure CMake project
SDKROOT="${SDK_ROOT_OVERRIDE:-/Applications/Xcode_12.4.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/}" cmake "$PROJECT_ROOT" -GXcode \
-DCMAKE_TOOLCHAIN_FILE="$PROJECT_ROOT/vendor/realm-core/tools/cmake/xcode.toolchain.cmake" \
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(pwd)/out/$<CONFIG>\$EFFECTIVE_PLATFORM_NAME" \
-DCMAKE_ARCHIVE_OUTPUT_DIRECTORY="$(pwd)/out/$<CONFIG>\$EFFECTIVE_PLATFORM_NAME"

DEVELOPER_DIR="${DEVELOPER_DIR_OVERRIDE:-/Applications/Xcode_12.4.app}" xcodebuild build \
-scheme realm-js-ios \
Expand Down