2012-11-09 12 views
6

Mamy:
(1) Facebook API oparte aplikacji internetowych z funkcjonalnością Facebook OAuth („aplikacji internetowej FB”)
(2) UIWebView -na przeglądarki na iPada („przeglądarka”)Jak mogę uzyskać UIWebView, aby otworzyć stronę logowania do Facebooka w odpowiedzi na żądanie OAuth na iOS 5 i iOS 6?

Nasz celem jest otwarcie strony logowania na Facebooku, aby zalogować się do aplikacji internetowej FB (1) w przeglądarce opartej na UIWebView (2) na iPadzie.

Jest nieco podobny problem tutaj:
http://facebook.stackoverflow.com/questions/11337285/no-longer-able-to-login-to-ios-app-via-oauth-the-page-requested-was-not-found

Jednak kwestia tego pytania dzieje się po wprowadzeniu przez użytkownika loginu i hasła w postaci Facebooku. Naszym problemem jest to, że nie możemy w pierwszej kolejności wyświetlić formularza logowania na Facebooku. Zmiana typu aplikacji na "Sieć" na "Natywny/komputer", jak sugerowano w tym pytaniu, nie pomogła.

Kroki: 1. Otwórz
nasza strona internetowa (prosta strona HTML) z tym UIWebView Browser
2. Kliknij na „FB” przycisk web app uruchomić na tej stronie
3. OnClick JavaScript próbuje zainicjować OAuth, które powinny otworzyć ekran logowania Facebook, aby zalogować się do aplikacji internetowej FB

Aktualny wyników (wydania)
iOS 5. + i iOS 6. + urządzenia
- Nasza strona internetowa pozostaje niezmieniona
- Strona logowania na Facebooku to N OT pokazane (nasza strona internetowa jest nadal wyświetlany)
iOS 4.3 (działa zgodnie z oczekiwaniami):
- strona logowania Facebook otwiera się w tym samym UIWebView przedmiotu Browser (zastępuje naszą stronę internetową)

Oczekiwany wynik :
- Wyświetlana jest strona logowania do Facebooka, a użytkownik może wprowadzić hasło do Facebooka & hasło - Działa na iOS 5. + i iOS 6. +, jeśli uruchomiono go w przeglądarce Safari na iPadzie. Facebook strona logowania jest otwarty na osobnej karcie (w przeciwieństwie do tego, nie ma oddzielnych kart w UIWebView)

Pytanie: Jak mogę uzyskać Facebook UIWebView otworzyć stronę logowania w odpowiedzi na żądanie OAuth na iOS 5+ i iOS 6 +?

Więcej szczegółów technicznych:

Logujemy różne NSURLRequest pola od wewnątrz

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

I zauważyć pewne różnice w dziennikach dla „poprawnych” i „niewłaściwych” zachowań. Oto jak wyglądają przepływy wykonanie dla mnie:

Po pierwsze, naciśnij „FB Web App” przycisk uruchamiania, aby zainicjować OAuth, a następnie niektóre przypadki przejść

iOS 4.3, „poprawne”
żądanie www.facebook.com/dialog/oauth? ...
wniosek do fbwebapp.com
wniosek do m.facebook.com/login.php? ....
--here facebook logowanie pojawia

iOS 5.0 „incorrect1”
żądanie www.facebook.com/dialog/oauth? ...
żądanie fbwebapp.com
żądanie m.facebook. com/login.php? ...

to może być
-A dużo m.facebook.com/login.php?...with następnego ... w parametrach
następnie błędu sqlite
- Teraz widzę "Przepraszam, coś poszło nie tak" pa ge z Facebook (jest to pierwszy raz w ogóle spotykam go)

iOS 6.0 „incorrect2”
żądanie www.facebook.com/dialog/oauth? ...
żądanie fbwebapp.com

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

Możesz zobaczyć, że to zachowanie zdecydowanie zależy od wersji iOS. Ale często zdarza się, że błąd występuje na etapie uzyskiwania adresu URL m.facebook.com/login.php .. Ale to wszystko, co możemy wykryć.

Pociskamy głową o ścianę przez cały dzień szukając rozwiązań. Beznadziejnie.
Czy możesz pomóc nam otworzyć stronę logowania na Facebooku w numerze UIWebView w odpowiedzi na OAuth?

Odpowiedz

0

Użyj klasy FBDialog, aby wyświetlić monit o zalogowanie. Ten wykorzystuje webview wewnątrz aplikacji, dlatego na udanym logowaniu użytkownik zostanie zalogowany wewnątrz każdej 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]; 

następnie dokonaj klasa przylegają do protokołu FBDialogDelegate i dodać tę funkcję do swojej klasie:

-(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

, można powiedzieć coś więcej o tym rozwiązaniu? Jestem początkującym użytkownikiem iOS, ale wypróbowałem już niektóre próbki SDK Facebooka. See you – owlmsj

3

Zrobiłem to!

To trochę hack, ale js facebook sdk login na UiWebView na iOS 6 w końcu działa.

Jak to można zrobić? Jest to czyste rozwiązanie do obsługi funkcji JS + Facebook JS SDK + UIWebView Delegate.

JS - pierwszy etap)

przycisk Login (do połączenia z Facebook) nazywa to przykład funkcji, która będzie wyzwalać twarzy JS dialogi login/OAuth:

function loginWithFacebookClick(){ 

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

} 

JS - Drugi etap)

dodać detektora authResponseChange za każdym razem, gdy użytkownik ładuje stronę (po FB.init()), aby złapać podłączonego status użytkownika:

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 
} 
}); 

I z UIWebView funkcji delegata aplikacji można handler facebook odpowiedzi OAuth

Objective C - Trzeci etap)

- (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]; 
    } 
} 

} 

Więc, gdy " przekieruj 'użytkownika do ostatniej wczytanej strony, drugi krok będzie obsługiwać akcję użytkownika w oknie dialogowym logowania na facebooku.

Jeśli mam zbyt szybko z tą odpowiedzią, proszę pytaj mnie! Mam nadzieję, że to pomaga.

4

wystarczy użyć: ten kod

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);  
    }]; 
} 

// tutaj manager.loginBehavior = FBSDKLoginBehaviorWeb; jest wszystko, czego potrzeba, aby otworzyć facebook w UIWebview

1

W przypadku gdy ktoś jest googlowania, oto co pracował dla mnie:

-(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.

W zależności od implementacji strony internetowej prawdopodobnie wystąpi jeden dodatkowy krok. Skrypt na Facebooku faktycznie wykonuje window.close(), a następnie window.open(), a następnie window.close(). Dla mnie było to przyczyną problemów, ponieważ po stronie internetowej, po zakończeniu tego logowania, moje okno (tj. Dla webView, do którego chcę się zalogować) otrzymało wywołanie window.close() pochodzące z pakietu SDK Facebooka. Zakładam, że dzieje się tak dlatego, że pakiet SDK Facebooka oczekuje wywołania window.open(), aby otworzyć nowe okno, które zostanie zamknięte.

Ponieważ nie zastąpiliśmy funkcji window.open(), wywołanie window.open() nic nie da, a pakiet SDK Facebooka podejmie próbę zamknięcia okna. Może to powodować wszelkiego rodzaju problemy, ale dla mnie, ponieważ używam Parse, window.localStorage został ustawiony na null, więc otrzymywałem różnego rodzaju błędy.

Jeśli coś takiego dzieje się dla ciebie, masz dwie opcje, aby je naprawić:

  1. Jeśli masz kontrolę nad kodem internetowej, a dół za niewielką siekać, rzuć to w window.close=function(){}
  2. Jeśli nie masz kontroli nad kodem sieci, możesz dodać nadpisanie do window.close dla głównego webView, tak jak zrobiliśmy dla webview popUp, lub zastąpić funkcję window.open, aby otworzyć inne popUp (które jest opisane w more detail here)
0

Jak zalogować się na facebooku w UIWebView.

Cel C

Zastosowanie taylorstine's answer. Uratował mi dzień. Dziękuję taylorstine

Ale używam Swift 3. więc po prostu konwertowałem kod poniżej z odpowiedzi taylorstine.

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)") 

    } 

}