I have the following method in a ViewModel to handle user clicks on a Facebook login button:
import Foundation
import FirebaseAuth
import FacebookLogin
/// A view model that handles login and logout operations.
class SessionStore: ObservableObject {
@Published var user: User?
@Published var isAnon = false
private var handle: AuthStateDidChangeListenerHandle?
private let authRef = Auth.auth()
/// A login manager for Facebook.
private let loginManager = LoginManager()
/// Listens to state changes made by Firebase operations.
func listen() {
handle = authRef.addStateDidChangeListener {[self] (auth, user) in
if user != nil {
self.isAnon = false
self.user = User(id: user!.uid, fbId: authRef.currentUser!.providerData[0].uid, name: user!.displayName!, email: user!.email!, profilePicURL: user!.photoURL)
} else {
self.isAnon = true
self.user = nil
}
}
}
/// Logs the user in using `loginManager`.
///
/// If successful, get the Facebook credential and sign in using `FirebaseAuth`.
///
/// - SeeAlso: `loginManager`.
func facebookLogin() {
loginManager.logIn(permissions: [.publicProfile, .email], viewController: nil) { [self] loginResult in
switch loginResult {
case .failed(let error):
print(error)
case .cancelled:
print("User cancelled login.")
case .success:
let credential = FacebookAuthProvider.credential(withAccessToken: AccessToken.current!.tokenString)
authRef.signIn(with: credential) { (authResult, error) in
if let error = error {
print("Facebook auth with Firebase error: \(error)")
return
}
}
}
}
}
}
In listen()
, I'm trying to build my User
model whenever Firebase detects state change (i.e., when a user is logged in). My User
model is a simple struct
like this:
/// A model for the current user.
struct User: Identifiable, Codable {
var id: String
var fbId: String
var name: String
var email: String
var profilePicURL: URL?
}
The Problem
Right now, as you can see in my listen()
method, I'm using Firebase's photoURL
to get user's profile picture. However, it will only give me a low-quality thumbnail pic.
I would love to fetch normal photos from Facebook.
What I have tried
I tried, in my facebookLogin()
to call GraphRequest
to get the picture url. However, since my function is synchronous, I couldn't store the result to my User
model.
I also tried directly using the Graph API link like "http://graph.facebook.com/user_id/picture?type=normal", but it seems like it's no longer the safe/suggested practice.
Question
Given my ViewModel structure, what is the best way to fetch and store Facebook user picture URL to my User
model?
CodePudding user response:
I found out that Firebase's photoURL
is Facebook's Graph API URL: http://graph.facebook.com/user_id/picture
. So, to get other sizes, all I need to do is to append a query string like ?type=normal
to the photoURL
.
To use GraphRequest
, consider @jnpdx's suggestion:
Seems like you have at least a couple of options: 1) Use the GraphRequest and don't set your User model until you get the result back. 2) Set your User model as you are now and then update it with a new URL once your GraphRequest comes back.