How will my iPhone Objective-C code receive Javascript error notification in UIWebView?

I need my iPhone Objective-C to encode Javascript errors in a UIWebView. This includes uncaught exceptions, syntax errors while loading files, undefined variable references, etc.

This is for the development environment, so it does not need to be SDK-kosher. In fact, it really needs to work on a simulator.

I already found some hidden WebKit tricks, for example. expose Obj-C objects in JS and intercept pop-ups, but that still eludes me.

[NOTE: after posting this question, I found one way to use the debug delegate. Is there a way with lower overhead using the error console / web inspector?]

+45
objective-c iphone webkit
Oct 10 '08 at 21:39
source share
10 answers

Now I have found one way using script debugger hooks in a WebView (note, NOT UIWebView). First I had to subclass the UIWebView and add a method like this:

- (void)webView:(id)webView windowScriptObjectAvailable:(id)newWindowScriptObject { // save these goodies windowScriptObject = newWindowScriptObject; privateWebView = webView; if (scriptDebuggingEnabled) { [webView setScriptDebugDelegate:[[YourScriptDebugDelegate alloc] init]]; } } 

Next, you must create the YourScriptDebugDelegate class containing the following methods:

 // in YourScriptDebugDelegate - (void)webView:(WebView *)webView didParseSource:(NSString *)source baseLineNumber:(unsigned)lineNumber fromURL:(NSURL *)url sourceId:(int)sid forWebFrame:(WebFrame *)webFrame { NSLog(@"NSDD: called didParseSource: sid=%d, url=%@", sid, url); } // some source failed to parse - (void)webView:(WebView *)webView failedToParseSource:(NSString *)source baseLineNumber:(unsigned)lineNumber fromURL:(NSURL *)url withError:(NSError *)error forWebFrame:(WebFrame *)webFrame { NSLog(@"NSDD: called failedToParseSource: url=%@ line=%d error=%@\nsource=%@", url, lineNumber, error, source); } - (void)webView:(WebView *)webView exceptionWasRaised:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame { NSLog(@"NSDD: exception: sid=%d line=%d function=%@, caller=%@, exception=%@", sid, lineno, [frame functionName], [frame caller], [frame exception]); } 

There is probably a big influence on runtime for this, since the debug delegate can also provide methods that must be called to enter and exit the stack frame, and to execute each line of code.

See http://www.koders.com/noncode/fid7DE7ECEB052C3531743728D41A233A951C79E0AE.aspx for an Objective-C ++ WebScriptDebugDelegate definition.

Those other methods:

 // just entered a stack frame (ie called a function, or started global scope) - (void)webView:(WebView *)webView didEnterCallFrame:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame; // about to execute some code - (void)webView:(WebView *)webView willExecuteStatement:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame; // about to leave a stack frame (ie return from a function) - (void)webView:(WebView *)webView willLeaveCallFrame:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame; 

Please note that all this is hidden in a private structure, so do not try to put this in the code that you send to the App Store, and be prepared for hacking to make it work.

+28
Oct 10 '08 at 22:57
source share

I created a beautiful little category that you can add to your project ... It is based on the decision of Robert Sanders. Kudos.

You can download it here:

UIWebView + Debugging

This will make it easier for you to debug UIWebView :)

+13
Jul 16 2018-12-12T00:
source share

I used the great solution suggested by Robert Sanders: How will my iPhone Objective-C code receive Javascript error notification in UIWebView?

This hook for webkit works great on iPhone as well . Instead of the standard UIWebView, I highlighted the resulting MyUIWebView. I also needed to define hidden classes inside MyWebScriptObjectDelegate.h:

@class WebView;
@class WebFrame;
@class WebScriptCallFrame;

Inside ios sdk 4.1 function:

 - (void)webView:(id)webView windowScriptObjectAvailable:(id)newWindowScriptObject 

deprecated , and instead I used the function:

 - (void)webView:(id)sender didClearWindowObject:(id)windowObject forFrame:(WebFrame*)frame 

In addition, I get some annoying warnings, such as "NSObject may not respond -windowScriptObject" because the class interface is hidden. I ignore them and it works well.

+11
Nov 05 '10 at 17:02
source share

Direct way: put this code on top of your controller / view using UIWebView

 #ifdef DEBUG @interface DebugWebDelegate : NSObject @end @implementation DebugWebDelegate @class WebView; @class WebScriptCallFrame; @class WebFrame; - (void)webView:(WebView *)webView exceptionWasRaised:(WebScriptCallFrame *)frame sourceId:(int)sid line:(int)lineno forWebFrame:(WebFrame *)webFrame { NSLog(@"NSDD: exception: sid=%d line=%d function=%@, caller=%@, exception=%@", sid, lineno, [frame functionName], [frame caller], [frame exception]); } @end @interface DebugWebView : UIWebView id windowScriptObject; id privateWebView; @end @implementation DebugWebView - (void)webView:(id)sender didClearWindowObject:(id)windowObject forFrame:(WebFrame*)frame { [sender setScriptDebugDelegate:[[DebugWebDelegate alloc] init]]; } @end #endif 

And then create it like this:

 #ifdef DEBUG myWebview = [[DebugWebView alloc] initWithFrame:frame]; #else myWebview = [[UIWebView alloc] initWithFrame:frame]; #endif 

Using #ifdef DEBUG ensures that it is not included in the release build, but I would also recommend commenting on it when you are not using it, as this affects performance. Credit owned by Robert Sanders and Prcela for the original code

Also, if you use ARC, you may need to add "-fno-objc-arc" to prevent some build errors.

+8
08 Oct 2018-11-11T00:
source share

One of the ways that works during development, if you have Safari v 6+ (I don’t know which version of iOS you need), you should use the Safari development tools and connect to UIWebView through it.

  • In Safari: enable the "Design" menu ("Settings"> "Advanced"> "Show Menu" in the menu bar)
  • Connect the phone to the computer via cable.
  • List item
  • Download the application (either through xcode, or just run it), and go to the screen that you want to debug.
  • Return to Safari, open the "Development" menu, look for the name of your device in this menu (mine is called iPhone 5), the User Agent should be right.
  • Select it, and you will see a drop-down list of web views currently displayed in your application.
  • If there are several web views on the screen, you can try to tell them about everything by moving the application name to the development menu. The corresponding UIWebView will turn blue.
  • Select the application name, the development window will open and you can check the console. You can even issue JS commands through it.
+6
Mar 18 '13 at 18:53
source share

I created an SDK encoder error corrector that includes:

  • Error message
  • The name of the file in which the error occurred
  • The line number where the error occurs
  • JavaScript column including parameters passed

This is part of the QuickConnectiPhone framework available from the sourceForge project.

There is even an example application that shows how to send an error message to the Xcode terminal.

All you have to do is surround your JavaScript code, including function definitions, etc. using try catch. It should look like this.

 try{ //put your code here } catch(err){ logError(err); } 

This does not work well with compilation errors, but works with everyone else. Even anonymous features.

Here is a blog here and includes links to wiki, sourceForge, google group and twitter. Perhaps this will help you.

+4
Apr 21 '09 at 20:58
source share

I did this in firmware 1.x, but not 2.x. Here is the code I used in 1.x, it should at least help you on your way.

 // Dismiss Javascript alerts and telephone confirms /*- (void)alertSheet:(UIAlertSheet*)sheet buttonClicked:(int)button { if (button == 1) { [sheet setContext: nil]; } [sheet dismiss]; }*/ // Javascript errors and logs - (void) webView: (WebView*)webView addMessageToConsole: (NSDictionary*)dictionary { NSLog(@"Javascript log: %@", dictionary); } // Javascript alerts - (void) webView: (WebView*)webView runJavaScriptAlertPanelWithMessage: (NSString*) message initiatedByFrame: (WebFrame*) frame { NSLog(@"Javascript Alert: %@", message); UIAlertSheet *alertSheet = [[UIAlertSheet alloc] init]; [alertSheet setTitle: @"Javascript Alert"]; [alertSheet addButtonWithTitle: @"OK"]; [alertSheet setBodyText:message]; [alertSheet setDelegate: self]; [alertSheet setContext: self]; [alertSheet popupAlertAnimated:YES]; } 
0
Oct 10 '08 at 22:14
source share

See exception handling in iOS7: http://www.bignerdranch.com/blog/javascriptcore-example/

 [context setExceptionHandler:^(JSContext *context, JSValue *value) { NSLog(@"%@", value); }]; 
0
Feb 22 '15 at
source share

First configure WebViewJavascriptBridge , then override the console.error function.

In javascript

  window.originConsoleError = console.error; console.error = (msg) => { window.originConsoleError(msg); bridge.callHandler("sendConsoleLogToNative", { action:action, message:message }, null) }; 

In Objective-C

 [self.bridge registerHandler:@"sendConsoleLogToNative" handler:^(id data, WVJBResponseCallback responseCallback) { NSString *action = data[@"action"]; NSString *msg = data[@"message"]; if (isStringValid(action)){ if ([@"console.error" isEqualToString:action]){ NSLog(@"JS error :%@",msg); } } }]; 
0
Apr 13 '17 at 3:37 on
source share

A simpler solution for some cases might be to simply add Firebug Lite to the web page.

-3
Nov 16
source share



All Articles