Can I run JavaScript inside Swift code? - javascript

I need to include JavaScript code in Swift code to be able to call a signalR chat, is that possible? If not, can I convert it?
sendmessage is a button.
$(function () {
// Declare a proxy to reference the hub.
var chat = $.connection.chatHub;
// Create a function that the hub can call to broadcast messages.
chat.client.broadcastMessage = function (name, message) {
// some code
};
// Start the connection.
$.connection.hub.start().done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.send('name', 'message');
});
});
});
and the signalr code is:
public void Send(string name, string message)
{
// Call the broadcastMessage method to update clients.
Clients.All.broadcastMessage(name, message);
}
Update #1:
changed question a little bit so it is not confusing per #MartinR

Last tested with Swift 5.1
Here is an example you can run in Playground to get you started:
import JavaScriptCore
let jsSource = "var testFunct = function(message) { return \"Test Message: \" + message;}"
var context = JSContext()
context?.evaluateScript(jsSource)
let testFunction = context?.objectForKeyedSubscript("testFunct")
let result = testFunction?.call(withArguments: ["the message"])
result would be Test Message: the message.
You also can run JavaScript code within a WKWebView calling evaluate​Java​Script(_:​completion​Handler:​).
You can also run JavaScript within a UIWebView by calling string​By​Evaluating​Java​Script(from:​), but note that that method has been deprecated and is marked as iOS 2.0–12.0.

Using JavaScriptCore framework include JavaScript code in Swift code.
The class that you’ll be dealing the most with, is JSContext. This class is the actual environment (context) that executes your JavaScript code.
All values in JSContext, are JSValue objects, as the JSValue class represents the datatype of any JavaScript value. That means that if you access a JavaScript variable and a JavaScript function from Swift, both are considered to be JSValue objects.
I strongly advise you to read the official documentation regarding the JavaScriptCore framework. 
import JavaScriptCore
var jsContext = JSContext()
// Specify the path to the jssource.js file.
if let jsSourcePath = Bundle.main.path(forResource: "jssource", ofType: "js") {
do {
// Load its contents to a String variable.
let jsSourceContents = try String(contentsOfFile: jsSourcePath)
// Add the Javascript code that currently exists in the jsSourceContents to the Javascript Runtime through the jsContext object.
self.jsContext.evaluateScript(jsSourceContents)
}
catch {
print(error.localizedDescription)
}
}
more details refer this tutorial

Related

get a variable value from a method at runtime with frida

I'm completely beginner to frida.
I've this final method which belongs to class say X.
I want to extract the value of token variable -> result.getToken() when i hook frida to the android app which contains that class at runtime.
can anyone complete this code with javascript API of frida to get the value of token variable ?
Java.perform(function () {
Java.choose("com.xx.xx", {
onMatch: function (inst) {
//.................................
}
});
console.log("Done");
});
then i'll use --> frida -U -f "xxx.apk" -l test.js
thank you so much for help !!
Java.choose is in most cases the wrong approach because that only lists the existing instances of a class, so you can only hook a method if there is already an instance loaded into memory.
The common way is to hook the method itself so that all existing and newly created instances use your hook.
var classInstanceIdResult = Java.use('com.google.firebase.iid.InstanceIdResult');
var getTokenMethod = classInstanceIdResult.getToken.overload();
// replace the getToken() method with out own implementation
getTokenMethod.implementation = function () {
// call the orignal method
var ret = getTokenMethod.call(this);
// do something with ret
console.log("Token: " + ret);
return ret;
}
BTW: The code for hooking a Java method can simply be generated by using Jadx-Gui. Just decompile the APK, select the method and let Jadx generate the Frida code snipped necessary to hook the method (see context menu of the method).

Kotlin Call Javascript function in Android without webView

Is there any way we can call JS function from Kotlin without having WebView in Android?
Let's say as mentioned below I have one JS function helloJS() in test.js file,
test.js:-
function helloJS(){
return "Hello from JS"
}
And now I want to call this function from Kotlin file like
TestClass.kt:-
class TestHello{
fun getHelloFromJS(){
val name = test.helloJS()
}
}
Till now I am using Webview and loading JS file into that and getting result as call back
But, I read that Kotlin is interoperable with JS like Java
So I am curious to know if there is any way we can use that on Android without having webView
This is not possible straight forward but I found one library Execute JavaScript in Android without WebView for achieve this.
Read that blog carefully and follow below step.
Keep your JavaScript file (test.js) in assets folder in android project.
I have converted that code into Kotlin.
CallJavaScript.jks
import org.mozilla.javascript.Context
import org.mozilla.javascript.Function
import java.io.InputStreamReader
object CallJavaScript {
fun callFunction(mContext: android.content.Context): Any? {
var jsResult: Any? = null
val params = arrayOf<Any>("")
// Every Rhino VM begins with the enter()
// This Context is not Android's Context
val rhino = Context.enter()
// Turn off optimization to make Rhino Android compatible
rhino.optimizationLevel = -1
try {
val scope = rhino.initStandardObjects()
// Note the forth argument is 1, which means the JavaScript source has
// been compressed to only one line using something like YUI
val assetManager = mContext.assets
try {
val input = assetManager.open("test.js")
val targetReader = InputStreamReader(input)
rhino.evaluateReader(scope, targetReader, "JavaScript", 1, null)
} catch (e: Exception) {
e.printStackTrace()
}
// Get the functionName defined in JavaScriptCode
val obj = scope.get("helloJS", scope)
if (obj is Function) {
// Call the function with params
jsResult = obj.call(rhino, scope, scope, params)
// Parse the jsResult object to a String
val result = Context.toString(jsResult)
}
} finally {
Context.exit()
}
return jsResult
}
}
Add this line to build.gradle:
implementation 'org.mozilla:rhino:1.7R4'
In your assets folder, create a file called test.js:
function helloJS()
{
return "Hello from JS";
}
Now simply call above function from Activity.
Log.e("JS : ", CallJavaScript.callFunction(this).toString());
Output :
E/JS :: Hello from JS
It's not possible. You must not confuse the language with the platform.
Kotlin is interoperable with JS like Java
means Kotlin/JS can use and be used in a Javascript platform (Node.js or browsers). The Kotlin code compiled (transpiled) into js is able to call other js files. And external Js code can call the js code build from Kotlin. This is the interoperability with JS.
There is no interoperability between Kotlin/JS and Kotlin/JVM.
Kt looks like JS, but it is not. It will be compiled for Android runtime, not for the java script engine.
JS code require a JS runtime, but it is not in Android Runtime.
i.e. you cannot run JS directly in Java / Kt code for Android.
Am not a pro in Kotlin but Java is a pie for me. Anything you can implement in Java can be implemented in Kotlin and To execute Javascript code, I use rhino which does the job pretty easier than using the webview
Implement it:
try {
Scriptable scope = rhino.initStandardObjects();
rhino.evaluateString(scope, javaScriptCode, "JavaScript", 1, null);
Object obj = scope.get(functionNameInJavaScriptCode, scope);
if (obj instanceof Function) {
Function jsFunction = (Function) obj;
// Call the function with params
Object jsResult = jsFunction.call(rhino, scope, scope, params);
// Parse the jsResult object to a String
String result = Context.toString(jsResult);
}
}finally {
Context.exit();
}

How can I invoke a class method in Swift if I only have the string?

I am writing a cordova plugin for HealthKit and my task is to make sure that we can dynamically read more or less data from HK. Im doing the native part in swift. But I mostly write JavaScript so I am a bit lost in with the Swift part.
I want to be able to dynamically invoke methods having only a string.
let store = HKHealthStore()
do {
let bloodType: HKBloodTypeObject = try store.bloodType()
...
That is an example to read blood type. I am not a Swift developer, but is there any way I can do this dynamically, like I would do in javascript:
... // assuming this function receives a string as paramater
let param[0] = try store[param[0]]() // <-- how to do this in Swift?
then i can talk to a server and get a list of characteristics and load them dynamically from healthkit without having to update my code and hardcode for each possible characteristic.
Create a mapping from your parameter strings to an API enumeration.
enum API: String {
case function1 = "function1"
case function2 = "functionTwo"
case function3 = "threethreethree"
}
Create a relay function that maps the API enumeration to the Swift function.
func callTheCorrectFunction(_ api: API) {
switch api {
case .function1: updateBlood()
case .function2: spinAround()
case .function3: jump()
}
}
Construct your function call using enum's rawValue initializer.
let param = fromSomeJsonStrings[0]
let api = API(rawValue: param)
callTheCorrectFunction(api)
Alternatively, you could use a dictionary mapping from [String: Function] in much the same way.
typealias Function = () -> ()
let dict = {
"function1": updateBlood,
"function2": spinAround,
}
dict[param[0]]()

Running IAsyncOperation from a Windows Runtime Component using JavaScript

I have a solution that has both a Windows Runtime Component (C#) and a Universal App (JS).
One of my classes in the WRC has the following static function:
public static IAsyncOperation<Project> Import()
{
return System.Threading.Tasks.Task.Run<Project>(async () =>
{
try
{
FileOpenPicker picker = new FileOpenPicker();
picker.ViewMode = PickerViewMode.List;
picker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
picker.FileTypeFilter.Add(".xml");
StorageFile source = await picker.PickSingleFileAsync();
if (source != null)
{
StorageFile destination = await ApplicationData.Current.RoamingFolder.CreateFileAsync(source.Name, CreationCollisionOption.ReplaceExisting);
await source.MoveAndReplaceAsync(destination);
return await Project.Open(source.DisplayName);
}
else
{
return null;
}
}
catch (Exception)
{
return null;
}
}).AsAsyncOperation<Project>();
}
I am trying to call this function from JS using:
SignalOne.Data.Project.import().done(function () {
new Windows.UI.Popups.MessageBox("Done").showAsync();
}
However, while the "Done" message appears, the file open dialog does not. If I put a message box as the first line inside the try of the C#, it doesn't display, either.
I know I have an upper-case Import in C# and a lower-case import in JS, but that is how it comes up with Intellisense, and if I change it to upper-case in JS it crashes.
I'm sure I'm missing something small/stupid, but I can't put my finger on it.
Thanks.
As you known, if we want to use the async method in Windows Runtime Components, we should be able to use the WindowsRuntimeSystemExtensions.AsAsyncAction or AsAsyncOperation extension method to wrap the task in the appropriate interface.
You can use .NET Framework tasks (the Task class and generic Task class) to implement your asynchronous method. You must return a task that represents an ongoing operation, such as a task that is returned from an asynchronous method written in C# or Visual Basic, or a task that is returned from the Task.Run method.
For more info, see Asynchronous operations.
Also the FileOpenPicker.PickSingleFileAsync method should be run in UI thread.
In this example, the event is being fired on the UI thread. If you fire the event from a background thread, for example in an async call, you will need to do some extra work in order for JavaScript to handle the event. For more information, see Raising Events in Windows Runtime Components.
So we should be able to use CoreWindow.GetForCurrentThread method get the UI thread before the async Task is run that the async Task is not run on the UI thread.
For example:
var window = Windows.UI.Core.CoreWindow.GetForCurrentThread();
var m_dispatcher = window.Dispatcher;
Then we should be able to use the FileOpenPicker.PickSingleFileAsync method in the CoreDispatcher.RunAsync method.
For example:
await m_dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(async () =>
{
var source = await picker.PickSingleFileAsync();
}));

Notifying javascript from a node.js native addon (c++)

I do not have much knowledge about javascript. I have written in C++ a shared library that does certain things in a daemon thread. I needed this to be invoked from javascript. By using SWIG I've successfully able to generate a wrapper and compile my code along with it into .node module using node-gyp (wrote binding.gyp for it too). Now i can drop to node prompt and do something like:
> var a = require("./module_name")
> a.SomeCppFunction("SomeString")
and wonderfully invoke the cpp functions, start a detached thread there and return the control back to javascript. However I want to notify the javascript from the detached cpp thread about stuffs. I tried registering javascript functions by collecting function() {} signature types in void(*fp)() etc., to call them back later from c++, but that didn't work. Is there anyway to be able to achieve this ie., register javascript functions (or something else) as callback in the cpp code ?
You can use a combination of SWIG and Napi. An existing repo which does this is available here, with a blog here. But I'll sum up the process here.
Create your class to use in SWIG, which has a thread running in the threadMain method :
#include <Thread.H>
class Test : public ThreadedMethod {
void *threadMain(void);
public:
Test();
void setFnPointer(const char* s);
};
Now in the Napi code, you will generate your thread safe function like so :
Napi::ThreadSafeFunction tsfn; ///< The node api's threadsafe function
Napi::Value Start( const Napi::CallbackInfo& info ){
Napi::Env env = info.Env();
// Create a ThreadSafeFunction
tsfn = Napi::ThreadSafeFunction::New(env,
info[0].As<Napi::Function>(), // JavaScript function to call
"Resource Name", 0,1);
// return the tsfn as a pointer in a string
char addr[24];
sprintf(addr,"%p",&tsfn);
return Napi::String::New(env, addr);
}
// some small code to call NODE_API_MODULE here, check the file NapiCode.C in the repo
You compile the SWIG code to one module and the Napi code down to a different module and you pass the thread safe funciton pointer from one to the other like so :
var libNapiNodejs = require('../swig/.libs/libNapiNodejs');
let fp = libNapiNodejs.start(function () {
console.log("JavaScript callback called with arguments", Array.from(arguments));
}, 5);
// SWIG get our C++ and thread running
var libSwigCNodejs = require('../swig/.libs/libSwigCNodejs');
let test = new libSwigCNodejs.Test;
test.setFnPointer(fp); // tell swig the callback function pointer to execute
test.run(); // run the C++ thread in the SWIG module
You will see that the C++ thread calls the javascript function. This is what the C++ thread looks like in SWIG :
Napi::ThreadSafeFunction *tsfn; ///< The node api's threadsafe function
void *Test::threadMain(void){
printf("C++ Thread enter %s\n",__func__);
auto callback = []( Napi::Env env, Napi::Function jsCallback, int* value ) {
jsCallback.Call( {Napi::Number::New( env, *value )} );
};
for (int i=0; i<10; i++){
sleep(1);
if (*tsfn) {
printf("calling tsfn->BlockingCall\n");
napi_status status = tsfn->BlockingCall( &i, callback );
if ( status != napi_ok ) // Handle error
break;
}
}
tsfn->Release();
printf("C++ Thread exit %s\n",__func__);
return NULL;
}

Categories

Resources