Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HTTP Request through JavaScriptCore in iOS7

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)?

like image 651
Kostis Avatar asked Nov 18 '13 16:11

Kostis


2 Answers

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.

like image 145
Manuel Spuhler Avatar answered Oct 21 '22 21:10

Manuel Spuhler


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.

like image 45
Ben Clayton Avatar answered Oct 21 '22 20:10

Ben Clayton