We have:
(1) Facebook API-based web application with Facebook OAuth functionality (“the FB web app”)
(2) UIWebView-based browser on iPad (“the Browser”
In case anyone is googling, here's what worked for me:
-(BOOL) webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)inType {
if ([request.URL.absoluteString containsString:@"m.facebook.com"]) {
if ([request.URL.absoluteString rangeOfString:@"back"].location == 0) {
[self.popUp removeFromSuperview];
self.popUp = nil;
return NO;
}
if (self.popUp) {
return YES;
}
UIWebView *wv = [self popUpWebView];
[wv loadRequest:request];
return NO;
}
return YES;
}
- (UIWebView *) popUpWebView {
toolbar height
UIWebView *webView = [[UIWebView alloc]
initWithFrame:CGRectMake(0, 0, (float)self.view.bounds.size.width,
(float)self.view.bounds.size.height)];
webView.scalesPageToFit = YES;
webView.delegate = self;
// Add to windows array and make active window
self.popUp = webView;
[self.view addSubview:webView];
return webView;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if (self.popUp) {
NSError *error = nil;
NSString *jsFromFile = @"window.close=function(){window.location.assign('back://' + window.location);};";
__unused NSString *jsOverrides = [webView
stringByEvaluatingJavaScriptFromString:jsFromFile];
JSContext *openerContext = [self.webView
valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
JSContext *popupContext = [webView
valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
popupContext[@"window"][@"opener"] = openerContext[@"window"];
}
//this is the secret sauce
if (webView == self.popUp
&& [webView.request.URL.absoluteString containsString:@"m.facebook.com"]
&& [[webView stringByEvaluatingJavaScriptFromString:@"document.body.innerHTML"] isEqualToString:@""]) {
[webView stringByEvaluatingJavaScriptFromString:@"eval(document.getElementsByTagName('script')[0].text)"];
}
}
I snagged a bunch of this implementation from here.
Depending on your web implementation, there will likely be one extra step. The Facebook script actually executes a window.close() then a window.open() then a window.close(). For me this was causing problems because on the web side, after this login is complete, my window (i.e. for the webView that I want the user to log in to) was getting a window.close() call, coming from the Facebook SDK. I'm assuming this is because the Facebook SDK expects that window.open() call to open a new window that it will close.
Since we didn't override the functionality of window.open(), calling window.open() won't do anything, and the Facebook SDK will attempt to close your window. This could cause all kind of problems, but for me since I'm using Parse, window.localStorage was set to null so I was getting all kinds of errors.
If something like this is happening for you, you have two options to fix it:
window.close=function(){}window.close for the main webView like we did for the popUp webView, or override the window.open function to open another popUp (which is described in more detail here)