HTTP Request through JavaScriptCore in iOS7
Asked Answered
K

3

8

I am trying to use one of iOS7 new features, the JavaScriptCore Framework. I can successfully output a helloWorld string from Javascript, but what I'm interested in, is doing HTTP POSTs in Javascript and then pass the response to Objective-C. Unfortunately, when I'm creating an XMLHttpRequest object in Javascript, I get EXC_BAD_ACCESS (code=1, address=....).

Here is the Javascript code (hello.js):

var sendSamplePost = function () {
    // when the following line is commented, everything works,
    // if not, I get EXC_BAD_ACCESS (code=1, address=....)
    var xmlHttp = new XMLHttpRequest();
};

var sayHello = function (name) {
    return "Hello " + name + " from Javascript";
};

Here is the Objective-C code inside my ViewController:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    JSContext *context = [[JSContext alloc] initWithVirtualMachine:[[JSVirtualMachine alloc] init]];

    NSString *scriptPath = [[NSBundle mainBundle] pathForResource:@"hello" ofType:@"js"];
    NSLog(@"scriptPath: %@", scriptPath);
    NSString *script = [NSString stringWithContentsOfFile:scriptPath encoding:NSUTF8StringEncoding error:nil];
    NSLog(@"script: %@", script);

    [context evaluateScript:script];

    JSValue *sayHelloFunction = context[@"sayHello"];
    JSValue *returnedValue = [sayHelloFunction callWithArguments:@[@"iOS"]];

    // this works!
    self.label.text = [returnedValue toString];


    JSValue *sendSamplePostFunction = context[@"sendSamplePost"];

    // this doesn't work :(
    [sendSamplePostFunction callWithArguments:@[]];
}

Could it be that HTTP Requests functionality is not provided in JavaScriptCore Framework? If yes, could I overcome this by using UIWebView's -stringByEvaluatingJavaScriptFromString:? What if I compiled and included in my project another Javascript Engine (e.g. V8)?

Konstance answered 18/11, 2013 at 16:42 Comment(0)
R
5

My guess would be that HTTP Requests are not part of JavaScript Core, as it's really part of the browser, not the JavaScript Language.
I would assume that JavaScript core only includes what's in the ECMAScript definition.

If you want AJAX, then the WebView is the way to go.

Rothwell answered 18/11, 2013 at 17:6 Comment(3)
Thanks Ben for the help! I appreciate it. I was hoping that this new iOS7 feature would be trully powerful, but apparently, it isn't :( XMLHttpRequest seems to exist in some draft version. And if I'm not sure that UIWebView is the way to go, since I'll have to resort to nasty hacks and have the UIWebView overhead, when I only need to execute Javascript. But anyway, since I don't see any other solution to this... Thanks Ben :)Konstance
No probs. I recommend just biting the bullet and using AFNetworking for your POST request instead.Rothwell
isn't fetch() a thing yet?Ovida
B
23

XMLHttpRequest is, as stated before, not part of JavaScript, but you still can wrap the iOS URLRequest so it's available in your JS.

in JSUtils.h

   @protocol UtilsExport;

   @interface JSUtils : NSObject <UtilsExport>
   @end

   @protocol UtilsExport <JSExport>
   - (void)get:(NSString *)url then:(JSValue *)jsCallback;
   @end

in JSUtils.m

#import "JSUtils.h"

- (void)get:(NSString *)url then:(JSValue *)callback {
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
                                                           cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
                                                       timeoutInterval:10];
    [request setHTTPMethod:@"GET"];
    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
        if ([data length] > 0 && error == nil) {
            [callback callWithArguments:@[[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding], @YES]];
        } 
    }];
}

Next, bind the instance to the JSContext somewhere in your code

JSContext *context = [[JSContext alloc] init];
context[@"utils"] = [[JSUtils alloc] init];

from your JS file, you can now call

utils.getThen('http://localhost/api/dashboard', function(resultString){
  console.log(resultString)
}

You could also use a block and bind it straight to the JSContext to get the same result.

Birthright answered 30/1, 2014 at 7:57 Comment(3)
How to I get data data from js callback to my objective cUnfix
on swift context["utils"] = JSUtils() Type 'JSContext' has no subscript members. how it worked in swift?Ferocious
swift context.setObject(JSUtils.self, forKeyedSubscript: "utils" as NSString)Ferocious
R
5

My guess would be that HTTP Requests are not part of JavaScript Core, as it's really part of the browser, not the JavaScript Language.
I would assume that JavaScript core only includes what's in the ECMAScript definition.

If you want AJAX, then the WebView is the way to go.

Rothwell answered 18/11, 2013 at 17:6 Comment(3)
Thanks Ben for the help! I appreciate it. I was hoping that this new iOS7 feature would be trully powerful, but apparently, it isn't :( XMLHttpRequest seems to exist in some draft version. And if I'm not sure that UIWebView is the way to go, since I'll have to resort to nasty hacks and have the UIWebView overhead, when I only need to execute Javascript. But anyway, since I don't see any other solution to this... Thanks Ben :)Konstance
No probs. I recommend just biting the bullet and using AFNetworking for your POST request instead.Rothwell
isn't fetch() a thing yet?Ovida
M
0
JSContext *context = [[JSContext alloc] init];

context[@"request"] = ^(NSString *url) {
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]
                                                       cachePolicy:NSURLRequestReloadIgnoringCacheData
                                                   timeoutInterval:10];

    NSURLResponse *response = nil;

    [request setHTTPMethod:@"GET"];
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
    NSString *body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
    return body;
};

In JS:

var body = request(url);
Millian answered 16/8, 2015 at 18:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.