網頁

2012年12月21日 星期五

【facebook SDK 3.1】教程2-登入,認證,登出

【環境:xCode4.5 , ios6 , USE ARC】
facebook app what is NEW:【facebook SDK 3.1】what is NEW?

facebook app的基本設定,請參考:【facebook SDK 3.1】教程1-設定

說明:
這篇文章,主要在說明,登入-->驗證-->登出 等步驟說明。
若有需要基本設定等,請參考上面文章。

目前facebook login共有三種,現在說明的是目前2012釋放的版本教學。

在新本的SDK 3.1中,若用戶嘗試登入facebook,facebook SDK將會針對目前用戶的設定,選擇最佳的登入方式。
若用戶已經給與ios app權限,SDK將會立即取得token。

現在讓我們開始享受coding的流程吧...

step 1 : include the Facebook SDK
首先建立一個uiviewcontroller,命名為login,將此view設定為windows的rootviewcontroller。
分別在login.m和delegate.m下加入
#import <FacebookSDK/FacebookSDK.h>

step 2 : impelment the login flow

1.在login.m中建立一個uibutton名稱自定,若要跟下面所講的內容一樣的話,那就authButton

2.開啓你的delegate.h檔,建立一個全域變數
extern NSString *const FBSessionStateChangedNotification; 


3.開啓你的delegate.m檔,並定義一個notification string
NSString *const FBSessionStateChangedNotification =
    @"com.example.Login:FBSessionStateChangedNotification";


你要注意的是『com.example.Login』這是你iOS app的bundle id…..

4.接下來,將下列兩個方法放到你的delegate.m中
/*
 * Callback for session changes.
 */
- (void)sessionStateChanged:(FBSession *)session
                      state:(FBSessionState) state
                      error:(NSError *)error
{
    switch (state) {
        case FBSessionStateOpen:
            if (!error) {
                // We have a valid session
                NSLog(@"User session found");
            }
            break;
        case FBSessionStateClosed:
        case FBSessionStateClosedLoginFailed:
            [FBSession.activeSession closeAndClearTokenInformation];
            break;
        default:
            break;
    }
    
    [[NSNotificationCenter defaultCenter]
     postNotificationName:FBSessionStateChangedNotification
     object:session];
    
    if (error) {
        UIAlertView *alertView = [[UIAlertView alloc]
                                  initWithTitle:@"Error"
                                  message:error.localizedDescription
                                  delegate:nil
                                  cancelButtonTitle:@"OK"
                                  otherButtonTitles:nil];
        [alertView show];
    }
}

/*
 * Opens a Facebook session and optionally shows the login UX.
 */
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
    return [FBSession openActiveSessionWithReadPermissions:nil
                                          allowLoginUI:allowLoginUI
                                     completionHandler:^(FBSession *session,
                                                         FBSessionState state,
                                                         NSError *error) {
                                         [self sessionStateChanged:session
                                                             state:state
                                                             error:error];
                                     }];
}

5.在你的.h檔中加入
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI;

6.若你需要額外的權限,修改openSessionWithAllowLoginUI:方法

ex:要求email 和 user_likes 的用戶權限
- (BOOL)openSessionWithAllowLoginUI:(BOOL)allowLoginUI {
    NSArray *permissions = [[NSArray alloc] initWithObjects:
        @"email", 
        @"user_likes",
        nil];
    return [FBSession openActiveSessionWithReadPermissions:permissions
                                              allowLoginUI:allowLoginUI
                                         completionHandler:^(FBSession *session,
                                                         FBSessionState state,
                                                         NSError *error) {
                                         [self sessionStateChanged:session
                                                             state:state
                                                             error:error];
                                     }];
}

7.若你需要寫入的權限,如:public_actions,你必須使用
reauthorizeWithPermissions:defaultAudience:completionHandler: 

permissions guide會有更多相關訊息

8.login flow最大的不同點在於 iOS 6+ 與 早期的iOS版本 兩者。
在iOS 6中,登入時,你的app將傳遞控制權給Facebook iOS app or 手機瀏覽器中的Facebook。
當使用者認證後,控制權將返回給你的app,同時夾帶session的資訊在編碼過的URL中。
為了記錄這些資訊,你需要給在返回的url中做一些處理,在ios6+中,login flow從ios中取得用戶的證書,用戶不需傳送資訊到facebook app。

9.在delegate.m中,分別找到對應的位置,把下面的code塞進去
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {
    // attempt to extract a token from the url
    return [FBSession.activeSession handleOpenURL:url];
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    [FBSession.activeSession handleDidBecomeActive];
}

- (void)applicationWillTerminate:(UIApplication *)application
{
    [FBSession.activeSession close];
}

10.在你的login.m中
#import "AppDelegate.h"

並將剛剛設定好的button的action,寫成
- (void)authButtonAction
{
    AppDelegate *appDelegate =
    [[UIApplication sharedApplication] delegate];
    
    // If the user is authenticated, log out when the button is clicked.
    // If the user is not authenticated, log in when the button is clicked.
    if (FBSession.activeSession.isOpen) {
        [appDelegate closeSession];
    } else {
        // The user has initiated a login, so call the openSession method
        // and show the login UX if necessary.
        [appDelegate openSessionWithAllowLoginUI:YES];
    }
} 

此時你run project的話會看到兩種畫面,
『根據你的設定會有所不同:有無使用ios 6 內建的facebook帳號登入』
並在log中看到
2012-12-21 18:56:16.832 facebooktest[2725:19a03] User session found

到了這一步...你已經完成了登入+驗證的程序

step 3 : impelment the logout flow

1.在delegate.m中
- (void) closeSession {
    [FBSession.activeSession closeAndClearTokenInformation];
} 

2.在delegate.h中
- (void) closeSession; 

3.改寫你的- (void)authButtonAction
- (void)authButtonAction
{
    AppDelegate *appDelegate =
    [[UIApplication sharedApplication] delegate];
    
    // If the user is authenticated, log out when the button is clicked.
    // If the user is not authenticated, log in when the button is clicked.
    if (FBSession.activeSession.isOpen) {
        [appDelegate closeSession];
    } else {
        // The user has initiated a login, so call the openSession method
        // and show the login UX if necessary.
        [appDelegate openSessionWithAllowLoginUI:YES];
    }
} 

4.在login.m中的viewdidload中
[[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(sessionStateChanged:)
     name:FBSessionStateChangedNotification
     object:nil];

5.在login.m中的- (void)didReceiveMemoryWarning
 
[[NSNotificationCenter defaultCenter] removeObserver:self];

6.在login.n中添加此方法
 
- (void)sessionStateChanged:(NSNotification*)notification {
    if (FBSession.activeSession.isOpen) {
        [self.authButton setTitle:@"Logout" forState:UIControlStateNormal];
    } else {
        [self.authButton setTitle:@"Login" forState:UIControlStateNormal];
    }
}

7.在login.m中的viewdidload中的最後面加上
 
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate openSessionWithAllowLoginUI:NO];


==
到這邊就完成了自建的登入、驗證、註冊...等動作
當然facebook sdk中也有提供login ui的api
不過就不像這種彈性方式了~

最後若有error,請檢查facebook app的設定是否正確.
ex:bundle id沒有設定好,請參考前面的設定文章


As always , if you have any question , feel free to contact me.
有任何問題,請聯絡我

歡迎轉載,請註明出處,感謝。

16 則留言:

  1. 感謝分享這麼有用的資訊~讚喔!!!

    回覆刪除
  2. 您好

    我想請問一下

    我使用的SDK版本為5.1

    裡面並沒有Social.framework

    第四步開始就會出錯

    這跟framework有關係嗎?

    回覆刪除
    回覆
    1. 基本上....Social.framework 在設定時可選optional
      針對6以下版本相容
      所以應該不是你說的那個問題

      或許你仔細看他的error log應該就可以知道,問題出在哪

      刪除
    2. 針對6,6以下ios版本
      均測試過~
      分享..等功能也ok

      若要說,唯一的缺點就是
      當你用ios6的facebook登入後,分享
      程式不關掉,縮入背景
      去設定中,把facebook的賬號刪除...
      此時因為你的ios app抓session已經抓到原本ios的session權限認證

      故分享時會無法分享
      但重新關掉app,打開後再分享,會重新用利用sheme的方式,取得fbsession
      不過一般人應該不會這樣測試

      刪除
    3. 關於你說的"唯一的缺點",
      小弟我剛吃了這個苦頭,
      浪費了半天的時間,
      一直以為我的code有bug,
      搜到這裡,才了解真相~ 感謝!

      刪除
    4. 我是用fb sdk 3.1.1
      看了很多網路上的討論來解決這個問題,
      但是都沒效,
      不知道你後來解決了嗎?

      刪除
    5. 在UIApplication喚醒app的地方
      判斷目前FBSession的狀態
      讓app立即重新抓取session

      讓安全機制好點是不錯
      但是或許應該考量到『用戶』會不會像測試者一樣無聊

      寫程式和企劃常常會陷入,用戶用不太到,但是卻一股腦兒把一堆功能塞進去的窘境

      刪除
  3. 請問你是說哪一階段的第四步

    回覆刪除
    回覆
    1. 您好

      是這篇的4

      加入Code之後會錯

      有google過error

      得到的答案都是要升XCode4.5+SDK6.0 Q_Q

      刪除
    2. 遺憾的是...
      我這篇文章
      只到step3...

      刪除
    3. 我表達錯誤QQ

      是step2的4...|||

      刪除
    4. Undefined symbols for architecture armv7:
      "_ACFacebookAudienceFriends", referenced from:
      -[FBSession authorizeUsingSystemAccountStore:accountType:permissions:defaultAudience:isReauthorize:] in FacebookSDK(FBSession.o)
      "_ACFacebookAppIdKey", referenced from:
      -[FBSession authorizeUsingSystemAccountStore:accountType:permissions:defaultAudience:isReauthorize:] in FacebookSDK(FBSession.o)
      "_ACAccountTypeIdentifierFacebook", referenced from:
      +[FBSession renewSystemAuthorization] in FacebookSDK(FBSession.o)
      "_ACFacebookAudienceKey", referenced from:
      -[FBSession authorizeUsingSystemAccountStore:accountType:permissions:defaultAudience:isReauthorize:] in FacebookSDK(FBSession.o)
      "_ACFacebookAudienceOnlyMe", referenced from:
      -[FBSession authorizeUsingSystemAccountStore:accountType:permissions:defaultAudience:isReauthorize:] in FacebookSDK(FBSession.o)
      "_ACFacebookPermissionsKey", referenced from:
      -[FBSession authorizeUsingSystemAccountStore:accountType:permissions:defaultAudience:isReauthorize:] in FacebookSDK(FBSession.o)
      "_OBJC_CLASS_$_ASIdentifierManager", referenced from:
      objc-class-ref in FacebookSDK(FBSettings.o)
      "_ACFacebookAudienceEveryone", referenced from:
      -[FBSession authorizeUsingSystemAccountStore:accountType:permissions:defaultAudience:isReauthorize:] in FacebookSDK(FBSession.o)
      ld: symbol(s) not found for architecture armv7
      clang: error: linker command failed with exit code 1 (use -v to see invocation)

      刪除
  4. 你好 看過你的文章後獲益良多
    已經將 facebook login 的部份加入我的 app 中
    但有個問題我一直卡住
    想向你詢問看看

    我希望的狀況是
    除了第一次按 login 會導出 app 外 尋問權限的確認
    之後再進來 app 中 就算是關掉過app後 仍直接是 登入狀態
    除非使用者有按 logout 按鈕

    但我目前的情況是
    每次新進到 app 的時候 都會是未登入的狀態
    需要再按一次 login 導出去 但導到權限確認頁時 都是說已經確認過 直接按確定就會再導回 app
    這樣每次都需要多按一次
    我希望可以保持 facebook 登入狀態

    把 FBSession.activeSession.accessToken 跟 FBSession.activeSession.expirationDate 存起來應該也不太對
    這兩個值應該都不是固定的
    請問有沒有什麼地方我遺漏掉了
    謝謝~




    回覆刪除
  5. 謝謝你的分享~
    不過有問題想請教一下,當我在首次登入時,選擇不同意的話,
    是不是只有從"設定"裡的"facebook"中,將App改成允許呢?

    有沒有辦法在點選不同意後,再一次點選登入時,再一次詢問他同不同意?

    謝謝~

    回覆刪除
  6. hi,N11!
    请问在iPhone手机上,使用facebook的sdk,实现一个分享功能的思路是怎样的呢?
    不使用ios6本身的集成(Social Framwork或者ActivityController等),分享功能是向下兼容的,包括ios5的手机

    回覆刪除