FacebookSDK(4.1.x) 自定义登录 UI 按钮 - Swift(1.2)

Posted

技术标签:

【中文标题】FacebookSDK(4.1.x) 自定义登录 UI 按钮 - Swift(1.2)【英文标题】:FacebookSDK(4.1.x) Custom Login UI Button - Swift(1.2) 【发布时间】:2015-06-04 03:05:36 【问题描述】:

在this tutorial 之后,我设法使 Facebook 登录按钮正常工作。但是,它会自动从 SDK 分配按钮图像,并且无法自定义(因为它不是在 Storyboard 上创建的),因此我无法改用自己的按钮图像或文本。

我相信这部分代码(在 ViewDidLoad 中)正在分配按钮:

        let loginView : FBSDKLoginButton = FBSDKLoginButton()
        self.view.addSubview(loginView)
        loginView.center = self.view.center
        loginView.readPermissions = ["public_profile", "email"]
        loginView.delegate = self

我需要做的是在 Storyboard 上创建一个 @IBOutlet 按钮并从那里对其进行自定义。我该怎么做?

【问题讨论】:

【参考方案1】:

使用自定义按钮和访问令牌登录。

在 facebook sdk 4.x 中获取用户信息

斯威夫特

@IBAction func btnFBLoginPressed(sender: AnyObject) 
    var fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()
    fbLoginManager.logInWithReadPermissions(["email"], fromViewController: self, handler:  (result, error) -> Void in
        if (error == nil)
            var fbloginresult : FBSDKLoginManagerLoginResult = result
            if(fbloginresult.grantedPermissions.contains("email"))
            
                self.getFBUserData()
                fbLoginManager.logOut()
            
        
    )


func getFBUserData()
    if((FBSDKAccessToken.currentAccessToken()) != nil)
        FBSDKGraphRequest(graphpath: "me", parameters: ["fields": "id, name, first_name, last_name, picture.type(large), email"]).startWithCompletionHandler( (connection, result, error) -> Void in
            if (error == nil)
                println(result)
            
        )
    

【讨论】:

containsObject 部分给出错误:'Set<NSObject>' does not have a member named 'containsObject' ****找到答案:将 containsObject 更改为 contains 更改代码:if(fbloginresult.grantedPermissions..contains("email") @senty 很好,fbLoginManager.logOut() 是干什么用的? 修改结果检查以避免在 Facebook 对话框显示“您已经授权...”时用户取消而不是确定时出现错误“在展开可选选项时获得 nil”。使用if fbloginresult.grantedPermissions != nil && fbloginresult.grantedPermissions.contains("email") 而不是仅仅尝试查看grantedPermissions 包含电子邮件 截至 2016 年 7 月,logInWithReadPermissions 应包括 viewController。所以将fbLoginManager .logInWithReadPermissions(["email"], handler: (result, error) -> Void in修改为fbLoginManager.logInWithReadPermissions(permissions, fromViewController: self, handler: (result, error) -> Void in。检查@SantosRamon 的答案以供参考【参考方案2】:

使用最新的 Facebook SDK (01/05/2016) 和 Swift 2.1 更新了答案

使用 Interface Builder 或通过代码创建一个 UIButton 并将该按钮的操作与此链接:

@IBAction func loginFacebookAction(sender: AnyObject) 
    let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()
    fbLoginManager.logInWithReadPermissions(["email"], fromViewController: self)  (result, error) -> Void in
        if (error == nil)
            let fbloginresult : FBSDKLoginManagerLoginResult = result
            if(fbloginresult.grantedPermissions.contains("email"))
            
                self.getFBUserData()
            
        
    

前面代码的快乐案例触发了函数 self.getFBUserData() 所以你必须在同一个文件中实现该函数

func getFBUserData()
    if((FBSDKAccessToken.currentAccessToken()) != nil)
        FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, picture.type(large), email"]).startWithCompletionHandler( (connection, result, error) -> Void in
            if (error == nil)
                //everything works print the user data
                print(result)
            
        )
    

【讨论】:

修改结果检查以避免在 Facebook 对话框显示“您已经授权...”时用户取消而不是确定时出现错误“在展开可选选项时获得 nil”。使用 if fbloginresult.grantedPermissions != nil && fbloginresult.grantedPermissions.contains("email") 而不是仅仅尝试查看grantedPermissions 包含电子邮件【参考方案3】:

我在 xcode 7.3 中成功做到了

    @IBAction func fbLoginBtnAction(sender: AnyObject) 

    let fbLoginManager : FBSDKLoginManager = FBSDKLoginManager()

    fbLoginManager.logInWithReadPermissions(["email"], fromViewController: self, handler: (result, error) -> Void in
            if error == nil 
                print("Logged in through facebook" )
                self.getFBUserData()
            
            else 
                print("Facebook Login Error----\n",error)
            
        
    )



  func getFBUserData () 
    if((FBSDKAccessToken.currentAccessToken()) != nil)
        FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name, last_name, picture.type(large), email"]).startWithCompletionHandler( (connection, result, error) -> Void in
            if (error == nil)
                print(result)
            
        )
    

【讨论】:

【参考方案4】:

可重用类 (Swift 4)。

用法:FacebookSignIn.shared.signIn(from: yourVC, completion: yourCompletion)

class FacebookSignIn 

   enum Error: Swift.Error 
      case unableToInitializeGraphRequest
      case unexpectedGraphResponse
      case permissionsIsNotGranted
      case unexpectedLoginResponse
      case canceled
   

   struct Permissions 

      static let email = "email"
      static let profile = "public_profile"

      static func isValidPermissions(_ permissions: Set<AnyHashable>) -> Bool 
         return permissions.contains(email) && permissions.contains(profile)
      

      static var permissions: [String] 
         return [email, profile]
      
   

   public static let shared = FacebookSignIn()

   private init() 
   



extension FacebookSignIn 

   func signIn(from: UIViewController, completion: Result<SignInResponse>.Completion?) 
      let manager = FBSDKLoginManager()
      manager.loginBehavior = .native
      if !isValidToken 
         manager.logOut()
      
      if let token = FBSDKAccessToken.current() 
         let interval = token.expirationDate.timeIntervalSince(Date())
         if interval > 300  // At least 5 min token will be valid
            performLogin 
               switch $0 
               case .failure(let error):
                  completion?(.failure(error))
               case .success(let info):
                  completion?(.success(SignInResponse(accessToken: token.tokenString, userInfo: info)))
               
            
          else 
            FBSDKAccessToken.refreshCurrentAccessToken  [weak self] _, _, error in
               if let error = error 
                  manager.logOut()
                  completion?(.failure(error))
                else 
                  let token = FBSDKAccessToken.current()?.tokenString ?? "" // Should be always valid value at this point.
                  self?.performLogin 
                     switch $0 
                     case .failure(let error):
                        completion?(.failure(error))
                     case .success(let info):
                        completion?(.success(SignInResponse(accessToken: token, userInfo: info)))
                     
                  
               
            
         
       else 
         manager.logIn(withReadPermissions: Permissions.permissions, from: from)  [weak self] result, error in
            if let error = error 
               manager.logOut()
               completion?(.failure(error))
               return
            
            guard let result = result else 
               manager.logOut()
               completion?(.failure(Error.unexpectedLoginResponse))
               return
            
            let permissions = result.grantedPermissions ?? Set<AnyHashable>()
            let token = result.token?.tokenString ?? "" // Should be always valid value at this point.
            if result.isCancelled 
               manager.logOut()
               completion?(.failure(Error.canceled))
             else if Permissions.isValidPermissions(permissions) 
               self?.performLogin 
                  switch $0 
                  case .failure(let error):
                     completion?(.failure(error))
                  case .success(let info):
                     completion?(.success(SignInResponse(accessToken: token, userInfo: info)))
                  
               
             else 
               manager.logOut()
               completion?(.failure(Error.permissionsIsNotGranted))
            
         
      
   

   private var isValidToken: Bool 
      guard let token = FBSDKAccessToken.current() else 
         return false
      
      return Permissions.isValidPermissions(token.permissions ?? Set<AnyHashable>())
   

   private func makeGraphRequest() -> FBSDKGraphRequest? 
      guard FBSDKAccessToken.current().tokenString != nil else 
         return nil
      
      // You might not get email: https://developers.facebook.com/docs/facebook-login/permissions/v2.4
      // Note, even if you request the email permission it is not guaranteed you will get an email address. For example,
      // if someone signed up for Facebook with a phone number instead of an email address, the email field may be empty.
      let fields = "email,id,first_name,last_name,gender"
      return FBSDKGraphRequest(graphPath: "me", parameters: ["fields": fields])
   

   private func performLogin(completion: Result<[String: String]>.Completion?) 
      let manager = FBSDKLoginManager()
      guard let request = makeGraphRequest() else 
         manager.logOut()
         completion?(.failure(Error.unableToInitializeGraphRequest))
         return
      
      _ = request.start  _, result, error in
         if let e = error 
            manager.logOut()
            completion?(.failure(e))
          else if let result = result as? [String: String] 
            completion?(.success((result)))
          else 
            manager.logOut()
            completion?(.failure(Error.unexpectedGraphResponse))
         
      
   



public struct SignInResponse 

   public let accessToken: String
   public let userInfo: [String: String]

   public init(accessToken: String, userInfo: [String: String]) 
      self.accessToken = accessToken
      self.userInfo = userInfo
   



public enum Result<T> 

   case success(T)
   case failure(Swift.Error)

   public typealias Completion = (Result<T>) -> Void

【讨论】:

【参考方案5】:

如果你想使用原生按钮试试这个:

let buttonText = NSAttributedString(string: "your text here")
facebookButton.setAttributedTitle(buttonText, for: .normal)

【讨论】:

【参考方案6】:

截至 2017 年 6 月,已为 Swift 3 和最新版本的 FBSDK 更新了可接受的答案,代码如下所示-

@IBAction func fbLoginPressed(_ sender: Any) 
        let fbLoginManager: FBSDKLoginManager = FBSDKLoginManager()

        fbLoginManager.logIn(withReadPermissions: ["email"], from: self)  (result, error) in
            if error == nil 
                if let fbLoginResult = result 
                    if fbLoginResult.grantedPermissions != nil && fbLoginResult.grantedPermissions.contains("email")
                        self.getFBUserdata()
                    
                
            
        
    

    func getFBUserdata()
        if FBSDKAccessToken.current() != nil
            FBSDKGraphRequest(graphPath: "me", parameters: ["fields":"id,name,first_name, last_name, picture.type(large), email"]).start(completionHandler:  (cnnection, result, error) in
                if error == nil
                    print(result ?? "Error in getFBUserdata function")
                
            )
        
    

【讨论】:

以上是关于FacebookSDK(4.1.x) 自定义登录 UI 按钮 - Swift(1.2)的主要内容,如果未能解决你的问题,请参考以下文章

FacebookSDK 无法登录,授权后出现白屏。

使用自定义按钮登录 Facebook

自定义 Facebook 登录视图 Swift

使用自定义登录按钮检索Facebook页面

自定义移动 Facebook 登录按钮?

Facebook SDK iOS 的自定义分享、登录按钮