Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS: Facebook Comments Plugin mobile keeps reloading

Recently I have been trying to integrate Facebook Social Plugins into a custom UIWebView in iOS for commenting a webpage. I have added the Like Button as well as the Comments plugin. Here is the HTML code I load into the web view:

  <html>
    <body>
<div id="fb-root"></div>
<script>(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
<div class="fb-like" data-href="http://www.heretheweb.com" data-send="false" data-layout="button_count" data-width="240" data-show-faces="false"></div>
<div class="fb-comments" data-href="http://www.heretheweb.com" data-num-posts="5" data-width="470"></div>
<body>
</html>

The first implementation on Monday was sucessfull in 4 platforms, both simulators (iOS 4 and iOS 5), iPhone 3G iOS4 and iPhone 4 iOS 5. On Tuesday, I kept developing this and I ended up with my custom UIWebView working with no problems in the first three. But on iPhone 4 (iOS 5) the web view kept reloading the same web page over and over again, resulting in the comment box never appearing. That URL is this:

https://m.facebook.com/plugins/comments.php?channel_url=http%3A%2F%2Fstatic.ak.facebook.com%2Fconnect%2Fxd_arbiter.php%3Fversion%3D4%23cb%3Df28c738848%26origin%3Dhttp%253A%252F%252Fwww.heretheweb.com%252Ff3fdf142e8%26domain%3Dwww.heretheweb.com%26relation%3Dparent.parent&href=http%3A%2F%2Fwww.heretheweb.com&locale=en_US&mobile=true&numposts=5&sdk=joey&width=470

I don't know what I am doing wrong really, I have cleaned the uiWebView delegate methods, I have check with breakpoints ALL the methods I could override. Nothing... The webpage gets loaded at the beginning, and then it loops trying to load the above URL...

like image 944
lupidan Avatar asked Apr 18 '12 12:04

lupidan


1 Answers

There is a bug in the facebook comments plugin that causes an infinite loading loop when the comments plugin is being loaded on Retina enabled devices.

There is a line in one of fb js scripts that goes as follows:

if(window.devicePixelRatio>1)document.location.reload()

so if you're accessing the page on a device with a high density screen you are doomed.

I reported the issue here

I came up with a dirty hack to fix it but think twice before using it, it might stop working at any time.

Note that this approach works only when you embed the plugin in UIWebView, if you have a problem when you're accessing a page in safari there's no other option but to wait for a fix from facebook.

My idea was to 'fix' the js code on the fly as it's getting loaded by a UIWebView.

To process requests on the fly I created my own implementation of NSURLProtocol:

<FBCommentsFixingURLProtocol.h>

#import <Foundation/Foundation.h>

@interface FBCommentsFixingURLProtocol : NSURLProtocol

@end

<FBCommentsFixingURLProtocol.m>
#import "FBCommentsFixingURLProtocol.h"


static NSString *FBCommentsFixingHeader = @"X-FBFix";

@interface FBCommentsFixingURLProtocol () 
@property (nonatomic, readwrite, strong) NSURLRequest *request;
@property (nonatomic, readwrite, strong) NSURLConnection *connection;
@property (nonatomic, readwrite, strong) NSURLResponse *response;

@end

@implementation FBCommentsFixingURLProtocol
@synthesize request = request_;
@synthesize connection = connection_;
@synthesize response = response_;


+ (BOOL)canInitWithRequest:(NSURLRequest *)request
{
    if (([request.URL.scheme isEqualToString:@"https"] || [request.URL.scheme     isEqualToString:@"http"]) && [request.URL.absoluteString rangeOfString:@"facebook.com/plugins/comments.php"].location != NSNotFound &&
    [request valueForHTTPHeaderField:FBCommentsFixingHeader] == nil)
{
    return YES;
}
return NO;
}

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
{
    return request;
}

- (id)initWithRequest:(NSURLRequest *)request
       cachedResponse:(NSCachedURLResponse *)cachedResponse
           client:(id <NSURLProtocolClient>)client
{
    // Modify request so we don't loop
    NSMutableURLRequest *myRequest = [request mutableCopy];
    [myRequest setValue:@"" forHTTPHeaderField:FBCommentsFixingHeader];
    self = [super initWithRequest:myRequest
               cachedResponse:cachedResponse
                       client:client];
    if (self)
    {
       [self setRequest:myRequest];
    }
    return self;
}


- (void)startLoading
{
    NSURLConnection *connection = [NSURLConnection connectionWithRequest:[self request]
                                                            delegate:self];
    [self setConnection:connection];

}

- (void)stopLoading
{
    [[self connection] cancel];
}


- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    NSString *dataAsString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
     //Just modify the script to prevent it from execution on Retina devices.
    //window.devicePixelRatio = 2 for the Retina Display
    NSString* modified =  [dataAsString stringByReplacingOccurrencesOfString:@"if(window.devicePixelRatio>1)document.location.reload();" withString:@""];
    NSData* dataMod=[modified dataUsingEncoding:NSUTF8StringEncoding];
    [[self client] URLProtocol:self didLoadData:dataMod];
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    [[self client] URLProtocol:self didFailWithError:error];
    [self setConnection:nil];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    [self setResponse:response];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    [[self client] URLProtocolDidFinishLoading:self];
    [self setConnection:nil];
}


@end

And then I registered it in the app delegate didFinishLaunchingWithOptions:

[NSURLProtocol registerClass:[FBCommentsFixingURLProtocol class]];

I'm aware that this is a dirty hack but still it works.

like image 153
blebleble Avatar answered Nov 03 '22 15:11

blebleble