I am writing a function that collaborates with a JS web page. I use UIWebView to contain the webpage and then situation has become complicated when I want the web page to communicate with my app.
Calling a javascript function in UIWebView is easy by using the – stringByEvaluatingJavaScriptFromString: method
But is there any easier way to call an obj-c function in the web page, using javascript? I tried using the UIWebView delegate method, but I think it's too hacky.
Any advice?
I guess using delegate is the only (one or two) methodology you can use in iOS WebView. But there are several wrappers that may help you easy out.
EasyJSWebView - This replicates the development experience as in Android. In Android, you can simply use the addJavascriptInterface() method in WebView to bridge the Javascript to Java. EasyJSWebView provides both sync-style and async-style for getting the return value from Objective-C methods.
WebViewJavascriptBridge - The code may look a little bit like socket programming. You can pass data to and fro between the "server" in Objective-C and the "client" in Javascript.
GAJavaScript - This may provide a better DOM manipulation experience.
Take a look at all of them and choose one that fits your need.
Yes it does feel hacky and is a little laggy but you need to do it with the UIWebViewDelegate
function init()
{
$('input').on('click', function(e) { answerBoxShouldBeginEditing(e); });
}
function answerBoxShouldBeginEditing(e)
{
var object = e.toElement;
var answer = $(object).attr('name');
var request = 'engine:' + answer;
var iframe = document.createElement('IFRAME');
iframe.setAttribute('src', request);
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSString *requestString = [[request URL] absoluteString];
if ([requestString hasPrefix:#"engine:"]) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Hello" message:nil delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
return NO;
}
return YES;
}
If you are considering to upgrade to WKWebView, XWebView may be the best solution.
Related
I'm using UIWebView in a project. Sometimes it doesn't call the webViewDidFinishLoad method. Because the web page have some javascripts. The method
- (BOOL) webView: (UIWebView *) webView shouldStartLoadWithRequest: (NSURLRequest *) request navigationType: (UIWebViewNavigationType) navigationType
is getting call but webViewDidFinishLoad doesn't. I want to catch that method. Because I'm start an animation when the webview start loading. Then I want to stop this animation when it finished. It's not working with websites having javascript content. Any one have an idea please?
Thanks
webViewDidFinishLoad method gets called when the UIWebView has finished loading the url, in your case since you are calling a javascript, it doesn't load your content, it just calls a javascript function in your already loaded webview. But YES you can catch the javascript actions in the same method you stated as below
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{
NSString *url = [[request URL] absoluteString];
if(navigationType == UIWebViewNavigationTypeLinkClicked){
if([url rangeOfString:#"SOMETHING"].length > 0 ){
//if your action returns something appended in your url like the anchors work
//DO YOUR STUFFS
}
}
return TRUE;
}
apparently, the webview in ios checks specifically for "iframe" tags in the html's dom and in case it finds, it creates events based on that tag as well. therefore, a simple however a patchy solution would be adding the following code in the part of the dom that is changing (for example, in the actual template of each section):
<iframe></iframe>
did the trick for me..
I'm developing an iOS app with a UIWebView instance.
If the user touches an object in a webpage shown by the web view, how can I extract metadata regarding the object touched (such as an "id" for an HTML element) over in Objective C land?
[I'm not interested in whether the web view was touched or not, I'm only interested in what part of the page was touched and being able to act on this.]
You probably need to do this in JavaScript land. In your webview set up some javascript to monitor the click (e.g. element.onclick = function() { ... }, or use jQuery if that's easier).
Now you can call out to the native code in your app by using a made up url and then intercepting it using the webview delegate, e.g.
//in your web page, in javascript
myDiv.onclick = function() { document.location.href = 'http://madeupdomain/' + this.id};
//webview delegate in cocoa
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *URL = [request URL];
NSString *host = URL.host;
if ([host isEqualToString:#"madeupdomain"])
{
NSString *theDivID = URL.path;
//now do something based on the div id value
return NO;
}
return YES;
}
This is essentially how frameworks like PhoneGap communicate between the webview and the native code.
I am creating an iPhone/iPad app for the app store. What I'd like to do is create it using HTML5/Javascript through a UIWebView so I can later use the HTML5/Javascript code for a web version as well (this is a requirement). I would like to have an offline database (SQLite) that basically ships with the app - this would be the content for the app and the .sqlite file would exist in the /Supporting Files/ folder of my XCode Project.
My question is, how can I run queries and get data back from this database from Javascript? Is this possible?
You would have to build your own bridge or use one of the many HTML-based app frameworks available for iOS (PhoneGap, Appcelerator, etc).
If you want to go down the path of building your own bridge, you should check out UIWebView's -stringByEvaluatingJavaScriptFromString:, and the combination of UIWebView's -loadRequest and UIWebViewDelegate's webView:shouldStartLoadWithRequest:navigationType: using a custom protocol (e.g., com.mycompany.myapp.1.0://) that you check for in the delegate method.
EDIT:
Here's some sample code:
Your HTML should have something like this:
Do Query
or:
Do Query
<script>
function doQuery() {
window.location = "myapp://doQuery";
}
</script>
Then your webview delegate can capture a click there by:
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)req (UIWebViewNavigationType)navType {
if ([[req URL] scheme] == #"myapp:") {
if ([[req URL] host] == #"doQuery") {
// Do the query here.
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:#"latestResult = %#; queryReturned(latestResult);", queryResultAsJSON]];
} else if ([[req URL] host] == #"doSomethingElse") {
// Do something else.
}
return NO;
}
return YES;
}
I have a webpage loaded in a UIWebView, and a javascript function of the page needs to data from native iOs app, a NSString. How can a Js function access the data in native app?
Thanks,
lvreiny
You can execute JavaScript in your UIWebView from Obj-C. Simply call [webView stringByEvaluatingJavaScriptFromString:#"myJavaScript"];.
I could imagine a setup like this:
Webpage
<html>
<head>
<script type="text/javascript">
function callmeFromObjC(para1) {
// do something
alert(para1);
}
</script>
</head>
<body>
</body>
</html>
Objective-C
NSString *myParameter = #"myParameter";
[webView stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:#"callmeFromObjC('%#')", myParameter]];
With WebViewJavaScriptBridge you can achieve two way communication between javaScript and iOS.
Check this link below for WebViewJavaScriptBridge .
I used this bridge for one of my application for communication between iOS and JS and also vice versa.
https://github.com/marcuswestin/WebViewJavascriptBridge.
I created an iOS/JS library to help make this easier -- that is, communication in both directions using similar methods. You can check it out here: https://github.com/tcoulter/jockeyjs
Let the javascript load a custom URL, which your app intercepts. It than can parse it, prepare the data and pass it on to your webpage via stringByEvaluatingJavaScriptFromString:.
[webView loadHTMLString:#"<script src=\"filename.js\"></script>"
baseURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] resourcePath]]];
NSString *result = [webView stringByEvaluatingJavaScriptFromString:#"function(parameter)"];
Give feedback to iOS
window.location = customprefix://function/parameter=value
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
if ([[URL scheme] isEqualToString:#"customprefix"]) {
// handle function name and paramters
}
}
I also wrote a guide on how to call and handle different javascript functions from within iOS.
http://www.dplusmpage.com/2012/07/20/execute-javascript-on-ios/
Sample code for this is available here,you can check it....very usefull
http://ramkulkarni.com/blog/framework-for-interacting-with-embedded-webview-in-ios-application/
I'm hoping to be able to use PhoneGap for my app. I will have to build a custom protocol/plugin so that I can call Native methods from the Javascript. I know you can call a success function in the Javascript when the native code returns.
What I need to be able to do is call a javascript function from the native code. Basically the app will connect to an OSX companion app over local network and when the OSX app send data to the iOS app it is processed in an Objective C method, I need to be able to send the result into the PhoneGap/javascript and do something with it in the WebView.
Is this possible? I have only been able to find information about calling native from javascript not the other way around.
Thanks,
Thomas
Using the code from Answer below here:
MyPhoneGapPlugin.m
- (void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port {
NSLog(#"Connected To %#:%i.", host, port);
NSString* jsString = [NSString stringWithFormat:#"alert(connected to: %#);", host];
[theWebView stringByEvaluatingJavaScriptFromString:jsString];
[self readWithTag:2];
}
Giving me the error 'Unknown receiver 'theWebView' did you mean 'UIWebView'?
UPDATE: Found the answer: using the phonegap helper I can write something like this...
[super writeJavascript:#"alert('connected');"];
You can easily call JavaScript from native code with a UIWebView:
[webView stringByEvaluatingJavaScriptFromString:#"myJSFunction()"];
To use the result of a function somewhere as an arg to a JS function:
NSString *stringData = getStringData(); // however you get it
[webView stringByEvaluatingJavaScriptFromString:
[NSString stringWithFormat:#"myJSFunction(%#)", stringData]];
Found the PhoneGap helper to accomplish this... Write javascript to the webView using:
[super writeJavascript:#"alert('it works');"];
You should try this,
[webView stringByEvaluatingJavaScriptFromString:#"sendSelectedDate()"];
Will this work for you?
http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/DisplayWebContent/Tasks/JavaScriptFromObjC.html
Taken from this page:
You can also call JavaScript functions with arguments. Assume that you have written a JavaScript function which looks like this:
function addImage(image, width, height) { ... }
Its purpose is to add an image to a web page. It is called with three arguments: image, the URL of the image; width, the screen width of the image; and height, the screen height of the image. You can call this method one of two ways from Objective-C. The first creates the array of arguments prior to using the WebScriptObject bridge:
id win = [webView windowScriptObject];
NSArray *args = [NSArray arrayWithObjects:
#"sample_graphic.jpg",
[NSNumber numberWithInt:320],
[NSNumber numberWithInt:240],
nil];
[win callWebScriptMethod:#"addImage"
withArguments:args];