I am trying to send method invocations from JavaScript to Objective-C and vice versa. Everything works fine for window.location triggered urls, which are catched by shouldStartLoadWithRequest. Now if I try to use an AJAX call instead, shouldStartLoadWithRequest is not called. Is there a way to do this? Mainly I do not want to be restricted to the max URL size on data that can be passed from JavaScript to Objective-C.
My UIWebViewDelegate implements:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
NSString *url = [[request URL] absoluteString];
NSRange urlrange = [url rangeOfString:@"myScheme://"];
if(urlrange.length > 0){
NSLog(@"this is an objective-c call, do not load link: %@", [url substringWithRange:NSMakeRange(urlrange.location, [url length])] );
return NO;
} else {
NSLog(@"not an objective-c call, load link: ", url );
return YES;
}
}
My JavaScript calls:
// works
window.location.href = "myScheme://readyHref";
// fails
var xmlHttpReq = false;
if (window.XMLHttpRequest) {
xmlHttpReq = new XMLHttpRequest();
} else if (window.ActiveXObject) {
xmlHttpReq = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlHttpReq.open('GET', "myScheme://readyAJAX", false);
xmlHttpReq.send();
If you'd like to have a cleaner way of transferring data from JavaScript to Objective-C you could follow these steps:
var myTempData = ...
document.location = 'myapp://fire-some-event'
[myWebView stringByEvaluatingJavaScriptFromString:@"myTempData"]
.Although I could not find the answer why AJAX requests are not intercepted by shouldStartLoadWithRequest I found two workarounds. I assume that JavaScript Requests are not being intercepted but only HTML-associated / -originated requests are. If any one could verify or correct this, I'd be happy.
The two workarounds are simple. On the one hand it seems that the restriction of 256 characters in the URL does not affect MobileSafari or at least the url in that state. I read that Safari allows 80'000 charcters. However I did not feel well with that. So the workaround #2 is to use a html form that uses the POST method and set the action to your scheme. The data can be stored in the form as the value of an input field or the like. After submitting the form with JavaScript shouldStartLoadWithRequest is triggered and the data can be retrieved from HTTPBody.
I'm not sure if this will work for you, but if you're trying to use the shouldStartLoadWithRequest in order to access native phone functions from javascript you could use PhoneGap. It is a handy and open-source objective-c framework that is able to bridge javascript and objective-c.
I needed a way to asynchronously cause the phone to vibrate from javascript and I looked at the PhoneGap source to see how they do it. After some testing I found that $.ajax wouldn't be intercepted by shouldStartLoadWithRequest and also that it was very particular about when it would intercept http requests. You could get everything working nicely though by calling document.location instead of $.ajax and by using another protocol such as gap:// instead of http://.
So the javascript code looks like:document.location = "gap://vibrate";
And the objective-c code:
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType { NSURL *url = request.URL; NSString *urlString = url.relativeString; if ([urlString isEqualToString:@"gap://vibrate"]) { AudioServicesPlaySystemSound(kSystemSoundID_Vibrate); }; return YES; }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With