send a notification from javascript in UIWebView to ObjectiveC
There seems to be no official method of doing this. However, the standard workaround involves reading and parsing incoming URL requests, basically rolling your own serialized messaging protocol. The message handling should be done in the webView:shouldStartLoadWithRequest:navigationType
method of your view controller.
Note: there are several free libraries (PhoneGap, QuickConnect, JS-to-Cocoa Bridge) which wrap this functionality (plus do a whole lot more). To reinvent the wheel (or know why it's round, so to speak), read on.
From JavaScript, you will invoke the callback by attempting to navigate to a new URL:
// In JavaScript
window.location = 'myapp:myaction:param1:param2'; // etc...
In Objective-C, implement the UIWebViewDelegate
protocol in your .h
file:
// In your header file
@interface MyAppViewController : UIViewController <UIWebViewDelegate> {
...
}
@end
Next, implement the method in your .m
file:
// In your implementation file
-(BOOL)webView:(UIWebView *)webView2
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
{
// Break apart request URL
NSString *requestString = [[request URL] absoluteString];
NSArray *components = [requestString componentsSeparatedByString:@":"];
// Check for your protocol
if ([components count] > 1 &&
[(NSString *)[components objectAtIndex:0] isEqualToString:@"myapp"])
{
// Look for specific actions
if ([(NSString *)[components objectAtIndex:1] isEqualToString:@"myaction"])
{
// Your parameters can be found at
// [components objectAtIndex:n]
// where 'n' is the ordinal position of the colon-delimited parameter
}
// Return 'NO' to prevent navigation
return NO;
}
// Return 'YES', navigate to requested URL as normal
return YES;
}
Two important notes:
Context: navigating to
myapp:whatever
will (of course) fail under any other context. Keep this in mind if you're loading cross-platform pages.Timing: if a second
window.location =
call is made before the first returns, it will get 'lost.' So, either lump your calls together, manually delay execution, or implement a queue which combines the above with JS queries into Objective-C objects.
How to send events from HTML running inside a UIWebView to native Objective-C code?
I have done this using jQuery and UIWebViewDelegate:
JavaScript (jQuery mobile):
$("#bloodType").change(function() {
url = $("#bloodType option:selected").text();
url = "donordialog:bloodTypeChanged(" + url + ")";
window.location = url;
});
So, the resulting URL looks like: donordialog:bloodTypeChanged(typeAB-)
In my objc code:
-(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
NSURL *URL = [request URL];
if ([[URL scheme] isEqualToString:@"donordialog"])
{
// now we need to figure out the function part
NSString *functionString = [URL resourceSpecifier];
if ([functionString hasPrefix:@"bloodTypeChanged"])
{
// the blood type has changed, now do something about it.
NSString *parameter = [functionString stringByReplacingOccurrencesOfString:@"bloodTypeChanged" withString:@""];
// remove the '(' and then the ')'
parameter = [parameter stringByReplacingOccurrencesOfString:@"(" withString:@""];
parameter = [parameter stringByReplacingOccurrencesOfString:@")" withString:@""];
// log the paramter, as I don't know what to do with it right now
NSLog(@"%@", parameter);
}
return NO;
}
return YES;
}
This code was copied verbatim from a project I am currently working on, and can verify that this works.
How to invoke Objective-C method from Javascript and send back data to Javascript in iOS?
There is an API to call JavaScript directly from Objective-C, but you cannot call Objective-C directly from Javascript.
How to tell your Objective-C code to do something from the Javascript in your WebView
You have to serialize your Javascript action into a special URL and intercept that URL in the UIWebView's delegate's shouldStartLoadWithRequest
method.
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType;
There you can deserialize that special URL and interpret it to do what you want on the Objective-C side. (You should return NO
in the above shouldStartLoadWithRequest
method so the UIWebView doesn't use your bogus URL to actually make an HTTP request to load a webpage.)
How to Run Javascript Code from Objective-C
Then you can run Javascript from Objective-C by calling this method on your webview.
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
Example Code
I recommend using a bogus URL scheme so it will be easy to tell the difference between your action URLs and legit requests. You can make this request in the Javascript along these lines:
// JavaScript to send an action to your Objective-C code
var myAppName = 'myfakeappname';
var myActionType = 'myJavascriptActionType';
var myActionParameters = {}; // put extra info into a dict if you need it
// (separating the actionType from parameters makes it easier to parse in ObjC.)
var jsonString = (JSON.stringify(myActionParameters));
var escapedJsonParameters = escape(jsonString);
var url = myAppName + '://' + myActionType + "#" + escapedJsonParameters;
document.location.href = url;
Then in the UIWebView.delegate
's shouldStartLoadWithRequest
method, you can inspect the URL scheme and fragment to check if it's a normal request or one of your special actions. (The fragment of a URL is what comes after the #
.)
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType {
// these need to match the values defined in your JavaScript
NSString *myAppScheme = @"myfakeappname";
NSString *myActionType = @"myJavascriptActionType";
// ignore legit webview requests so they load normally
if (![request.URL.scheme isEqualToString:myAppScheme]) {
return YES;
}
// get the action from the path
NSString *actionType = request.URL.host;
// deserialize the request JSON
NSString *jsonDictString = [request.URL.fragment stringByReplacingPercentEscapesUsingEncoding:NSASCIIStringEncoding];
// look at the actionType and do whatever you want here
if ([actionType isEqualToString:myActionType]) {
// do something in response to your javascript action
// if you used an action parameters dict, deserialize and inspect it here
}
// make sure to return NO so that your webview doesn't try to load your made-up URL
return NO;
}
(Read this answer if you need help deserializing your json string into an NSDictionary.)
webview javascript event notification
If you are talking about UIWebViews (as you have indicated with your tags): No, there is no direct way to call Objective-C code from inside a UIWebView.
You can however use stringByEvaluatingJavaScriptFromString:
and poll for changes. Example: if you want to get notified when a certain global JS variable changes, you can use
NSString *variableContent = [webView stringByEvaluatingJavaScriptFromString:@"myGlobalVariable"];
Call this code from a repeating timer, store the retrieved content and perform your action whenever the content changes.
iOS Calling Objective-C from Javascript: Some calls are ignored?
The accepted answer does not solve the problem since location changes that arrive before the first is handled are still ignored. See the first comment.
I suggest the following approach:
function execute(url)
{
var iframe = document.createElement("IFRAME");
iframe.setAttribute("src", url);
document.documentElement.appendChild(iframe);
iframe.parentNode.removeChild(iframe);
iframe = null;
}
You call the execute
function repeatedly and since each call executes in its own iframe, they should not be ignored when called quickly.
Credits to this guy.
Javascript in UIWebView callback to C/Objective-C
Update - don't use UIWebView anymore. Use WKWebView, or better yet (if it fits your needs and you're building for iOS 9), a Safari View Controller.
But if you must use UIWebView, in your UIWebView delegate, provide an implementation for webView:shouldStartLoadWithRequest:navigationType:
In your HTML or Javascript files, add functions that send URLs to a custom scheme (for readability purposes, the custom scheme isn't required). All the URLs sent will be passed to your Objective-C method implementation, and then you can do what you'd like.
iphone notification from javascript to objective C
Implement the following UIWebView Delegate Method and call your Objective methods
(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
if (navigationType == UIWebViewNavigationTypeLinkClicked) {
NSLog(@"LINK CLICKED......");
//return NO;
}return YES;
}
Related Topics
Need to Load Image as Modal on Click in Bootstrap CSS
Detect When Scrolling Has Finished When Using 'Scroll-Behavior: Smooth'
How to Add an Icon to the Options in React-Select
Handle Webpack CSS Imports When Testing with Mocha and Babel
Remove Styles from Text When Copying/Cutting Using CSS or JavaScript
How to Detect When an HTML Element's Class Changes
Highlight an Individual Word Within a Text Block on Hover
How to Width-Wise Shrink-Wrap Content That Spans More Than One Line
Random Fullscreen Background Image on Browser Refresh
Document.Body.Scrollheight Yielding Two Different Results in Firefox/Chrome
Svg Resizes on Hover in Safari Only
Detect Browser Graphics Performance
Applying More in Depth Selection to the :Host CSS Pseudo Class
Convert from English Digits to Arabic Ones in HTML Page
Animation for Newly Rendered Elements, But Not on Page Load
Any Way to Hide CSS and JavaScript File from the Client-Side User