2014年5月13日 星期二

[IOS] 使用 FacebookSDK 實作 Facebook 登入 (二)

延續 [IOS] 使用 FacebookSDK 實作 Facebook 登入 (一) 的內容,上一篇我們做了這些事:

  • 建立 App 以及申請 Facebook 的 App
  • 加入 FacebookSDK 到專案裡面
  • 設定 .plist

這篇我們會按照 Facebook Login for iOS 這篇的教學,繼續進行製作 Facebook Login 的功能 (使用 Facebook Login 的按鈕)。



1. 增加 Facebook 的 Login UI Control

在你需要置入 Facebook Login 按鈕的 controller 的 .h 檔案 (以我的例子來說,我是在我的 rootViewController 加上 Facebook Login Button ) 把 FacebookSDK import 進來: (同樣的事情也請在 AppDelegate.h 做一次)
#import <UIKit/UIKit.h>
#import <FacebookSDK/FacebookSDK.h>

@interface rootViewController : UIViewController

@end


接著在該 controller 的實作檔 (.m),初始化一個 FBLoginView: (通常我都是放在 
viewDidLoad 裡面)


//此段參考自 developers.facebook.com
FBLoginView *loginView = [[FBLoginView alloc] init];
[self.view addSubview:loginView];
其實現在只要按 Build,你就會看到 Login Button 了,但是事情沒有這麼簡單,繼續往下走。



當我們把 Login 按鈕擺到畫面上之後,編輯 AppDelegate.m的 didFinishLaunchingWithOptions,新增以下幾行 code:
( 為了在視圖顯示之前,先執行 FBLoginView Class )
//此段參考自 developers.facebook.com
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    [FBLoginView class];
    ... 你可以會在這裡設定你的 window.self.rootViewController 等...
    return YES;
}


2. 處理 Facebook App 給你的 response
在 AppDelegate.m 的下方加上這段 Code:
//此段參考自 developers.facebook.com
  - (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
  sourceApplication:(NSString *)sourceApplication
         annotation:(id)annotation {

        // Call FBAppCall's handleOpenURL:sourceApplication to handle Facebook app responses
        BOOL wasHandled = [FBAppCall handleOpenURL:url sourceApplication:sourceApplication];

        // You can add your app-specific url handling code here if needed

        return wasHandled;
    }

3. 要求取得使用者的其他 email 以及 user_friends


當有人要用 Facebook 登入到你的 App 時,App 可以取得該用戶的一些公開資訊 (public profile),APP 取的該用戶的資訊只有讀的權限,至於其他的資訊,是要分開去要這些權限,比方說想要取得使用者的 email,他就必須同意給你讀取 email 的權限 (permission)(ex: email, user_friends)


你可以比較左圖跟右圖的差別,通常如果沒有 initWithReadPermission 加入其他項目,就只會像左圖那樣,只要 user 的 public profile,如何做到右圖那樣,連 user_friends 以及 email 都要呢,就繼續往下看。




修改前面 (第1點) 加入的 loginView,把   FBLoginView *loginView = [[FBLoginView alloc] init];  改成以下,除了取得 public_profile 之外,額外加上取得 email 跟 user_friends 的讀取權限。
//此段參考自 developers.facebook.com
FBLoginView *loginView = 
    [[FBLoginView alloc] initWithReadPermissions:
        @[@"public_profile", @"email", @"user_friends"]];

4. 處理 authentication callback

使用者的登入, 登出, 錯誤處理, 取得該使用者的資料等等,會有適合的 method 可以處理,包含以下三個 delegate method 以及一個 method:

loginViewFetchedUserInfo:user: delegate method.
如果你有實做 loginViewFetchedUserInfo:user 這個方法,當 user 透過 FB 登入後會取得他的 public profile,你可以透過這個 method 收到通知。

loginViewShowingLoggedInUser: method.
如果該使用者已經是登入狀態,則會送出 nofi 給這個 method.

loginViewShowingLoggedOutUser: delegate method.
如果使用者已經登出,則會送出 nofi 給這個 method.

loginView:handleError: delegate method.
如果有什麼錯誤,則會送出這個 nofi 給 loginView:handleError: 這個 method


我們為了要測試這些 callback 的結果,可以在畫面加上一些 layout,進而用來顯示登入狀態(statusLabel), user 的 avatar (profilePictureView), 以及使用者名稱 (nameLabel),在你要顯示 Login Button 的 controller.h 加上這幾個 layouts:


ex: 比方說我加入 login button 的 controller 名為 rootViewController,則是編輯 rootViewController.xib

拖曳一個 view, 兩個 label 到 xib 的 view



結果如下 : (位置可自行調整)




點到 view,設定這個 view 的 class 為 FBProfilePictureView



但因為 FBProfilePictureView 是用來抓取 Facebook 的頭像,我們要再傳遞 class 的訊息給 FBProfilePictureView ([FBProfilePictureView  Class]),回到 AppDelegate.m,補上這行: (如果你有要顯示圖像,並且會使用到 FBProfilePictureView 的話,務必要補上這一段,否則編譯時可能就出錯了,我已經踩過這個雷了 T-T)




切換編輯器的模式為 show the Assistant editor,使畫面呈現為左邊是 .xib, 右邊是 .h 檔






接著把畫面上的三個元素,關聯到 .h 檔,按住按盤的 control 鍵不放,拖曳該到 .h 檔,並設定正確的 Name:











另外再到 .h 檔補上 FBLoginViewDelegate delegate:

//此段參考自 developers.facebook.com
@interface rootViewController : UIViewController <FBLoginViewDelegate>
@property (strongnonatomicIBOutlet FBProfilePictureView *profilePictureView;
@property (strongnonatomicIBOutlet UILabel *nameLabel;
@property (strongnonatomicIBOutlet UILabel *statusLabel;


@end



接著我又回到我的實作檔 (.m),指定 delegate 給我的 view controller class,在 FBLoginView *loginView 下方加上 loginView.delegate = self; ,以下是目前的程式碼:







實現幾個 delegate 的方法,在 rootViewController.m (應該說是你實作 login button 的 controller 的 .m 檔),加上以下幾個 method 的 code:

loginViewFetchedUserInfo:user:
//此段參考自 developers.facebook.com
// 當取得到使用者的 user profile 之後,這個 method 就會被呼叫
- (void)loginViewFetchedUserInfo:(FBLoginView *)loginView
                            user:(id<FBGraphUser>)user {
  //將 layout 是 profilePictureView 將會顯示使用者的大頭照
  self.profilePictureView.profileID = user.id;
  //nameLabel 的內容將會改變成使用者的名稱
  self.nameLabel.text = user.name;
}

loginViewShowingLoggedInUser: 
//此段參考自 developers.facebook.com
// Logged-in user experience
- (void)loginViewShowingLoggedInUser:(FBLoginView *)loginView {
  self.statusLabel.text = @"You're logged in as";
}

loginViewShowingLoggedOutUser:
//此段參考自 developers.facebook.com
// Logged-out user experience
- (void)loginViewShowingLoggedOutUser:(FBLoginView *)loginView {
  //使用者未登入,profilePictureView.profileId 沒有值
  self.profilePictureView.profileID = nil;
  //使用者未登入,將 nameLabel 的值清空
  self.nameLabel.text = @"";
  self.statusLabel.text= @"你還沒登入";
}
loginView:handleError:
handleError 因為內容太長了,就請自行到官網上 copy / paste。




5. 測試 Login

按下左上角的 Build,跑一下登入流程






參考:

https://developers.facebook.com/docs/facebook-login/ios/v2.0



5 則留言:

  1. 非常感謝大大的分享,讓我節省了許多翻譯文章的時間~

    回覆刪除
  2. 謝謝大大,受益良多
    目前對英文還沒有駕馭的很好><

    回覆刪除
    回覆
    1. 不客氣,很久沒寫 ios 了,希望有幫上你忙

      刪除
  3. 感谢;虽然已粗略看过官方文档,但文档支线比较多,如果只是实现登陆,不如你们的文档有有效快捷。

    回覆刪除

若你看的文章,時間太久遠的問題就別問了,因為我應該也忘了... XD

Vue multiselect set autofocus and tinymce set autofocus

要在畫面一進來 focus multiselect 的方式: 參考: https://jsfiddle.net/shentao/mnphdt2g/ 主要就是在 multiselect 的 tag 加上 ref (例如: my_multiselect), 另外在 mounted...