Touches in a UIWebView - javascript

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.

Related

pass alert from UIWebView to iOS app

I have create an app, which works fine. The only thing i need is to pass the alerts from uiwebview to my iOS app.
i have this alert on my uiwebview
<div id="alerts" class="alerts">
<p class="alert-red">ok. come back again tomorrow, not now.</p>
i want this alert to transfer into my app and make it into an uialertview
UIAlertView *errr = [[UIAlertView alloc]initWithTitle:#"nil" message:#"ok. come back again tomorrow, not now." delegate:self cancelButtonTitle:#"Ok, Got it" otherButtonTitles:nil, nil];
[errr show];
any idea how to achieve this result? do i need NSNotification to listen when this alert show up on uiwebview?
I tried something like this
NSString *theTitle=[webView stringByEvaluatingJavaScriptFromString:#"var targetDiv = document.getElementById('alerts').getElementsByClassName('alert-red')[0];"];
NSLog(#"%#",theTitle);
So I can try to retrieve that message from "alert-red" but doesn't work.
I'm new to javascript and html
This is the typical workaround used to solve this problem:
in your webpage when you want to show this alert, run this javascript code:
window.location = 'custom_action';
then in objc implement shouldStartLoadWithRequest on your controller (and set yourWebView.delegate = yourController)
-(BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
// detect when the webview switches to this custom url
if([[[request URL] absoluteString] isEqualToString: #"custom_action"]) {
UIAlertView *errr = [[UIAlertView alloc]initWithTitle:#"nil" message:#"ok. come back again tomorrow, not now." delegate:self cancelButtonTitle:#"Ok, Got it" otherButtonTitles:nil, nil];
[errr show];
// this prevents the webview from actually trying to load the custom url
return NO;
}
// allow the url to load if its not your custom url
return YES;
}

Capture (and prevent) alert() modal in UIWebView [duplicate]

<script language="javascript">
alert("Hell! UIWebView!");
</script>
I can see the alert message inside my UIWebView but can I handle this situation?
Update:
I'm loading a web-page into my UIWebView:
- (void)login {
NSString *requestText = [[NSString alloc] initWithFormat: #"%#?user=%#&password=%#", DEFAULT_URL, user.name, user.password]; // YES, I'm using GET request to send password :)
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:requestText]];
[webView loadRequest:request];
}
The target page contain a JS. If user name or password is incorrect this JS show alert.
I have not any access to its sources.
I want to handle it inside my UIWebViewDelegate.
A better solution to this problem is to create a Category for UIWebView for the method
webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:
So that you can handle the alert event in any way that you'd like. I did this because I don't like the default behavior of UIWebView when it puts the filename of the source in the UIAlertView title. The Category looks something like this,
#interface UIWebView (JavaScriptAlert)
- (void)webView:(UIWebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame;
#end
#implementation UIWebView (JavaScriptAlert)
- (void)webView:(UIWebView *)sender runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WebFrame *)frame {
UIAlertView* dialogue = [[UIAlertView alloc] initWithTitle:nil message:message delegate:nil cancelButtonTitle:#"Okay" otherButtonTitles:nil];
[dialogue show];
[dialogue autorelease];
}
#end
This seems to do it:
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
JSContext *ctx = [webView valueForKeyPath:#"documentView.webView.mainFrame.javaScriptContext"];
ctx[#"window"][#"alert"] = ^(JSValue *message) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"JavaScript Alert" message:[message toString] delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
};
}
Note: only tested on iOS 8.
If by "contain a flash" you mean the page you're loading into your web view has an Adobe Flash movie in it, you're out of luck, I'm afraid. Mobile Safari doesn't support Flash, and most likely never will.
In the general case, if you want JavaScript running in a web view to communicate with the native app hosting it, you can load fake URLs (for example: "myapp://alert?The+text+of+the+alert+goes+here."). That will trigger the webView:shouldStartLoadWithRequest:navigationType: delegate method. In that method, inspect the request, and if the URL being loaded is one of these internal communications, trigger the appropriate action in your app, and return NO.

iOS: call obj-c methods using javascript in a UIWebview

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.

User Interaction Enabled Javascript

I am writing a Javascript application and am going to wrap it in a native iOS application. I would like to block user interaction on the UIWebView containing the JS app for a second or two following an event.
Normally I would use the self.webView.userinteractionenabled = NO but the event is triggered in Javascript. How can I block the user from interacting with the web view?
Guessing return false on a touch event of some sort? It's scrolling that I want to block.
Thanks!
When the event occurs in your Javascript code you can send a message to the native wrapper by using the following method:
Set up the following UIWebViewDelegate method (don't forget to set the delegate for the UIWebView):
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
NSURL *url = [request URL];
if ([[url scheme] isEqualToString:#"block"]) {
// do the your blocking code here
return NO;
}
return YES;
}
Now when your event happens, call the delegate method from your javascript code:
window.location.href = "block://";

iOS SQL Database access from Javascript

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;
}

Categories

Resources