iOS WebView error and debug logging

Theoretically one of the advantages of implementing a user interface using an embedded UIWebView is that you can debug the whole thing outside of the iOS app, in a regular browser with full debugging facilities. This is true, but sometimes you want to see what's going on in the Javascript code as it's running on the iOS device. Unfortunately, the output from console.log and Javascript error reporting seems to just disappear, rather than go into the debug console in XCode.

Fortunately, this is remarkably easy to fix. It's just a little code on the Objective-C side, and a little on the Javascript side. Note that this is intended for debugging use only. It's a fair amount of unnecessary overhead otherwise.

Note that this uses a custom URL protocol handler. It's small, fast, and a really good way to have Javascript call into Objective-C, asynchronously. While it's easy for Objective-C to call into Javascript using stringByEvaluatingJavaScriptFromString, there is no facility built-in for going the opposite direction.

A few people have played tricks using the location.href, or the href of an invisible iframe or NativeBridge, but I don't really like those solutions. My solution allows you to pass essentially unlimited amounts of data in JSON format both into Objective-C, as well as return structured data.

In my Javascript I used jquery, since I was already using it, but it should be pretty easy to rewrite it without jquery.

Well, here we go:

ConsoleURLProtocol.h:


ConsoleURLProtocol.m:


The Javascript. You'll want to call interceptErrors() from your document ready handler.
function interceptErrors() { // Override console.log console = new Object(); console.log = function(log) { sendToConsoleLogger({k:'c', m:log}); }; console.debug = console.log; console.info = console.log; console.warn = console.log; console.error = console.log; // Override window onerror window.onerror = function(error, url, line) { sendToConsoleLogger({k:'e', m:error, u:url, l:line}); }; } function sendToConsoleLogger(requestData) { $.ajax({ type: 'POST', url: '/_ConsoleLogger', dataType: 'json', data: JSON.stringify(requestData), success: function(responseData) { }, error: function(error) { }}); }


You need to register the URL protocol, presumably in AppDelegate.m, in didFinishLaunchingWithOptions.
[NSURLProtocol registerClass:[ConsoleURLProtocol class]];

In my case, the Javascript isn't even downloaded from the web, it's embedded in the app. And I'm only using this during debugging. Still, when calling from Javascript into Objective-C make sure you take precautions to not allow the Javascript to execute anything it shouldn't. Fortunately, since the Objective-C side is written like you'd write a web service, writing it defensively should be straightforward.

About this Entry

This page contains a single entry by Rick Kasguma published on October 19, 2013 1:37 PM.

iOS UIWebView for files in bundle without file URLs was the previous entry in this blog.

Spotify Next Track Button is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.

Categories

Pages