-
Notifications
You must be signed in to change notification settings - Fork 111
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
Does this NodeJS Framework work with iOS Native apps using Swift ? #20
Comments
Hi @umangkathuria , It's been used with Swift before: The start API has been introduced by the community in this PR: JaneaSystems/nodejs-mobile#18 Unfortunately I'm not familiar enough with Swift to help you get started. Hopefully someone from the community give some input here. |
Here is a rough guideline to get a prototype going. You'll copy-paste some obj-c code from the sample, then create a bridging header, then start Node and use it from your Swift code. These were copy-pasted: //
// NodeRunner.h
//
#ifndef NodeRunner_h
#define NodeRunner_h
#import <Foundation/Foundation.h>
@interface NodeRunner : NSObject {}
+ (void) startEngineWithArguments:(NSArray*)arguments;
@end
#endif //
// NodeRunner.mm
//
#include "NodeRunner.h"
#include <NodeMobile/NodeMobile.h>
#include <string>
@implementation NodeRunner
//node's libUV requires all arguments being on contiguous memory.
+ (void) startEngineWithArguments:(NSArray*)arguments
{
int c_arguments_size=0;
//Compute byte size need for all arguments in contiguous memory.
for (id argElement in arguments)
{
c_arguments_size+=strlen([argElement UTF8String]);
c_arguments_size++; // for '\0'
}
//Stores arguments in contiguous memory.
char* args_buffer=(char*)calloc(c_arguments_size, sizeof(char));
//argv to pass into node.
char* argv[[arguments count]];
//To iterate through the expected start position of each argument in args_buffer.
char* current_args_position=args_buffer;
//Argc
int argument_count=0;
//Populate the args_buffer and argv.
for (id argElement in arguments)
{
const char* current_argument=[argElement UTF8String];
//Copy current argument to its expected position in args_buffer
strncpy(current_args_position, current_argument, strlen(current_argument));
//Save current argument start position in argv and increment argc.
argv[argument_count]=current_args_position;
argument_count++;
//Increment to the next argument's expected position.
current_args_position+=strlen(current_args_position)+1;
}
//Start node, with argc and argv.
node_start(argument_count,argv);
free(args_buffer);
}
@end
//
// Use this file to import your target's public headers that you would like to expose to Swift.
//
#import "NodeRunner.h" Now in AppDelegate: //
// AppDelegate.swift
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// ... your other app code
DispatchQueue.global(qos: .background).async {
NodeRunner.startEngine(withArguments: ["node", "-e", "require('http').createServer((req, res) => res.end('alive!')).listen(3000);"])
}
return true
}
// ...
} It would be better to rewrite the above to use NSThread, where you can give it the required 2MB stack size. |
@tomholub I'll give this a try! Thanks !! |
@tomholub Any help is really appreciated!! Thanks!! |
You load the source file and pass it as argument during start to run your api. let jsFile = Bundle.main.path(forResource: "node-api.js", ofType: nil)!
let jsFileSrc = try? String(contentsOfFile: jsFile)
NodeRunner.startEngine(withArguments: ["node", "-e", jsFileSrc!]) Then you make http requests to the node with URLSession, Alamofire or whatever, at the port that you started the node api at. Same thing as https://code.janeasystems.com/nodejs-mobile/getting-started-ios at the bottom, just in swift. |
Yes, I was able to do this. But the challenge that I see with this method is that I cannot explicitly call a method. Let's say I have 10 utility functions which take an argument and return me a value. I have implemented a solution by using events in the javascript side. Where context is a JSContext Object and "getData" is the method in JavaScript that I am trying to call. Do we have anything similar to this in the library? Thank you for all your time and effort!! Appreciate it! |
You'd probably have to implement that using native node handlers, likely involving a bunch of c++, kind of like what react native is doing. This is not my domain. |
In case anyone needs it with thread to increase stackSize like I did: @objc
func startNode() {
let jsFile = Bundle.main.path(forResource: "index.js", ofType: nil)!
NodeRunner.startEngine(withArguments: ["node", jsFile])
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let nodejsThread = Thread(target:self, selector:#selector(startNode), object:nil)
nodejsThread.stackSize = 2*1024*1024;
nodejsThread.start()
return true
} |
Hi guys, I ran into an issue that the swift project can only access a single .js file only, I could require() node functions like "http" and "querystring", but could not require any modules like the 'left-pad' from the sample, or a .js file under the same directory, it always return errors like below: internal/modules/cjs/loader.js:834 Error: Cannot find module 'left-pad'
I've already run the "npm install" command under the "nodejs-project" and make sure "node_modules" folder have been created. Any ideas? |
@wltam-myndar About left-pad, you can refer |
Is there a Sample that I could refer to incorporate this framework in iOS App using Swift.
I am not familiar with ObjectiveC or C++. Could you please help me in getting started with Swift based native app ?
Thanks!
The text was updated successfully, but these errors were encountered: