How to login to Facebook on SwiftUI?

Viewed 4861

There are not many resources explaining Facebook Login with SwiftUI. I'm not sure whether my code requires a ViewController or not because Facebook's LoginManager.login() contains a ViewController parameter - however this doesn't really translate to SwiftUI.

Regardless, I am trying to login the user to Facebook when they click on the Button below:

LoginView.swift

import Foundation
import SwiftUI
import FBSDKLoginKit

struct LoginView: View {
    @EnvironmentObject var auth: UserAuth
    var body: some View {
        ZStack {
            VStack {
                Image("launcher_logo").resizable()
                .scaledToFit()
                .frame(height: 100)
                    .padding(.top, 100)
                Spacer()
                Button(action: {
                    FBLogin()
                }) {
                    Text("Continue with Facebook")
                }.foregroundColor(Color.black)

when the Button is clicked, it initialises FBLogin below - which fires login() in its init():

Model:

class FBLogin: LoginManager {

    let loginButton = FBLoginButton()
    let token = AccessToken.current
    let permissions = ["user_birthday", "user_gender", "public_profile"]

    override init(){
        super.init()
        logIn(permissions: permissions, from: nil)
        print("fb init()")
    }

    override func logIn(permissions: [String], from fromViewController: UIViewController?, handler: LoginManagerLoginResultBlock? = nil) {
        // TODO
    }

}

However I'm not sure what to do from there. At the moment, only fb init() prints but I want to execute the login and listen to the login result.

Any idea?

2 Answers

Just create LoginManager instance inside ObservableObject and then customise login completion. You can easily use inside SwiftUI View. No need UIViewControllerRepresentable. Here is my sample.

struct ContentView: View {
    @ObservedObject var fbmanager = UserLoginManager()
    var body: some View {
        Button(action: {
            self.fbmanager.facebookLogin()
        }) {
            Text("Continue with Facebook")
        }
    }
}

class UserLoginManager: ObservableObject {
    let loginManager = LoginManager()
    func facebookLogin() {
        loginManager.logIn(permissions: [.publicProfile, .email], viewController: nil) { loginResult in
            switch loginResult {
            case .failed(let error):
                print(error)
            case .cancelled:
                print("User cancelled login.")
            case .success(let grantedPermissions, let declinedPermissions, let accessToken):
                print("Logged in! \(grantedPermissions) \(declinedPermissions) \(accessToken)")
                GraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name"]).start(completionHandler: { (connection, result, error) -> Void in
                    if (error == nil){
                        let fbDetails = result as! NSDictionary
                        print(fbDetails)
                    }
                })
            }
        }
    }
}

Have a look on a callback wrapper for Combine to use Facebook Login and Graph API Request with SwiftUI: https://github.com/axmav/combine-extensions

LoginManager()
            .logIn(permissions: [.publicProfile, .email])
            .flatMap { loginResult -> AnyPublisher<Account?, Error> in
                switch loginResult {
                case .failed(let error):
                    return Fail(outputType: Account?.self, failure: error).eraseToAnyPublisher()
                case .cancelled:
                    return Just(Account?.none)
                        .setFailureType(to: Error.self)
                        .eraseToAnyPublisher()
                case .success(let grantedPermissions, let declinedPermissions, let accessToken):
                    return GraphRequest(graphPath: "me", parameters: ["fields": "id, name, first_name"])
                        .start(type: Account.self)
                }
            }
Related