Send a Notification from JavaScript in Uiwebview to Objectivec

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:

  1. Context: navigating to myapp:whatever will (of course) fail under any other context. Keep this in mind if you're loading cross-platform pages.

  2. 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



Leave a reply



Submit