From 6308072155041892fbf5940fc54c44e1877ceaab Mon Sep 17 00:00:00 2001 From: Wiktor Date: Tue, 22 Feb 2022 11:46:32 +0100 Subject: [PATCH 1/4] Added methods for starting project with custom arguments --- .../RNNodeJsMobileModule.java | 25 ++++++++ index.d.ts | 7 +++ index.js | 9 +++ ios/RNNodeJsMobile.m | 57 +++++++++++++++++++ 4 files changed, 98 insertions(+) diff --git a/android/src/main/java/com/janeasystems/rn_nodejs_mobile/RNNodeJsMobileModule.java b/android/src/main/java/com/janeasystems/rn_nodejs_mobile/RNNodeJsMobileModule.java index e882a0c..66e09ff 100644 --- a/android/src/main/java/com/janeasystems/rn_nodejs_mobile/RNNodeJsMobileModule.java +++ b/android/src/main/java/com/janeasystems/rn_nodejs_mobile/RNNodeJsMobileModule.java @@ -189,6 +189,31 @@ public void run() { } } + @ReactMethod + public void startNodeProjectWithArgs(final String mainFileName, final String... args, ReadableMap options) throws Exception { + // A New module instance may have been created due to hot reload. + _instance = this; + if(!_startedNodeAlready) { + _startedNodeAlready = true; + + final boolean redirectOutputToLogcat = extractRedirectOutputToLogcatOption(options); + + new Thread(new Runnable() { + @Override + public void run() { + waitForInit(); + startNodeWithArguments(new String[]{"node", + nodeJsProjectPath + "/" + mainFileName, + args + }, + nodeJsProjectPath + ":" + builtinModulesPath, + redirectOutputToLogcat + ); + } + }).start(); + } + } + @ReactMethod public void sendMessage(String channel, String msg) { sendMessageToNodeChannel(channel, msg); diff --git a/index.d.ts b/index.d.ts index 7ad3127..710219e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -6,6 +6,13 @@ declare module "nodejs-mobile-react-native" { * @param options */ start: (scriptFileName: string, options?: StartupOptions) => void + /** + * Starts the nodejs-mobile runtime thread with provided arguments + * @param scriptFileName + * @param options + * @param args + */ + startWithArgs: (scriptFileName: string, options?: StartupOptions, ...args: string[]) => void /** * Starts the nodejs-mobile runtime thread with a script body * @param scriptBody diff --git a/index.js b/index.js index 92a53ae..75290c5 100644 --- a/index.js +++ b/index.js @@ -87,6 +87,15 @@ const start=function(mainFileName, options) { options = options || {}; RNNodeJsMobile.startNodeProject(mainFileName, options); }; + +const startWithArgs=function(mainFileName, args, options) { + if (typeof mainFileName !== 'string') { + throw new Error('nodejs-mobile-react-native\'s start expects to receive the main .js entrypoint filename, e.g.: nodejs.start("main.js");'); + } + options = options || {}; + RNNodeJsMobile.startNodeProjectWithArgs(mainFileName, options, args); +}; + const startWithScript=function(script, options) { options = options || {}; RNNodeJsMobile.startNodeWithScript(script, options); diff --git a/ios/RNNodeJsMobile.m b/ios/RNNodeJsMobile.m index 00f11ef..5f3bfdf 100644 --- a/ios/RNNodeJsMobile.m +++ b/ios/RNNodeJsMobile.m @@ -101,6 +101,33 @@ -(void)callStartNodeProject:(NSString *)mainFileName [[NodeRunner sharedInstance] startEngineWithArguments:nodeArguments:nodePath]; } +-(void)callStartNodeProjectWithArgs:(NSDictionary *)dict +{ + NSString* srcPath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@/%@", NODEJS_PROJECT_RESOURCE_PATH, dict[@"mainFileName"]] ofType:@""]; + NSArray* nodeArguments = nil; + + NSString* dlopenoverridePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@/%@", NODEJS_PROJECT_RESOURCE_PATH, NODEJS_DLOPEN_OVERRIDE_FILENAME] ofType:@""]; + // Check if the file to override dlopen lookup exists, for loading native modules from the Frameworks. + if(!dlopenoverridePath) + { + nodeArguments = [NSArray arrayWithObjects: + @"node", + srcPath, + ]; + [nodeArguments addObjectsFromArray:dict[@"args"]]; + [nodeArguments addObject:nil]; + + } else { + nodeArguments = [NSArray arrayWithObjects: + @"node", + @"-r", + dlopenoverridePath, + srcPath, + nil + ]; + } + [[NodeRunner sharedInstance] startEngineWithArguments:nodeArguments:nodePath]; +} RCT_EXPORT_METHOD(startNodeWithScript:(NSString *)script options:(NSDictionary *)options) { @@ -136,6 +163,36 @@ -(void)callStartNodeProject:(NSString *)mainFileName } } +RCT_EXPORT_METHOD(startNodeProjectWithArgs:(NSString *)mainFileName options:(NSDictionary *)options, args:(NSString)args, ...) +{ + if(![NodeRunner sharedInstance].startedNodeAlready) + { + NSMutableArray * arguments = [NSMutableArray array]; + if(args) + { + [arguments addObject:args]; + id argument; + va_list argsList; + va_start(argsList, args); + while(argument = va_arg(argsList, NSString)) + { + [arguments addObject:argument]; + } + va_end(argsList); + } + [NodeRunner sharedInstance].startedNodeAlready=true; + NSThread* nodejsThread = nil; + nodejsThread = [[NSThread alloc] + initWithTarget:self + selector:@selector(callStartNodeProjectWithArgs:) + object:@{@"mainFileName":@mainFileName,@"args":@arguments} + ]; + // Set 2MB of stack space for the Node.js thread. + [nodejsThread setStackSize:2*1024*1024]; + [nodejsThread start]; + } +} + -(void) sendMessageBackToReact:(NSString*)channelName:(NSString*)message { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ From 2beb02f09cc5d451c0856f84153762f2f7f06615 Mon Sep 17 00:00:00 2001 From: Wiktor Date: Tue, 22 Feb 2022 17:21:46 +0100 Subject: [PATCH 2/4] Provide arguments in inline command --- .../RNNodeJsMobileModule.java | 22 ++++++++++++++---- index.d.ts | 2 +- index.js | 9 ++++---- ios/RNNodeJsMobile.m | 23 ++++++++++++------- 4 files changed, 38 insertions(+), 18 deletions(-) diff --git a/android/src/main/java/com/janeasystems/rn_nodejs_mobile/RNNodeJsMobileModule.java b/android/src/main/java/com/janeasystems/rn_nodejs_mobile/RNNodeJsMobileModule.java index 66e09ff..337de9b 100644 --- a/android/src/main/java/com/janeasystems/rn_nodejs_mobile/RNNodeJsMobileModule.java +++ b/android/src/main/java/com/janeasystems/rn_nodejs_mobile/RNNodeJsMobileModule.java @@ -190,22 +190,34 @@ public void run() { } @ReactMethod - public void startNodeProjectWithArgs(final String mainFileName, final String... args, ReadableMap options) throws Exception { + public void startNodeProjectWithArgs(final String input, ReadableMap options) throws Exception { // A New module instance may have been created due to hot reload. _instance = this; if(!_startedNodeAlready) { _startedNodeAlready = true; + List args = new ArrayList(Arrays.asList(input.split(" "))); + + String absoluteScriptPath = nodeJsProjectPath + "/" + args.get(0); + + // Remove script file name from arguments list + args.remove(0); + + final List command = new ArrayList(); + + command.add("node"); + command.add(absoluteScriptPath); + + command.addAll(args); + final boolean redirectOutputToLogcat = extractRedirectOutputToLogcatOption(options); new Thread(new Runnable() { @Override public void run() { waitForInit(); - startNodeWithArguments(new String[]{"node", - nodeJsProjectPath + "/" + mainFileName, - args - }, + startNodeWithArguments( + command.toArray(new String[0]), nodeJsProjectPath + ":" + builtinModulesPath, redirectOutputToLogcat ); diff --git a/index.d.ts b/index.d.ts index 710219e..bcda34a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -12,7 +12,7 @@ declare module "nodejs-mobile-react-native" { * @param options * @param args */ - startWithArgs: (scriptFileName: string, options?: StartupOptions, ...args: string[]) => void + startWithArgs: (command: string, options?: StartupOptions) => void /** * Starts the nodejs-mobile runtime thread with a script body * @param scriptBody diff --git a/index.js b/index.js index 75290c5..66c43d5 100644 --- a/index.js +++ b/index.js @@ -88,12 +88,12 @@ const start=function(mainFileName, options) { RNNodeJsMobile.startNodeProject(mainFileName, options); }; -const startWithArgs=function(mainFileName, args, options) { - if (typeof mainFileName !== 'string') { - throw new Error('nodejs-mobile-react-native\'s start expects to receive the main .js entrypoint filename, e.g.: nodejs.start("main.js");'); +const startWithArgs=function(command, options) { + if (typeof command !== 'string') { + throw new Error('nodejs-mobile-react-native\'s start expects to receive the main .js entrypoint filename with optional arguments, e.g.: nodejs.start("main.js -c custom");'); } options = options || {}; - RNNodeJsMobile.startNodeProjectWithArgs(mainFileName, options, args); + RNNodeJsMobile.startNodeProjectWithArgs(command, options); }; const startWithScript=function(script, options) { @@ -126,6 +126,7 @@ registerChannel(eventChannel); const export_object = { start: start, + startWithArgs: startWithArgs, startWithScript: startWithScript, channel: eventChannel }; diff --git a/ios/RNNodeJsMobile.m b/ios/RNNodeJsMobile.m index 5f3bfdf..e5c6d24 100644 --- a/ios/RNNodeJsMobile.m +++ b/ios/RNNodeJsMobile.m @@ -101,22 +101,29 @@ -(void)callStartNodeProject:(NSString *)mainFileName [[NodeRunner sharedInstance] startEngineWithArguments:nodeArguments:nodePath]; } --(void)callStartNodeProjectWithArgs:(NSDictionary *)dict +-(void)callStartNodeProjectWithArgs:(NSString *)input { - NSString* srcPath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@/%@", NODEJS_PROJECT_RESOURCE_PATH, dict[@"mainFileName"]] ofType:@""]; - NSArray* nodeArguments = nil; + NSArray* command = [input componentsSeparatedByString: @" "]; + NSString* script = [command objectAtIndex:0]; + + NSMutableArray* args = [command mutableCopy]; + [args removeObject:[args objectAtIndex:0]]; + + NSString* srcPath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@/%@", NODEJS_PROJECT_RESOURCE_PATH, script] ofType:@""]; + + NSMutableArray* nodeArguments = nil; NSString* dlopenoverridePath = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"%@/%@", NODEJS_PROJECT_RESOURCE_PATH, NODEJS_DLOPEN_OVERRIDE_FILENAME] ofType:@""]; // Check if the file to override dlopen lookup exists, for loading native modules from the Frameworks. if(!dlopenoverridePath) { - nodeArguments = [NSArray arrayWithObjects: + nodeArguments = [NSMutableArray arrayWithObjects: @"node", srcPath, - ]; - [nodeArguments addObjectsFromArray:dict[@"args"]]; - [nodeArguments addObject:nil]; + nil + ]; + [nodeArguments addObjectsFromArray:args]; } else { nodeArguments = [NSArray arrayWithObjects: @"node", @@ -124,7 +131,7 @@ -(void)callStartNodeProjectWithArgs:(NSDictionary *)dict dlopenoverridePath, srcPath, nil - ]; + ]; } [[NodeRunner sharedInstance] startEngineWithArguments:nodeArguments:nodePath]; } From 8ca0165efa6ef5c272d8c345b1e6605b7dbf9383 Mon Sep 17 00:00:00 2001 From: siepra Date: Wed, 23 Feb 2022 12:43:48 +0100 Subject: [PATCH 3/4] Fix passing args on iOS --- ios/RNNodeJsMobile.m | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/ios/RNNodeJsMobile.m b/ios/RNNodeJsMobile.m index e5c6d24..6ec9507 100644 --- a/ios/RNNodeJsMobile.m +++ b/ios/RNNodeJsMobile.m @@ -125,13 +125,15 @@ -(void)callStartNodeProjectWithArgs:(NSString *)input [nodeArguments addObjectsFromArray:args]; } else { - nodeArguments = [NSArray arrayWithObjects: + nodeArguments = [NSMutableArray arrayWithObjects: @"node", @"-r", dlopenoverridePath, srcPath, nil ]; + + [nodeArguments addObjectsFromArray:args]; } [[NodeRunner sharedInstance] startEngineWithArguments:nodeArguments:nodePath]; } @@ -170,29 +172,16 @@ -(void)callStartNodeProjectWithArgs:(NSString *)input } } -RCT_EXPORT_METHOD(startNodeProjectWithArgs:(NSString *)mainFileName options:(NSDictionary *)options, args:(NSString)args, ...) +RCT_EXPORT_METHOD(startNodeProjectWithArgs:(NSString *)command options:(NSDictionary *)options) { if(![NodeRunner sharedInstance].startedNodeAlready) { - NSMutableArray * arguments = [NSMutableArray array]; - if(args) - { - [arguments addObject:args]; - id argument; - va_list argsList; - va_start(argsList, args); - while(argument = va_arg(argsList, NSString)) - { - [arguments addObject:argument]; - } - va_end(argsList); - } [NodeRunner sharedInstance].startedNodeAlready=true; NSThread* nodejsThread = nil; nodejsThread = [[NSThread alloc] initWithTarget:self selector:@selector(callStartNodeProjectWithArgs:) - object:@{@"mainFileName":@mainFileName,@"args":@arguments} + object:command ]; // Set 2MB of stack space for the Node.js thread. [nodejsThread setStackSize:2*1024*1024]; From 3539b922be34dfec751740c63e0d3f4d9f902caa Mon Sep 17 00:00:00 2001 From: siepra Date: Wed, 16 Mar 2022 15:01:10 +0100 Subject: [PATCH 4/4] Updated documentation for startWithArgs feature --- README.md | 10 ++++++++++ index.d.ts | 3 +-- index.js | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index af7d322..cfdba7b 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,7 @@ import nodejs from 'nodejs-mobile-react-native'; ``` - `nodejs.start` +- `nodejs.startWithArgs` - `nodejs.startWithScript` - `nodejs.channel.addListener` - `nodejs.channel.post` @@ -138,6 +139,15 @@ import nodejs from 'nodejs-mobile-react-native'; Starts the nodejs-mobile runtime thread with a file inside the `nodejs-project` directory. +### nodejs.startWithArgs(command [, options]) + +| Param | Type | +| --- | --- | +| command | string | +| options | [StartupOptions](#ReactNative.StartupOptions) | + +Starts the nodejs-mobile runtime thread with a file inside the `nodejs-project` directory and passes provided arguments down to it. + ### nodejs.startWithScript(scriptBody [, options]) | Param | Type | diff --git a/index.d.ts b/index.d.ts index bcda34a..a9cf53e 100644 --- a/index.d.ts +++ b/index.d.ts @@ -8,9 +8,8 @@ declare module "nodejs-mobile-react-native" { start: (scriptFileName: string, options?: StartupOptions) => void /** * Starts the nodejs-mobile runtime thread with provided arguments - * @param scriptFileName + * @param command * @param options - * @param args */ startWithArgs: (command: string, options?: StartupOptions) => void /** diff --git a/index.js b/index.js index 66c43d5..fb09c48 100644 --- a/index.js +++ b/index.js @@ -90,7 +90,7 @@ const start=function(mainFileName, options) { const startWithArgs=function(command, options) { if (typeof command !== 'string') { - throw new Error('nodejs-mobile-react-native\'s start expects to receive the main .js entrypoint filename with optional arguments, e.g.: nodejs.start("main.js -c custom");'); + throw new Error('nodejs-mobile-react-native\'s startWithArgs expects to receive the main .js entrypoint filename with optional arguments, e.g.: nodejs.startWithArgs("main.js -c custom");'); } options = options || {}; RNNodeJsMobile.startNodeProjectWithArgs(command, options);