2012-11-09 44 views
6

Chúng tôi có:
(1) Facebook API dựa trên ứng dụng web với chức năng Facebook OAuth (“các ứng dụng web FB”)
(2) UIWebView trình duyệt dựa trên trên iPad (“Browser”)Tôi làm cách nào để có UIWebView mở trang đăng nhập Facebook theo yêu cầu OAuth trên iOS 5 và iOS 6?

chúng tôi mục tiêu là mở trang Đăng nhập Facebook để đăng nhập vào ứng dụng web FB (1) bên trong Trình duyệt dựa trên UIWebView (2) trên iPad.

Có một vấn đề tương tự như ở đây:
http://facebook.stackoverflow.com/questions/11337285/no-longer-able-to-login-to-ios-app-via-oauth-the-page-requested-was-not-found

Tuy nhiên, vấn đề của câu hỏi đó xảy ra sau khi người dùng nhập vào đăng nhập và mật khẩu vào form Facebook. Vấn đề của chúng tôi là chúng tôi không thể nhận được mẫu đăng nhập Facebook được hiển thị ngay từ đầu. Thay đổi loại ứng dụng từ "Web" thành "Native/Desktop", như được đề xuất trong câu hỏi đó, không giúp được gì.

bước:
1. Mở trang web (đơn giản trang HTML) của chúng tôi với UIWebView Trình duyệt này
2. Nhấp vào nút khởi động “FB ứng dụng web” trên trang này cố gắng
3. OnClick hoạt Javascript để khởi OAuth, mà nên mở màn hình đăng nhập của Facebook để đăng nhập vào ứng dụng FB web

kết quả hiện tại (vấn đề):
trên iOS 5. + và iOS 6. + thiết bị
- trang web của chúng tôi vẫn không thay đổi
- Trang đăng nhập Facebook là N OT hiển thị (trang web của chúng tôi vẫn còn hiển thị)
Trên iOS 4.3 (chỉ hoạt động như dự kiến):
- trang đăng nhập Facebook được mở trong đối tượng UIWebView cùng của trình duyệt (thay thế trang web của chúng tôi)

Kết quả mong đợi :
- Trang đăng nhập Facebook được hiển thị và người dùng có thể nhập thông tin đăng nhập Facebook & mật khẩu
- Hoạt động trên iOS 5. + và iOS 6. + nếu được khởi chạy trong trình duyệt Safari trên iPad. Trang đăng nhập Facebook được mở trong một tab riêng (ngược lại, không có các tab riêng biệt trong UIWebView)

Câu hỏi: Làm cách nào để có được UIWebView để mở trang đăng nhập Facebook theo yêu cầu OAuth trên iOS 5+ và iOS 6 +?

Chi tiết kỹ thuật:

Chúng tôi đăng nhập khác nhau NSURLRequest lĩnh vực từ bên trong

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

Và chúng tôi nhận thấy một số khác biệt trong các bản ghi cho “đúng” và hành vi “không chính xác”. Dưới đây như thế nào thực hiện dòng tìm kiếm tôi:

Thứ nhất, tôi nhấn nút “FB Web App” khởi động để bắt đầu OAuth, sau đó một số trường hợp đi

iOS 4.3, “đúng”
yêu cầu www.facebook.com/dialog/oauth? ...
yêu cầu fbwebapp.com
yêu cầu tới m.facebook.com/login.php? ....
--here facebook đăng nhập xuất hiện

iOS 5.0, “incorrect1”
yêu cầu www.facebook.com/dialog/oauth? ...
yêu cầu fbwebapp.com
yêu cầu m.facebook. com/login.php? ...

sau đó, nó có thể
nhiều --một của m.facebook.com/login.php?...with tiếp theo ... trong thông số
tiếp theo lỗi sqlite
- ngay bây giờ tôi thấy "Xin lỗi, có gì đó không ổn" ge từ facebook (đây là thời điểm đầu tiên ở tất cả tôi gặp nó)

iOS 6.0 “incorrect2”
yêu cầu www.facebook.com/dialog/oauth? ...
yêu cầu fbwebapp.com

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

Bạn có thể thấy hành vi đó chắc chắn phụ thuộc vào phiên bản iOS. Nhưng trường hợp phổ biến là lỗi xảy ra trên bước nhận m.facebook.com/login.php .. URL. Nhưng đó là tất cả những gì chúng tôi có thể phát hiện.

Chúng tôi đang đập đầu vào bức tường đó cho cả ngày tìm kiếm giải pháp. Vô vọng.
Bạn có thể giúp chúng tôi mở trang Đăng nhập Facebook trong UIWebView để phản hồi lại OAuth không?

Trả lời

0

Sử dụng lớp FBDialog để nhắc người dùng đăng nhập. Này sử dụng một webview bên trong ứng dụng, do đó về đăng nhập thành công, người dùng sẽ được đăng nhập bên trong của bất kỳ 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]; 

Sau đó, làm cho lớp học của bạn tuân theo các giao thức FBDialogDelegate, và thêm chức năng này để lớp học của bạn:

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

, bạn có thể giải thích thêm về giải pháp này? Tôi là một newbie tại iOS, nhưng đã thử một số mẫu SDK của Facebook. Xem ya – owlmsj

3

Đã làm!

Đó là một hack, nhưng đăng nhập facebook sdk js trên UiWebView tại iOS 6 cuối cùng cũng hoạt động.

Làm cách nào để thực hiện? Đây là một giải pháp JS + Facebook JS SDK + UIWebView Delegate xử lý các giải pháp chức năng.

JS - Bước đầu tiên)

một nút đăng nhập (để kết nối với facebook) gọi chức năng này ví dụ, sẽ kích hoạt Mặt JS hộp thoại đăng nhập/oauth:

function loginWithFacebookClick(){ 

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

} 

JS - Bước thứ hai)

thêm người nghe authResponseChange mỗi khi người dùng tải trang web (sau FB.init()) để đón tình trạng kết nối của người dùng:

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

VÀ với chức năng đại biểu UIWebView ứng dụng của bạn có thể xử lý facebook phản ứng oauth

Objective C - Bước thứ ba)

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

} 

Vì vậy, khi ' chuyển hướng người dùng đến trang được tải cuối cùng, bước thứ hai sẽ xử lý hành động của người dùng tại hộp thoại đăng nhập facebook.

Nếu tôi quá nhanh với câu trả lời này, hãy hỏi tôi! Hy vọng điều đó sẽ hữu ích.

4

chỉ cần sử dụng: mã này

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

// đây manager.loginBehavior = FBSDKLoginBehaviorWeb; là tất cả các bạn cần phải mở facebook trong UIWebview

1

Trong trường hợp bất cứ ai được googling, đây là những gì làm việc cho tôi:

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

Tùy thuộc vào việc triển khai web của bạn, có khả năng sẽ có thêm một bước. Tập lệnh Facebook thực sự thực hiện một số window.close() rồi sau đó là window.open(), sau đó là window.close(). Đối với tôi, điều này gây ra sự cố bởi vì ở phía web, sau khi đăng nhập này hoàn tất, cửa sổ của tôi (tức là cho webView mà tôi muốn người dùng đăng nhập) nhận được cuộc gọi window.close(), đến từ Facebook SDK. Tôi giả định điều này là bởi vì SDK của Facebook mong rằng window.open() gọi để mở một cửa sổ mới mà nó sẽ đóng lại.

Vì chúng tôi đã không ghi đè chức năng của window.open(), gọi window.open() sẽ không làm bất kỳ điều gì và Facebook SDK sẽ cố gắng đóng cửa sổ của bạn. Điều này có thể gây ra tất cả các loại vấn đề, nhưng đối với tôi vì tôi đang sử dụng Parse, window.localStorage được đặt thành null vì vậy tôi đã gặp phải tất cả các loại lỗi.

Nếu một cái gì đó như thế này đang xảy ra cho bạn, bạn có hai lựa chọn để sửa chữa nó:

  1. Nếu bạn có quyền kiểm soát của mã web, và xuống của bạn cho một hack nhỏ, ném này trong window.close=function(){}
  2. Nếu bạn không có quyền kiểm soát mã web, bạn có thể thêm ghi đè lên window.close cho webView chính như chúng tôi đã làm cho webView popUp hoặc ghi đè chức năng window.open để mở một cửa sổ bật lên khác (được mô tả trong more detail here)
0

Cách đăng nhập facebook trong UIWebView.

Objective-c

Sử dụng taylorstine's answer. Anh ấy đã cứu tôi trong ngày. Cảm ơn bạn taylorstine

Nhưng tôi đang sử dụng Swift 3. vì vậy tôi vừa chuyển đổi mã bên dưới từ câu trả lời của 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)") 

    } 

} 
Các vấn đề liên quan