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
70 changes: 54 additions & 16 deletions NativeScript/NativeScript.mm
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,63 @@ @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 (RuntimeConfig.IsDebug) {
Console::DetachInspectorClient();
}
tns::Tasks::ClearTasks();
if (runtime_ != nullptr) {
runtime_ = nullptr;
}
}

- (instancetype)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 @@ -58,26 +103,19 @@ - (instancetype)initWithConfig:(Config*)config {
Console::AttachInspectorClient(inspectorClient);
}
}

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 {
return [self initializeWithConfig:config];
}

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
Binary file not shown.
4 changes: 4 additions & 0 deletions NativeScript/runtime/Console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ void Console::AttachInspectorClient(v8_inspector::JsV8InspectorClient* aInspecto
inspector = aInspector;
}

void Console::DetachInspectorClient() {
inspector = nullptr;
}

void Console::LogCallback(const FunctionCallbackInfo<Value>& args) {
// TODO: implement 'forceLog' override option like android has, to force logs in prod if desired
if (!RuntimeConfig.LogToSystemConsole) {
Expand Down
1 change: 1 addition & 0 deletions NativeScript/runtime/Console.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class Console {
public:
static void Init(v8::Local<v8::Context> context);
static void AttachInspectorClient(v8_inspector::JsV8InspectorClient* inspector);
static void DetachInspectorClient();
private:
using ConsoleAPIType = v8_inspector::ConsoleAPIType;

Expand Down
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 @@ -303,6 +303,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
4 changes: 4 additions & 0 deletions NativeScript/runtime/Tasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ void Tasks::Drain() {
}
}

void Tasks::ClearTasks() {
tasks_.clear();
}

std::vector<std::function<void()>> Tasks::tasks_;

}
1 change: 1 addition & 0 deletions NativeScript/runtime/Tasks.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class Tasks {
public:
static void Register(std::function<void()> task);
static void Drain();
static void ClearTasks();
private:
static std::vector<std::function<void()>> tasks_;
};
Expand Down
20 changes: 18 additions & 2 deletions build_nativescript.sh
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ xcodebuild -project v8ios.xcodeproj \
-configuration Release clean \
$QUIET

if $BUILD_CATALYST; then
checkpoint "Building NativeScript for Mac Catalyst"
xcodebuild archive -project v8ios.xcodeproj \
-scheme "NativeScript" \
-configuration Release \
-destination "platform=macOS,variant=Mac Catalyst" \
$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

if $BUILD_SIMULATOR; then
checkpoint "Building NativeScript for iphone simulators (multi-arch)"
xcodebuild archive -project v8ios.xcodeproj \
Expand All @@ -71,7 +85,8 @@ xcodebuild archive -project v8ios.xcodeproj \
EXCLUDED_ARCHS="i386" \
DEVELOPMENT_TEAM=$DEV_TEAM \
SKIP_INSTALL=NO \
BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
BUILD_LIBRARIES_FOR_DISTRIBUTION=YES \
INCLUDE_DEFAULT_METADATA=$INCLUDE_DEFAULT_METADATA\
-archivePath $DIST/intermediates/NativeScript.iphonesimulator.xcarchive
fi

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

Expand Down
Loading
Loading