Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions NativeScript/NativeScript.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,10 @@
- (bool)liveSync;

@end

@interface NativeScriptRuntime : NSObject

+ (BOOL)reloadApplication;
+ (BOOL)reloadApplication:(NSString*)baseDir;

@end
53 changes: 53 additions & 0 deletions NativeScript/NativeScript.mm
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@ @implementation Config

@end

static Config* CopyConfig(Config* config) {
Config* copy = [[Config alloc] init];
copy.BaseDir = config.BaseDir;
copy.ApplicationPath = config.ApplicationPath;
copy.MetadataPtr = config.MetadataPtr;
copy.IsDebug = config.IsDebug;
copy.LogToSystemConsole = config.LogToSystemConsole;
copy.ArgumentsCount = config.ArgumentsCount;
copy.Arguments = config.Arguments;
return copy;
}

static NativeScript* currentNativeScript;
static Config* currentConfig;

@implementation NativeScript

extern char defaultStartOfMetadataSection __asm("section$start$__DATA$__TNSMetadata");
Expand Down Expand Up @@ -82,6 +97,9 @@ - (void)shutdownRuntime {

- (instancetype)initializeWithConfig:(Config*)config {
if (self = [super init]) {
currentNativeScript = self;
currentConfig = CopyConfig(config);

RuntimeConfig.BaseDir = [config.BaseDir UTF8String];
if (config.ApplicationPath != nil) {
RuntimeConfig.ApplicationPath =
Expand All @@ -98,6 +116,15 @@ - (instancetype)initializeWithConfig:(Config*)config {
RuntimeConfig.IsDebug = [config IsDebug];
RuntimeConfig.LogToSystemConsole = [config LogToSystemConsole];

// Connect the JS-exposed `NativeScriptRuntime.reloadApplication(baseDir?)`
// global (registered by the runtime) to the Objective-C implementation below.
tns::SetReloadApplicationHook([](const std::string& baseDir) -> bool {
NSString* dir = baseDir.empty()
? nil
: [NSString stringWithUTF8String:baseDir.c_str()];
return [NativeScriptRuntime reloadApplication:dir] == YES;
});

Runtime::Initialize();
runtime_ = nullptr;
runtime_ = std::make_unique<Runtime>();
Expand Down Expand Up @@ -135,3 +162,29 @@ - (void)restartWithConfig:(Config*)config {
}

@end

@implementation NativeScriptRuntime

+ (BOOL)reloadApplication {
return [self reloadApplication:nil];
}

+ (BOOL)reloadApplication:(NSString*)baseDir {
if (currentNativeScript == nil || currentConfig == nil) {
return NO;
}

Config* config = CopyConfig(currentConfig);
if (baseDir != nil && [baseDir length] > 0) {
config.BaseDir = baseDir;
}

dispatch_async(dispatch_get_main_queue(), ^{
[currentNativeScript restartWithConfig:config];
[currentNativeScript runMainApplication];
});

return YES;
}

@end
9 changes: 9 additions & 0 deletions NativeScript/runtime/Runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,15 @@
#include "SpinLock.h"
#include "libplatform/libplatform.h"

#include <functional>
#include <string>

namespace tns {

using ReloadApplicationHook = std::function<bool(const std::string& baseDir)>;
void SetReloadApplicationHook(ReloadApplicationHook hook);
bool InvokeReloadApplicationHook(const std::string& baseDir);

class Runtime {
public:
Runtime();
Expand Down Expand Up @@ -67,6 +74,8 @@ class Runtime {
void DefineCollectFunction(v8::Local<v8::Context> context);
void DefineNativeScriptVersion(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> globalTemplate);
void DefineNativeScriptRuntime(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> globalTemplate);
void DefinePerformanceObject(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> globalTemplate);
void DefineTimeMethod(v8::Isolate* isolate,
Expand Down
36 changes: 36 additions & 0 deletions NativeScript/runtime/Runtime.mm
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ void DisposeIsolateWhenPossible(Isolate* isolate) {
tns::binding::CreateInternalBindingTemplates(isolate, globalTemplateFunction);
Local<ObjectTemplate> globalTemplate = ObjectTemplate::New(isolate, globalTemplateFunction);
DefineNativeScriptVersion(isolate, globalTemplate);
DefineNativeScriptRuntime(isolate, globalTemplate);

// Worker::Init(isolate, globalTemplate, isWorker);
DefinePerformanceObject(isolate, globalTemplate);
Expand Down Expand Up @@ -573,6 +574,41 @@ void DisposeIsolateWhenPossible(Isolate* isolate) {
ToV8String(isolate, STRINGIZE_VALUE_OF(NATIVESCRIPT_VERSION)), readOnlyFlags);
}

static ReloadApplicationHook reloadApplicationHook_;

void SetReloadApplicationHook(ReloadApplicationHook hook) {
reloadApplicationHook_ = std::move(hook);
}

bool InvokeReloadApplicationHook(const std::string& baseDir) {
if (!reloadApplicationHook_) {
return false;
}
return reloadApplicationHook_(baseDir);
}

// API to trigger application reload from JS without restarting the application process.
// Exposes `global.NativeScriptRuntime.reloadApplication(baseDir?)` to JS.
// `NativeScriptRuntime` class is part of the runtime framework and
// is intentionally excluded from metadata generation, so it is not reachable
// from JS on its own.
void Runtime::DefineNativeScriptRuntime(Isolate* isolate, Local<ObjectTemplate> globalTemplate) {
Local<ObjectTemplate> runtimeTemplate = ObjectTemplate::New(isolate);

Local<FunctionTemplate> reloadTemplate =
FunctionTemplate::New(isolate, [](const FunctionCallbackInfo<Value>& info) {
Isolate* isolate = info.GetIsolate();
std::string baseDir;
if (info.Length() > 0 && info[0]->IsString()) {
baseDir = tns::ToString(isolate, info[0]);
}
info.GetReturnValue().Set(tns::InvokeReloadApplicationHook(baseDir));
});
runtimeTemplate->Set(ToV8String(isolate, "reloadApplication"), reloadTemplate);

globalTemplate->Set(ToV8String(isolate, "NativeScriptRuntime"), runtimeTemplate);
}

void Runtime::DefineTimeMethod(v8::Isolate* isolate, v8::Local<v8::ObjectTemplate> globalTemplate) {
Local<FunctionTemplate> timeFunctionTemplate =
FunctionTemplate::New(isolate, [](const FunctionCallbackInfo<Value>& info) {
Expand Down
Loading