UIWebView URL Interceptor

UIWebView is a container view loading all and only the html data provided. This means that it has no extra windows, no tabs and definitely does not operate as Mobile Safari or has any of the standard functionality of a (mobile) web browser in iOS.

One of the most common “annoyances” a developer has to face while implementing a UIWebView are the links included inside the data been displayed on the webview. And given that there are no windows or tabs, a user tap on a link will result in the loading of the content inside the webview (and thus losing any content loaded before).

Handling this scenario (that is loading content in a webview which includes links to other destinations) has three possible ways to deal with:

  • Strip all html code,
  • Insert an “Interceptor” and
  • Disable/ignore/discard all URL taps.

Strip all html code (tags, entities etc).

Stripping all html from a page data will result in a single string with all content as text.

This is a Gordian knot solution. Cuting off all links if tapping is not desired, it will result in losing all text formatting and any additional information included (ex. formatting, embedded media etc).

This can be done easily by extending NSString with HTML codestripping:

//HTMLString is the content string you get from a webservice or from the webview after its is loaded
while ((r = [HTMLString rangeOfString:@"\< [\^\&\>]+\>" options:NSRegularExpressionSearch]).location != NSNotFound) 
{
    HTMLString = [HTMLString stringByReplacingCharactersInRange:r withString:@""];
}
 
NSString *convStr = [HTMLString stringByDecodingHTMLEntities];

Again… I do not recommend this for a full presentation of content within a UIWebView. I’d rather prefer to…

Insert an “Interceptor” inside UIWebView.

In this scenario, the idea is to intercept a user tap on the UIWebView and “re-route” it to perform another action, for example, displaying another view controller with a webview (oh yes, you can call it “open a new browser window” or “open a new tab” 😉 ).

The “Interceptor” is an easy task to do. A boolean value is firstly needed as a flag so that we know if we have loaded content on the UIWebView and prevent this content being reloaded or replaced. Defining:

Boolean isWebViewLoaded;

and initializing it just to be sure it is false after the view controller is loaded and before UIWebView is loaded:

isWebViewLoaded = false;

Again before loading the webview, the interceptor must take place inside shouldStartLoadWithRequest. (UIWebViewDelegate remember?)

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    switch (navigationType) {
        case UIWebViewNavigationTypeLinkClicked: { //this is when a user tap is detected
             //write the handling code here.
             isWebViewLoaded = false; //set this to false only if you open another view controller.
             return NO; //prevent tapped URL from loading inside the UIWebView.
    }
 
// some other typical parameters within a UIWebView. Use what is needed
        case UIWebViewNavigationTypeFormResubmitted: return YES;
        case UIWebViewNavigationTypeReload: return YES;
 
//for all other cases, including UIWebViewNavigationTypeOther called when UIWebView is loading for the first time
        default: {
            if (!isWebViewLoaded) { isWebViewLoaded = true; return YES; }
            else return NO;
        } 
    }
}

UiWebViewNavigationType is extremely important in handling the behavior of the UIWebView. Check all parameters as defined in Apple Documentation, and code accordingly.

Discard-ignore-disable all URL taps.

Two ways to do this:
Either disable any link click activity…

case UIWebViewNavigationTypeLinkClicked: return NO;</code>
 
or disable any activity on the webview after its been loaded.
 
<code lang="objc">-(BOOL)webView:(UIWebView*)webViewshouldStartLoadWithRequest:(NSURLRequest*)requestnavigationType:(UIWebViewNavigationType)navigationType
{
    if (!isWebViewLoaded) { //this is to load the first time and ignore all other calls afterwards.
        isWebViewLoaded = true;
         return YES;
    }
    else return NO;
}

Conclusion

Managing content on a UIWebView is easy but needs some extra care. If the webview has definitely no links inside, it is safe to leave it as it is loaded but in all other cases, the interceptor is the best solution to provide both content and functionality without breaking stuff in the content UI.