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

feat: allow embedding into Swift host projects #231

Merged
merged 11 commits into from
Jul 1, 2024
4 changes: 4 additions & 0 deletions NativeScript/NativeScript.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
@interface NativeScript : NSObject

- (instancetype)initWithConfig:(Config*)config;
- (void)runScriptString: (NSString*) script runLoop: (BOOL) runLoop;
- (void)restartWithConfig:(Config*)config;
- (void)shutdownRuntime;

/**
WARNING: this method does not return in most applications. (UIApplicationMain)
*/
Expand Down
79 changes: 62 additions & 17 deletions NativeScript/NativeScript.mm
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,68 @@ @implementation Config

@implementation NativeScript

std::unique_ptr<Runtime> runtime_;
extern char defaultStartOfMetadataSection __asm("section$start$__DATA$__TNSMetadata");

- (instancetype)initWithConfig:(Config*)config {
- (void)runScriptString: (NSString*) script runLoop: (BOOL) runLoop {

std::string cppString = std::string([script UTF8String]);
runtime_->RunScript(cppString);

if (runLoop) {
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
}


tns::Tasks::Drain();

}

std::unique_ptr<Runtime> runtime_;

- (void)runMainApplication {
runtime_->RunMainScript();

CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);

tns::Tasks::Drain();
}

- (bool)liveSync {
if (runtime_ == nullptr) {
return false;
}

Isolate* isolate = runtime_->GetIsolate();
return tns::LiveSync(isolate);
}

- (void)shutdownRuntime {
if (runtime_ != nullptr) {
Isolate* isolate = runtime_->GetIsolate();
{
v8::Locker l(isolate);
v8::Isolate::Scope isolate_scope(isolate);
v8::HandleScope handle_scope(isolate);

isolate->Dispose();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this likely shouldn't be done here (the runtime destructor is responsible for deleting this isolate)

}
runtime_ = nullptr;
}
}

- (void)initializeWithConfig:(Config*)config {
if (self = [super init]) {
RuntimeConfig.BaseDir = [config.BaseDir UTF8String];
if (config.ApplicationPath != nil) {
RuntimeConfig.ApplicationPath = [[config.BaseDir stringByAppendingPathComponent:config.ApplicationPath] UTF8String];
} else {
RuntimeConfig.ApplicationPath = [[config.BaseDir stringByAppendingPathComponent:@"app"] UTF8String];
}
RuntimeConfig.MetadataPtr = [config MetadataPtr];
if (config.MetadataPtr != nil) {
RuntimeConfig.MetadataPtr = [config MetadataPtr];
} else {
RuntimeConfig.MetadataPtr = &defaultStartOfMetadataSection;
}
RuntimeConfig.IsDebug = [config IsDebug];
RuntimeConfig.LogToSystemConsole = [config LogToSystemConsole];

Expand All @@ -59,25 +109,20 @@ - (instancetype)initWithConfig:(Config*)config {
}
}

return self;
Copy link
Collaborator

@edusperoni edusperoni Apr 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't this still return self?


}

- (void)runMainApplication {
runtime_->RunMainScript();

CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true);
- (instancetype)initWithConfig:(Config*)config {
if (self = [super init]) {
[self initializeWithConfig:config];
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

init will be called twice if this method is called (one here and another in initializeWithConfig)

return self;
}

tns::Tasks::Drain();
- (void)restartWithConfig:(Config*)config {
[self shutdownRuntime];
[self initializeWithConfig:config];
}

- (bool)liveSync {
if (runtime_ == nullptr) {
return false;
}

Isolate* isolate = runtime_->GetIsolate();
return tns::LiveSync(isolate);
}

@end
Binary file added NativeScript/metadata-arm64.bin
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how do we generate this again when the metadata is updated? Shouldn't this just be part of the build process?

Binary file not shown.
4 changes: 4 additions & 0 deletions NativeScript/runtime/ModuleInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ class ModuleInternal {
public:
ModuleInternal(v8::Local<v8::Context> context);
bool RunModule(v8::Isolate* isolate, std::string path);
void RunScript(v8::Isolate* isolate, std::string script);

private:
static void RequireCallback(const v8::FunctionCallbackInfo<v8::Value>& info);
v8::Local<v8::Function> GetRequireFunction(v8::Isolate* isolate, const std::string& dirName);
Expand All @@ -23,6 +25,8 @@ class ModuleInternal {
v8::ScriptCompiler::CachedData* LoadScriptCache(const std::string& path);
void SaveScriptCache(const v8::Local<v8::Script> script, const std::string& path);
std::string GetCacheFileName(const std::string& path);
v8::MaybeLocal<v8::Value> RunScriptString(v8::Isolate* isolate, v8::Local<v8::Context> context, const std::string script);


std::unique_ptr<v8::Persistent<v8::Function>> requireFunction_;
std::unique_ptr<v8::Persistent<v8::Function>> requireFactoryFunction_;
Expand Down
22 changes: 22 additions & 0 deletions NativeScript/runtime/ModuleInternal.mm
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,28 @@
return script;
}

MaybeLocal<Value> ModuleInternal::RunScriptString(Isolate* isolate, Local<Context> context, const std::string scriptString) {
ScriptCompiler::CompileOptions options = ScriptCompiler::kNoCompileOptions;
ScriptCompiler::Source source(tns::ToV8String(isolate, scriptString));
TryCatch tc(isolate);
Local<Script> script = ScriptCompiler::Compile(context, &source, options).ToLocalChecked();
MaybeLocal<Value> result = script->Run(context);
return result;
}


void ModuleInternal::RunScript(Isolate* isolate, std::string script) {
std::shared_ptr<Caches> cache = Caches::Get(isolate);
Local<Context> context = cache->GetContext();
Local<Object> globalObject = context->Global();
Local<Value> requireObj;
bool success = globalObject->Get(context, ToV8String(isolate, "require")).ToLocal(&requireObj);
tns::Assert(success && requireObj->IsFunction(), isolate);
Local<Value> result;
this->RunScriptString(isolate, context, script);
}


Local<v8::String> ModuleInternal::WrapModuleContent(Isolate* isolate, const std::string& path) {
return tns::ReadModule(isolate, path);
}
Expand Down
2 changes: 2 additions & 0 deletions NativeScript/runtime/Runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class Runtime {
}

void RunModule(const std::string moduleName);

void RunScript(const std::string script);

static void Initialize();

Expand Down
9 changes: 9 additions & 0 deletions NativeScript/runtime/Runtime.mm
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,15 @@ void DisposeIsolateWhenPossible(Isolate* isolate) {
this->moduleInternal_->RunModule(isolate, moduleName);
}

void Runtime::RunScript(const std::string script) {
Isolate* isolate = this->GetIsolate();
v8::Locker locker(isolate);
Isolate::Scope isolate_scope(isolate);
HandleScope handle_scope(isolate);
this->moduleInternal_->RunScript(isolate, script);
}


Isolate* Runtime::GetIsolate() {
return this->isolate_;
}
Expand Down
6 changes: 6 additions & 0 deletions build_nativescript.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ xcodebuild archive -project v8ios.xcodeproj \
$QUIET \
EXCLUDED_ARCHS="x86_64" \
SKIP_INSTALL=NO \
BUILD_LIBRARIES_FOR_DISTRIBUTION=YES \
INCLUDE_DEFAULT_METADATA=$INCLUDE_DEFAULT_METADATA\
-archivePath $DIST/intermediates/NativeScript.maccatalyst.xcarchive
fi

Expand Down Expand Up @@ -104,6 +106,8 @@ xcodebuild archive -project v8ios.xcodeproj \
EXCLUDED_ARCHS="i386" \
DEVELOPMENT_TEAM=$DEV_TEAM \
SKIP_INSTALL=NO \
BUILD_LIBRARIES_FOR_DISTRIBUTION=YES \
INCLUDE_DEFAULT_METADATA=$INCLUDE_DEFAULT_METADATA\
-archivePath $DIST/intermediates/NativeScript.iphonesimulator.xcarchive
fi

Expand All @@ -118,6 +122,8 @@ xcodebuild archive -project v8ios.xcodeproj \
EXCLUDED_ARCHS="armv7" \
DEVELOPMENT_TEAM=$DEV_TEAM \
SKIP_INSTALL=NO \
BUILD_LIBRARIES_FOR_DISTRIBUTION=YES \
INCLUDE_DEFAULT_METADATA=$INCLUDE_DEFAULT_METADATA\
-archivePath $DIST/intermediates/NativeScript.iphoneos.xcarchive

#Create fat library for simulator
Expand Down
75 changes: 69 additions & 6 deletions v8ios.xcodeproj/project.pbxproj
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all these changes necessary in this pbxproj file @tdermendjiev ?

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
2B7EA6AF2353477000E5184E /* NativeScriptException.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2B7EA6AD2353476F00E5184E /* NativeScriptException.mm */; };
2B7EA6B02353477000E5184E /* NativeScriptException.h in Headers */ = {isa = PBXBuildFile; fileRef = 2B7EA6AE2353477000E5184E /* NativeScriptException.h */; };
2BFE22062AC1C93100307752 /* metadata-arm64.bin in Resources */ = {isa = PBXBuildFile; fileRef = 2BFE22052AC1C93100307752 /* metadata-arm64.bin */; };
3C1850542A6DCB2D002ACC81 /* Timers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C1850522A6DCB2D002ACC81 /* Timers.cpp */; };
3C1850552A6DCB2D002ACC81 /* Timers.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 3C1850532A6DCB2D002ACC81 /* Timers.hpp */; };
3C78BA5C2A0D600100C20A88 /* ModuleBinding.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3C78BA5A2A0D600100C20A88 /* ModuleBinding.cpp */; };
Expand Down Expand Up @@ -423,6 +424,15 @@
/* Begin PBXFileReference section */
2B7EA6AD2353476F00E5184E /* NativeScriptException.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = NativeScriptException.mm; sourceTree = "<group>"; };
2B7EA6AE2353477000E5184E /* NativeScriptException.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeScriptException.h; sourceTree = "<group>"; };
2BFE21F22AC1B7D500307752 /* UIView+NativeScript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+NativeScript.h"; sourceTree = "<group>"; };
2BFE21F32AC1B7D500307752 /* UIView+NativeScript.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+NativeScript.m"; sourceTree = "<group>"; };
2BFE21F42AC1B7D500307752 /* NativeScriptUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeScriptUtils.h; sourceTree = "<group>"; };
2BFE21F52AC1B7D500307752 /* NativeScriptUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NativeScriptUtils.m; sourceTree = "<group>"; };
2BFE21F62AC1B7D600307752 /* NativeScriptEmbedder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeScriptEmbedder.h; sourceTree = "<group>"; };
2BFE21F72AC1B7D600307752 /* NativeScriptEmbedder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NativeScriptEmbedder.m; sourceTree = "<group>"; };
2BFE21F82AC1B7D600307752 /* NativeScriptSDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeScriptSDK.h; sourceTree = "<group>"; };
2BFE22002AC1C65B00307752 /* module.modulemap */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.module-map"; path = module.modulemap; sourceTree = "<group>"; };
2BFE22052AC1C93100307752 /* metadata-arm64.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; path = "metadata-arm64.bin"; sourceTree = "<group>"; };
3C1850522A6DCB2D002ACC81 /* Timers.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Timers.cpp; sourceTree = "<group>"; };
3C1850532A6DCB2D002ACC81 /* Timers.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Timers.hpp; sourceTree = "<group>"; };
3C78BA5A2A0D600100C20A88 /* ModuleBinding.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ModuleBinding.cpp; sourceTree = "<group>"; };
Expand Down Expand Up @@ -863,6 +873,21 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
2BFE21F12AC1B79F00307752 /* embedding */ = {
isa = PBXGroup;
children = (
2BFE21F62AC1B7D600307752 /* NativeScriptEmbedder.h */,
2BFE21F72AC1B7D600307752 /* NativeScriptEmbedder.m */,
2BFE21F82AC1B7D600307752 /* NativeScriptSDK.h */,
2BFE21F42AC1B7D500307752 /* NativeScriptUtils.h */,
2BFE21F52AC1B7D500307752 /* NativeScriptUtils.m */,
2BFE21F22AC1B7D500307752 /* UIView+NativeScript.h */,
2BFE21F32AC1B7D500307752 /* UIView+NativeScript.m */,
2BFE22002AC1C65B00307752 /* module.modulemap */,
);
path = embedding;
sourceTree = "<group>";
};
6573B9C1291FE29F00B0ED7C /* v8runtime */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -1310,6 +1335,8 @@
C2DDEB33229EAB3B00345BFE /* NativeScript */ = {
isa = PBXGroup;
children = (
2BFE22052AC1C93100307752 /* metadata-arm64.bin */,
2BFE21F12AC1B79F00307752 /* embedding */,
F6191AA529C0FCE7003F588F /* inspector */,
6573B9D8291FE2A700B0ED7C /* jsi */,
6573B9C1291FE29F00B0ED7C /* v8runtime */,
Expand Down Expand Up @@ -1670,6 +1697,7 @@
C2DDEB2F229EAB3B00345BFE /* Frameworks */,
C2DDEB30229EAB3B00345BFE /* Resources */,
65A6D684291F63A30074DF31 /* ShellScript */,
2BFE21F02AC1B28000307752 /* Add default metadata */,
);
buildRules = (
);
Expand Down Expand Up @@ -1793,12 +1821,31 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
2BFE22062AC1C93100307752 /* metadata-arm64.bin in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */
2BFE21F02AC1B28000307752 /* Add default metadata */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Add default metadata";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "echo \"Checking flags to determine whether to copy default metadata\"\nif [ \"$INCLUDE_DEFAULT_METADATA\" = true ] ; then\necho \"Copying ${SRCROOT}/${PRODUCT_NAME}/metadata/metadata-arm64.bin directory to ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework\"\ncp ${SRCROOT}/${PRODUCT_NAME}/metadata/metadata-arm64.bin ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/metadata-arm64.bin\necho \"metadata-arm64.bin has been copied.\"\necho \"Copying ${SRCROOT}/${PRODUCT_NAME}/metadata/metadata-x86_64.bin directory to ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework\"\ncp ${SRCROOT}/${PRODUCT_NAME}/metadata/metadata-x86_64.bin ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/metadata-x86_64.bin\necho \"metadata-x86_64.bin has been copied.\"\nelse\necho \"Skipped copying metadata binaries.\"\nfi\n\n";
};
65A6D684291F63A30074DF31 /* ShellScript */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
Expand Down Expand Up @@ -2450,13 +2497,17 @@
"$(PROJECT_DIR)/AppWithModules/Frameworks",
);
GCC_C_LANGUAGE_STANDARD = gnu99;
HEADER_SEARCH_PATHS = "$(SRCROOT)/NativeScript";
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/NativeScript",
"$(SRCROOT)/NativeScript/embedding/",
);
INFOPLIST_FILE = AppWithModules/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
NS_DEBUG_METADATA_PATH = "/Users/teodordermendzhiev/workspace/ns-v8ios-runtime/yaml";
OTHER_LDFLAGS = (
"-Wl,-search_paths_first",
"-ObjC",
Expand Down Expand Up @@ -2485,13 +2536,17 @@
"$(PROJECT_DIR)/AppWithModules/Frameworks",
);
GCC_C_LANGUAGE_STANDARD = gnu99;
HEADER_SEARCH_PATHS = "$(SRCROOT)/NativeScript";
HEADER_SEARCH_PATHS = (
"$(SRCROOT)/NativeScript",
"$(SRCROOT)/NativeScript/embedding/",
);
INFOPLIST_FILE = AppWithModules/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
NS_DEBUG_METADATA_PATH = "/Users/teodordermendzhiev/workspace/ns-v8ios-runtime/yaml";
OTHER_LDFLAGS = (
"-Wl,-search_paths_first",
"-ObjC",
Expand Down Expand Up @@ -2647,10 +2702,10 @@
ALLOW_TARGET_PLATFORM_SPECIALIZATION = NO;
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_ENABLE_MODULES = NO;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = NO;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = NO;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
Expand Down Expand Up @@ -2705,6 +2760,10 @@
"-lcrdtp_platform",
"-linspector",
"-linspector_string_conversions",
"-sectcreate",
__DATA,
__TNSMetadata,
"\"$(SRCROOT)/NativeScript/metadata-arm64.bin\"",
);
PRODUCT_BUNDLE_IDENTIFIER = org.nativescript.NativeScript;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
Expand All @@ -2728,10 +2787,10 @@
ALLOW_TARGET_PLATFORM_SPECIALIZATION = NO;
BUILD_LIBRARY_FOR_DISTRIBUTION = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_ENABLE_MODULES = NO;
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = NO;
CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = NO;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
Expand Down Expand Up @@ -2784,6 +2843,10 @@
"-lcrdtp_platform",
"-linspector",
"-linspector_string_conversions",
"-sectcreate",
__DATA,
__TNSMetadata,
"\"$(SRCROOT)/NativeScript/metadata-arm64.bin\"",
);
PRODUCT_BUNDLE_IDENTIFIER = org.nativescript.NativeScript;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
Expand Down