UIWebView loading parsed html string

35,069

Solution 1

UIWebView doesn't open target="_blank" links. Certain links don't fire UIWebViewNavigationTypeLinkClicked events. This happens when the link has the target="_blank" attribute.

To work around this problem i used the code below. It injects some javascript after the page load to remove the target attribute from all the links. After using this code i didn;t needed anymore to parse the html source and replace _blank with _self for example.

- (void)webViewDidFinishLoad:(UIWebView *)webView {
        NSString *js = @"\
        var d = document.getElementsByTagName('a');\
        for (var i = 0; i < d.length; i++) {\
            if (d[i].getAttribute('target') == '_blank') {\
                d[i].removeAttribute('target');\
            }\
        }\
        ";

        [webView stringByEvaluatingJavaScriptFromString:js];
}

Solution 2

I like SorinA answer, we can make it even better by:

  • avoid obstructing javascript with var d
  • as we know we're running webkit engine we can use selectors:

...so in your UIWebViewDelegate protocol method invoke js code:

- (void) webViewDidFinishLoad: (UIWebView *) webView {
  [webView stringByEvaluatingJavaScriptFromString: @"(function($){for(var i=0;i<$.length;++i){$[i].removeAttribute('target')}})(document.querySelectorAll('a[target=_blank]'))"];
}
Share:
35,069
Iryna Tserlizhenka
Author by

Iryna Tserlizhenka

Computer science graduate. Employed as an iOS developer.

Updated on August 18, 2020

Comments

  • Iryna Tserlizhenka
    Iryna Tserlizhenka over 3 years

    i'm building an app that will display some newsletters to the users. the newsletters are displayed in a uiWebView. I'm reading the url's for the newsletters from an rss feed. I parse the xml, and in a table view i have all the newsletters. When a cell is clicked the uiWebView is pushed and the newsletter is loaded. Because the uiWebView doesn't open links that have target=_blank i need to replace the _blank from target with "". In an NSOperation i download the contents of the html and after the download is finished i replace the strings like this:

    NSMutableString *page = [[[NSMutableString alloc] initWithData:pageData encoding:NSISOLatin1StringEncoding] autorelease]; [page replaceOccurrencesOfString:@"target=_blank" withString:@"target=""" options:0 range:NSMakeRange(0, [page length])];
    

    after i do this i load the parsed string in the webView to display it to the user.

    [myWebView loadHTMLString:page baseURL:[NSURL URLWithString:@""]];
    

    while the NSOperation is downloading the contents of the page an HUD with a activity indicator and a label that says Loading is showed. When the download is finished the HUD is removed from the superview.

    so far so good..but here come the questions. i used the NSOperation with the callback function because i wasn't able to determine the last call to webDidFinishLoading ( i read this UIWebView - How to identify the "last" webViewDidFinishLoad message? - this is a part of my problem but the response was to use some Apple private classes and that is a problem for me). so i'm doing this:

    - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType {
    
    
    NSURL *url = request.URL;
    NSString *urlString = url.absoluteString;
    NSLog(@"WebViewSouldStartWithRequest: %@", urlString);
    if (navigationType == UIWebViewNavigationTypeLinkClicked)
    {
        if(![urlString isEqualToString:@"about:blank"])
        {
            NSLog(@"FeedViewController: startPageLoad");
            activityHud = [[HUDView alloc] initWithFrame:CGRectMake(110, 100, 80, 80)];
            [activityHud setText:@"Loading"];
            [myWebView addSubview:activityHud];
            NSLog(@"FeedViewController: pageUrl = %@", urlString);
            [self resetWebView];
            [urlLoader loadPageFromUrl:request.URL withCallbackTarget:self withCallbackSelector:@selector(endLoading:)];
        }
    }
    
    return NO;
    

    }

    - (void) endLoading:(NSMutableString *)page { [self resetWebView]; NSLog(@"FeedViewController: endLoading"); [activityHud removeFromSuperview]; [myWebView loadHTMLString:page baseURL:[NSURL URLWithString:@""]]; }
    

    after i touch a cell in the table view and the newsletter is showed it looks like it should, when i click a link in the newsletter, the page is loaded with the new request, parsed but visually is not looking as it should (i looked at the page after parsing in NSLog and it has the css styles and html tags, head, body opened and closed correctly) anyone had this problem with uiWebView, not showing webpages correctly?

    i tried loading the page with - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType{ return YES; } and in - (void)webViewDidFinishLoad:(UIWebView *)webview {} and in - webViewDiStartLoad

    but the methods are being called for every item that is loaded in the webview so showing and hiding the HUD in those method is not a good solution.

    I encountered some problems while using - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType { ... return NO }

    for example links that have paths like this /bilder-galerien to not work and in NSLog i receive this for them

    Unknown scheme, doing nothing: /bilder-galerien

    but when i use

    • (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType { return Yes } and didstartLoading and finishLoading the urls are loaded and i don't know why...

    another problem are the special german characters..in my first load(after pressing a cell in the uiTableView) the page is parsed like it should be by the uiWebView but after i click a link and the corresponding request is loaded also the characters are not parsed correctly..

    can anyone point me in the good direction? thank you in advance