I need to have my iPhone Objective-C code catch Javascript errors in a UIWebView. That includes uncaught exceptions, syntax errors when loading files, undefined variable references, etc.
This is for a development environment, so it doesn't need to be SDK-kosher. In fact, it only really needs to work on the simulator.
I've already found used some of the hidden WebKit tricks to e.g. expose Obj-C objects to JS and to intercept alert popups, but this one is still eluding me.
[NOTE: after posting this I did find one way using a debugging delegate. Is there a way with lower overhead, using the error console / web inspector?]
I have now found one way using the script debugger hooks in WebView (note, NOT UIWebView). I first had to subclass 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 should create a YourScriptDebugDelegate class that contains methods like these:
// 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 large runtime impact for this, as the debug delegate can also supply methods to be called for entering and exiting a stack frame, and for executing each line of code.
See http://www.koders.com/noncode/fid7DE7ECEB052C3531743728D41A233A951C79E0AE.aspx for the Objective-C++ definition of WebScriptDebugDelegate.
Those other methods:
// just entered a stack frame (i.e. 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 (i.e. return from a function) - (void)webView:(WebView *)webView   willLeaveCallFrame:(WebScriptCallFrame *)frame       sourceId:(int)sid           line:(int)lineno    forWebFrame:(WebFrame *)webFrame;   Note that this is all hidden away in a private framework, so don't try to put this in code you submit to the App Store, and be prepared for some hackery to get it to work.
I created a nice little drop-in category that you can add to your project... It is based on Robert Sanders solution. Kudos.
You can dowload it here:
UIWebView+Debug
This should make it a lot easier to debug you UIWebView :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With