Execute javascript without webview in Android - javascript

I'm trying to execute a JS fonction in my Android app.
The function is in a .js file on a website.
I'm not using webview, I want to execute the JS function because it sends the request i want.
In the Console in my browser i just have to do question.vote(0);, how can I do it in my app ?

UPDATE 2018: AndroidJSCore has been superseded by LiquidCore, which is based on V8. Not only does it include the V8 engine, but all of Node.js is available as well.
You can execute JavaScript without a WebView. You can use AndroidJSCore. Here is a quick example how you might do it:
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("http://your_website_here/file.js");
HttpResponse response = client.execute(request);
String js = EntityUtils.toString(response.getEntity());
JSContext context = new JSContext();
context.evaluateScript(js);
context.evaluateScript("question.vote(0);");
However, this most likely won't work outside of a WebView, because I presume you are not only relying on JavaScript, but AJAX, which is not part of pure JavaScript. It requires a browser implementation.
Is there a reason you don't use a hidden WebView and simply inject your code?
// Create a WebView and load a page that includes your JS file
webView.evaluateJavascript("question.vote(0);", null);

For the future reference, there is a library by square for this purpose.
https://github.com/square/duktape-android
This library is a wrapper for Duktape, embeddable JavaScript engine.
You can run javascript without toying with WebView.
Duktape is Ecmascript E5/E5.1 compliant, so basic stuff can be done with this.

Related

Swift Headless WKWebView; running XMLHttpRequest

How can I run an XMLHttpRequest from within a WKWebView that I have created in Swift?
Currently, I use the WKWebView to access a page on a server I own. This page contains my Javascript. However, when I attempt to make an XMLHttpRequest by using WKWebView.evaluateJavaScript (i.e. call a javascript function that makes an XMLHttpRequest) the Javascript code executes successfully but the Safari debugger shows "Failed to load resource".
However, if I 'manually' make an XMLHttpRequest by using the console in the Safari debugger and then call my request function from my app, it works fine - but only once!
I'm at a bit of a loss as to why this is...
As mentioned in the comments, a better solution than bundling the Javascript with my swift library is to host the scripts on a page that is accessed via the WKWebView. Previous information maintained below;
Some background: I have been tasked with producing a Swift library that wraps our current Javascript API. I had hoped to use a WKWebView to simply load and execute our existing javascript code, however any XMLHttpRequests that I run simply return error (fire the onerror callback) instantly. The error object returned to onerror is {"position":0,"totalSize":0}
This thread seems to suggest that my WKWebView needs a 'parent' in order to execute javascript correctly. I have attempted to reproduce their code in Swift, but to no effect (see below)
let webConf = WKWebViewConfiguration()
WKWebView webView = WKWebView(frame: CGRectZero, configuration: webConf)
UIApplication.sharedApplication().keyWindow?.addSubview(webView)
In order to get to this point, I have had to set 'App Transport Security Settings -> Allow Arbitrary Loads' to 'YES' in my info.plist file, in order to enable non-https requests.

How can you access javascript variables from a C#.Net Webbrowser object?

I want to create a Webbrowser .Net object from my C#.Net Winform application and then be able to access javascript variables.
Basically I want to take some action in my main Winform application depending on some user interactions that happen that set javascript variables.
Any advice on how I can make calls to the Webbrowser object to do this?
Note I did look at the Document property that lets you get at the DOM but don't understand how/if that can be used to get at javascript variables.
Dan
In the WinForms browser, use the ObjectForScripting property to handle two-way communications between your WinForms application and your WebBrowser's Document.
You can invoke javascript members from C# through the Document object:
// C# code
webBrowser1.Document.InvokeScript("test",
new String[] { "called from client code" });
Assigning ObjectForScripting as
// C# code
webBrowser1.ObjectForScripting = obj;
appears to allow the hosted javascript to call members of obj, e.g.
// javascript code
window.external.SomeMethod('called from script code');
// executes obj.SomeMethod(string) in C#
Disclaimer: I only have experience with the WPF web browser, so I haven't verified the above myself.
Make use of CeSharp, a Chromium Embedded Framework that allows much more control over your webbrowser component.
To get started
Fire up a VS project
Open nuget console and execute: Install-Package CefSharp.WinForms if you are doing Winforms C# App.
Restart your Visual studio and re-load project.
Example of CefSharp code to get started.
Add a toolStripContainer to your form from the toolbox then use the following example code to load cefsharp browser component.
public Form1()
{
InitializeComponent();
var browser = new ChromiumWebBrowser("http://localhost:1071/");
browser.Dock = DockStyle.Fill;
toolStripContainer1.ContentPanel.Controls.Add(browser);
}
This should get you started, in order to talk to JS from C# you will need to make use of EvaluateScript interface.
Take a look at the following resource.
https://github.com/cefsharp/CefSharp/issues/368

Transferring a javascript variable to to Objective C (IOS)

I am working on creating an app and am a relatively new Objective C programmer. On a page, "test.php", I have a javascript variable. Here is a simplified version.
<script>
var idx = 45;
document.write(idx);
</script>
I would like to be able to view the value of the variable "idx" in my IOS app, which I have created using Xcode. What would be the optimal way to connect to the page, test.php, and transfer my Javascript variable to Objective C so I could use it as part of my IOS App?
Any help would be greatly appreciated. Thank you.
You will need to communicate between the webview and the native code using a combination of two pieces. First, you will need to "trigger" the webview into returning some value by calling stringByEvaluatingJavaScriptFromString: on the webview. When the webview tries to navigate because of the javascript call, you can intercept it on the native side with the WebView's shouldStartLoadWithRequest: method.
For details, see the specifics here Invoke method in objective c code from HTML code using UIWebView
That is only if you need some activity in the webview to trigger the fetch (or notify the native code that the value has been set). If the value is always available via JS, you can simply use stringByEvaluatingJavaScriptFromString: as follows:
NSString *returnvalue = [self.webviewForHtml stringByEvaluatingJavaScriptFromString:#"var idx = "return_value";return idx;"];

UIWebView Javascript Window to Window Communication

I'm working on an iOS app in which I'm trying to use UIWebView to display a variety of websites. Recently I finished logic to inject Javascript into the UIWebView to catch instances of window.open, window.close, and window.opener.focus. In short, to do so, I inject JS that overrides the aforementioned JS functions, which includes creating an iframe with a specific scheme that I can catch in the app's webView:shouldStartLoadWithRequest:navigationType method. This is all working OK for now, including window.open creating a new UIWebView rather than loading in the same window.
Now though, the issue has come up where there's no feasible solution for JS communication between windows. If the child window tries to call to window.opener or window.parent, it's always returning a null value, and thus, it can't communicate back to the original web view.
In an effort to see what iOS browsers are able to effectively perform window-to-window communication, I found that of the 9 browsers I have on my iPhone, only Safari was able to effectively perform this communication successfully. This leads me to believe that there's something with UIWebView that prevents full JS window-to-window communication from being possible.
Has anyone had any success with getting UIWebView to fully integrate with all JS logic, namely window-to-window communication? Or have proof that JS window-to-window communication isn't possible? Any direction or advice is appreciated. Thanks!
Found possible solution.
Add JavaScriptCore.framework to Linked Frameworks and in your webViewDidFinishLoad:
JSContext *parentCtx = [self.parentWebView valueForKeyPath:#"documentView.webView.mainFrame.javaScriptContext"];
JSContext *childCtx = [self.childWebView valueForKeyPath:#"documentView.webView.mainFrame.javaScriptContext"];
childCtx[#"window"][#"opener"] = parentCtx[#"window"];
Now when you call window.opener.test() from childWebView, it will fire test function in parentWebView!
I'm not sure about private API.
Works on iOS 7 only
Swift version
import JavaScriptCore
let jsContextA = webA.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext")
let jsContextB = webB.valueForKeyPath("documentView.webView.mainFrame.javaScriptContext")
//Original objc code : jsContextB[#"window"][#"opener"] = jsContextA[#"window"];
jsContextB!.setObject("opener", forKeyedSubscript: "window")
jsContextB!.setObject(jsContextA!.objectForKeyedSubscript("window"), forKeyedSubscript: "opener")

How to call user32.dll methods from javascript

I have a javascript running on a browser. Is it possible to call a function/method in user32.dll.
This is possible from C# by using pInvoke calls. How do I do the same in JavaScript?
Thanks,
Datte
Because of the JavaScript sandbox, you can't do it without a middle layer requiring elevated security permissions, such as a Netscape-style browser plug-in (widely supported), ActiveX control (pretty much IE-only), or .Net control (I assume that's possible; again probably IE-only). In each case, the JavaScript would talk to the control, which would in turn make the USER32 call for you.
None of that will work without the user having granted your application elevated permissions, but I'm guessing as you're requiring Windows, this is for some kind of intranet application where that may be possible.
You definitely need a plug-in, extension or ActiveX of your own installed on the client.
In the case of a firefox extension, you can use jsctypes to wrap the calls easily.
If you use the Jetpack API included with Firefox 4, it will be all JavaScript and won't even require a browser restart.
Here's an exemple from mozilla.org for a basic Hello World :
/* Load JS Ctypes Javascript module */
require("chrome").Cu.import("resource://gre/modules/ctypes.jsm");
/* Load windows api dll */
var lib = ctypes.open("user32.dll");
/* Declare the signature of the function we are going to call */
var msgBox = lib.declare("MessageBoxW",
ctypes.stdcall_abi,
ctypes.int32_t,
ctypes.int32_t,
ctypes.ustring,
ctypes.ustring,
ctypes.int32_t);
var MB_OK = 3;
/* Do it! */
var ret = msgBox(0, "Hello world", "title", MB_OK);
/* Display the returned value */
alert("MessageBox result : "+ret);
lib.close();
On the client - it is not possible for security reasons (imagine every site could run system commands on your computer... end of the world - maybe possible with an ActiveX, but that's IE only, but then again, the DLL is windows only).
If you want to run it on the server you'll need to go trough AJAX and C#.
Run dll methods on the client machine using javascript from a web page? That's what is gonna trigger apocalypse.
If you build your own web browser in C#, you can intercept JavaScript calls and translate them to whatever you want in your browser. Though that won't work if you want it to be available to other browsers.
Write a com object that wraps your call to user32. Invoke it in IE/javascript.
Your DynamicWrapperX object would work for this (it would BE that com object, allowing you to just call your dlls as you wish).

Categories

Resources