2012-11-09 15 views
6

Abbiamo:
(1) Facebook API basata su un'applicazione web con funzionalità di Facebook OAuth (“la web app FB”)
(2) UIWebView del browser based su iPad (“Browser”)Come posso ottenere che UIWebView apra la pagina di accesso di Facebook in risposta alla richiesta OAuth su iOS 5 e iOS 6?

nostro l'obiettivo è aprire la pagina di accesso di Facebook per accedere all'app Web FB (1) all'interno del browser basato su UIWebView (2) su iPad.

Esiste un problema in qualche modo simile qui:
http://facebook.stackoverflow.com/questions/11337285/no-longer-able-to-login-to-ios-app-via-oauth-the-page-requested-was-not-found

Tuttavia, la questione di tale questione succede dopo che l'utente inserisce login e password nel modulo di Facebook. Il nostro problema è che non possiamo visualizzare il modulo di login di Facebook in primo luogo. La modifica del tipo di app da "Web" a "Nativo/Desktop", come suggerito in quella domanda, non ha aiutato.

Passi:
1. Aprire la pagina web (semplice pagina HTML) con questo UIWebView Browser
2. Fare clic sul pulsante “FB web app” lancio in questa pagina
3. Su clic JavaScript tenta di avviare OAuth, che dovrebbe aprire la schermata di login di Facebook per accedere al web app FB

risultato corrente (numero):
su iOS 5. iOS 6. + e + dispositivi
- la nostra pagina web rimane invariata
- La pagina di accesso di Facebook è N OT mostrato (la nostra pagina web è ancora visualizzato)
Su iOS 4.3 (funziona come previsto):
- la pagina di login di Facebook si apre nella stessa UIWebView oggetto del Browser (sostituisce la nostra pagina web)

Risultato previsto :
- Viene visualizzata la pagina di accesso di Facebook e l'utente può accedere al login Facebook & password
- Funziona su iOS 5. + e iOS 6. + se avviato nel browser Safari su iPad. pagina di login di Facebook si apre in una scheda separata (al contrario, non ci sono schede separate in UIWebView)

Domanda: Come posso ottenere UIWebView per aprire Facebook pagina di login in risposta alla richiesta di OAuth su iOS 5+ e iOS 6 +?

Altri dettagli tecnici:

Abbiamo log diversi campi NSURLRequest dall'interno

-(BOOL)webView(UIWebView*)webView shouldStartLoadWithRequest(NSURLREquest*)request navigationType:… 

E abbiamo notato una certa differenza di registri per “correggere” e comportamenti “scorretti”. Ecco come l'esecuzione flussi cercami:

In primo luogo, premere il pulsante di lancio “FB Web App” per avviare OAuth, quindi alcuni casi vanno

iOS 4.3, “corretto”
richiesta di www.facebook.com/dialog/oauth? ...
richiesta a fbwebapp.com
richiesta a m.facebook.com/login.php? ....
--here facebook login appare

iOS 5.0, “incorrect1”
richiesta di www.facebook.com/dialog/oauth~~V~~3rd? ...
richiesta di fbwebapp.com
richiesta di m.facebook. com/login.php? ...

allora può essere
sacco --un di m.facebook.com/login.php?...with prossimo ... in parametri
seguita da errore SQLite
- Bene ora vedo "Mi dispiace, qualcosa è andato storto" pa ge da facebook (si tratta di una prima volta a tutti che incontro esso)

iOS 6.0 “incorrect2”
richiesta di www.facebook.com/dialog/oauth~~V~~singular~~3rd? ...
richiesta di fbwebapp.com

-(void)webView:(UIWebView*)webView didFailLoadWithError:(NSError*)error is invoked with error code -999

Si può vedere che il comportamento dipende sicuramente dalla versione di iOS. Ma il caso comune è che l'errore si verifica sul passaggio di ottenere m.facebook.com/login.php .. URL. Ma questo è tutto ciò che possiamo rilevare.

Stiamo sbattendo la testa contro quel muro per tutto il giorno alla ricerca di soluzioni. Perdutamente.
Potete aiutarci a ottenere la pagina di accesso di Facebook aperta nello UIWebView in risposta a OAuth?

risposta

0

Utilizzare la classe FBDialog per richiedere all'utente di accedere. Questo utilizza una visualizzazione web all'interno dell'app, quindi su login con successo l'utente verrà registrato all'interno di qualsiasi UIWebView:

NSString *kRedirectURL = @"fbconnect://success"; 
NSString *kSDK = @"ios" ; 
NSString *kLogin = @"oauth"; 
NSString *kDialogBaseURL = @"https://m.facebook.com/dialog/"; 

NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys: 
           AE_FACEBOOK_APPID, @"client_id", 
           @"user_agent", @"type", 
           kRedirectURL, @"redirect_uri", 
           @"touch", @"display", 
           kSDK, @"sdk", 
           nil]; 

NSString *loginDialogURL = [kDialogBaseURL stringByAppendingString:kLogin]; 

FBLoginDialog* loginDialog = [[FBLoginDialog alloc] initWithURL:loginDialogURL 
                loginParams:params 
                 delegate:self]; 
[loginDialog show]; 

poi fare la classe aderire al protocollo FBDialogDelegate, e aggiungere questa funzione alla classe:

-(void)fbDialogLogin: (NSString *)token expirationDate:(NSDate *)expirationDate{ 
    // Store the token and expiration date into the FB SDK 
    self.facebook.accessToken = token; 
    self.facebook.expirationDate = expirationDate; 
    // Then persist these so the SDK picks them up on next load 

    NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; 

[defaults setObject:self.facebook.accessToken forKey:ACCESS_TOKEN_KEY]; 
[defaults setObject:self.facebook.expirationDate forKey:EXPIRATION_DATE_KEY]; 
[defaults synchronize]; 
} 

HTH!

+0

, potrebbe spiegare di più su questa soluzione? Sono un principiante su iOS, ma ho già provato alcuni esempi di Facebook SDK. See you – owlmsj

3

Fatto!

Si tratta di un trucco, ma il login di js facebook su UiWebView su iOS 6 funziona finalmente.

Come si può fare? È una pura soluzione JS + Facebook JS SDK + UIWebView Delegate.

JS - Primo passo)

un pulsante di accesso (per la connessione con facebook) chiama questa funzione ad esempio, che attiverà Viso JS finestre di dialogo di login/OAuth:

function loginWithFacebookClick(){ 

FB.login(function(response){ 
    //normal browsers callback 
}); 

} 

JS - Seconda fase)

aggiungere un listener authResponseChange ogni volta che l'utente carica la pagina Web (dopo FB.init()) per catturare stato di connessione dell'utente:

FB.Event.subscribe('auth.authResponse.Change', function(response){ 
//UIWebView login 'callback' handler 
var auth = response.authResponse; 
if(auth.status == 'connected'){ 
    //user is connected with facebook! just log him at your webapp 
} 
}); 

E con le funzioni di delegato UIWebView di applicazione è possibile handler facebook risposte OAuth

Objective C - Terzo passo)

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType 
{ 
NSString *url = [[request URL] absoluteString]; 

//when user status == connected (has a access_token at facebook oauth response) 
if([url hasPrefix:@"https://m.facebook.com/dialog/oauth"] && [url rangeOfString:@"access_token="].location != NSNotFound) 
{ 
    [self backToLastPage]; 
    return NO; 
} 

return YES; 
} 

- (void)webViewDidFinishLoad:(UIWebView *)webView 
{ 

NSString *url = [[webView.request URL] absoluteString]; 

if([url hasPrefix:@"https://m.facebook.com/dialog/oauth"]) 
{ 
    NSString *bodyHTML = [webView stringByEvaluatingJavaScriptFromString:@"document.body.innerHTML"]; 

    //Facebook oauth response dead end: is a blank body and a head with a script that does 
    //nothing. But if you got back to your last page, the handler of authResponseChange 
    //will catch a connected status if user did his login and auth app 
    if([bodyHTML isEqualToString:@""]) 
    { 
     [self backToLastPage]; 
    } 
} 

} 

Così, quando ' reindirizzare l'utente all'ultima pagina caricata, il secondo passo è l'azione dell'utente gestore nelle finestre di accesso di Facebook.

Se ho ottenuto troppo velocemente con questa risposta, per favore chiedimi! Spero che aiuti.

4

basta usare: questo codice

if (![FBSDKAccessToken currentAccessToken]) 
{ 
    FBSDKLoginManager *manager = [[FBSDKLoginManager alloc]init]; 
    manager.loginBehavior = FBSDKLoginBehaviorWeb; 
    [manager logInWithReadPermissions:@[@"public_profile", @"email", @"user_friends"] handler: 
    ^(FBSDKLoginManagerLoginResult *result, NSError *error) { 

     NSLog(@"result.token: %@",result.token.tokenString); 
     NSLog(@"%@",result.token.userID); 
     NSLog(@"%hhd",result.isCancelled);  
    }]; 
} 

// qui manager.loginBehavior = FBSDKLoginBehaviorWeb; è tutto ciò che serve ad aprire facebook in UIWebview

1

Nel caso qualcuno è googling, ecco cosa ha funzionato per 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.

A seconda dell'implementazione Web, è probabile che ci sia un ulteriore passaggio. Lo script di Facebook esegue effettivamente uno window.close() quindi uno window.open() quindi uno window.close(). Per me questo ha causato problemi perché sul lato web, dopo che questo login è stato completato, la mia finestra (cioè per la webView a cui voglio che l'utente si connetta) stava ottenendo una chiamata window.close(), proveniente dall'SDK di Facebook. Presumo che ciò avvenga perché l'SDK di Facebook si aspetta che la chiamata window.open() per aprire una nuova finestra che verrà chiusa.

Poiché non abbiamo eseguito l'override della funzionalità di window.open(), la chiamata a window.open() non farà nulla e l'SDK di Facebook tenterà di chiudere la finestra. Questo potrebbe causare tutti i tipi di problemi, ma per me dal momento che sto usando Parse, window.localStorage è stato impostato su null quindi ho ricevuto tutti i tipi di errori.

Se qualcosa di simile sta accadendo per voi, avete due opzioni per risolvere il problema:

  1. Se si ha il controllo del codice web, e il vostro giù per un piccolo hack, gettare questo in window.close=function(){}
  2. Se non si ha il controllo del codice Web, è possibile aggiungere una sovrascrittura a window.close per la visualizzazione Web principale come è stato fatto per la visualizzazione Web di popUp o sostituire la funzione window.open per aprire un altro pop-up (che è descritto in more detail here)
0

Come accedere a Facebook in UIWebView.

Objective-C

Usa taylorstine's answer. Ha salvato la mia giornata. Grazie taylorstine

Ma sto usando Swift 3. quindi ho appena convertito il codice di seguito dalla risposta di Taylor.

Swift 3.

func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, navigationType: UIWebViewNavigationType) -> Bool { 

    if let _ = request.url?.absoluteString.range(of: "m.facebook.com") { 
     if let _ = request.url?.absoluteString.range(of: "back"){ 
      self.popUp?.removeFromSuperview() 
      self.popUp = nil 
      return false 
     } 

     if let _ = self.popUp { 
      return true 
     } 

     let wv = popUpWebView() 
     wv.loadRequest(request) 

     return false 
    } 

    return true 
} 

func popUpWebView() -> UIWebView { 

    let webView = UIWebView(frame: self.view.frame) 

    webView.delegate = self 
    self.popUp = webView 
    self.view.addSubview(webView) 

    return webView 
} 

func webViewDidFinishLoad(_ webView: UIWebView) { 
    if let _ = self.popUp { 

     let jsFromFile = "window.close=function(){window.location.assign('back://' + window.location);};" 

     let _ = webView.stringByEvaluatingJavaScript(from: jsFromFile) 

     let openerContext = self.webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext 

     let popupContext = webView.value(forKeyPath: "documentView.webView.mainFrame.javaScriptContext") as! JSContext 

     popupContext.setObject("opener", forKeyedSubscript: "window" as (NSCopying & NSObjectProtocol)!) 
     popupContext.setObject(openerContext.objectForKeyedSubscript("window"), forKeyedSubscript: "opener" as (NSCopying & NSObjectProtocol)!) 

    } 

    if webView == self.popUp 
     && (webView.request?.url?.absoluteString.range(of:"m.facebook.com") != nil) 
     && webView.stringByEvaluatingJavaScript(from: "document.body.innerHTML") == "" { 

     webView.stringByEvaluatingJavaScript(from: "eval(document.getElementsByTagName('script')[0].text)") 

    } 

}