How to use ObservedObject with Google Sign In

Viewed 86

I am trying to observe if user logged in or not by Google sign in SDK using SwiftUI . the sign in is working fine and the print out is showing user is logged in successfully , but the UI is not changing it is like the observe not working or I am sure I miss something there .

App :

@main
struct test_app: App {
    
    @AppStorage("settings") private var settings: Data = Data()
    @Environment(\.scenePhase) var scenePhase
    @UIApplicationDelegateAdaptor(test_delegate.self) private var appDelegate
    
    var userInfo:Bool = false
    @ObservedObject static var gd = GoogleDelegate()
    
    init(){
        //Google sign in
        GIDSignIn.sharedInstance().delegate = test_app.gd
        //Firebase
        FirebaseApp.configure()
        print("[APP] Init complete.")
    }
    
    var body: some Scene {
        WindowGroup {
            
            if userInfo  {
                w_home().onOpenURL(perform: { url in
                                   print("[DEEP LINK] Incoming url: \(url)")
                                    })
            }else{
                w_splash()
            }
            
        }.onChange(of: scenePhase) { (newScenePhase) in
            switch newScenePhase {
            case .background:
                print("[APP] State : Background")
            case .inactive:
                print("[APP] State : Inactive")
            case .active:
                
                print("[APP] State : Active")
            @unknown default:
                print("[APP] State : Unknown")
            }
        }
    }
}

GoogleDelegate class :

class GoogleDelegate: NSObject, GIDSignInDelegate, ObservableObject {
    
    @Published var signedIn: Bool = false
    
    public func signIn(){
        
        // Maksure that there must be a presenting controller as a container
        GIDSignIn.sharedInstance()?.presentingViewController = UIApplication.shared.windows.first?.rootViewController
        
        //Google sign in
        GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
        GIDSignIn.sharedInstance().signIn()
        
        signedIn = false
        
    }
    
    func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
        if let error = error {
            if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue {
                print("[GSIN] The user has not signed in before or they have since signed out.")
            } else {
                print("[GSIN] \(error.localizedDescription)")
            }
            return
        }
        
        // If the previous `error` is null, then the sign-in was succesful
        if GIDSignIn.sharedInstance().currentUser != nil {
            print("[GSIN] Successful sign-in! \( String(describing: GIDSignIn.sharedInstance().currentUser!.profile.email) )")
        }else{
            print("[GSIN] Successful sign-in!")
        }
        
       self.signedIn = true

    }
    
}

and finally the login :

struct w_splash: View {
    
    let screenBounds:CGRect = UIScreen.main.bounds
    
    var body: some View {
        ZStack {
                Image("logo").resizable()
                             .aspectRatio(contentMode: .fit)
                             .frame(width: screenBounds.width * 0.5, height: screenBounds.height * 0.2)
                VStack {
                    
                        Spacer()
               
                        HStack {
                            
                        
                            Button(action: {
                            
                                test_app.gd.signIn()
                                
                            }, label: {
                                
                                HStack{
                                    Image("btn_google_dark_normal_ios").resizable().frame(width: 50, height: 50, alignment: .center)
                                    
                                    Text("Sign in with Google")
                                        .font( Font.custom("Roboto-Medium", size: 14) )
                                        .frame(width: .none,
                                               height: 50,
                                               alignment: .center)
                                    .foregroundColor(Color.white)
                                        .padding(.trailing, 30)
                                        .padding(.leading, 10)
                                }
                            })
                            .isHidden(test_app.gd.signedIn)
                            .background(Color(hex: "#4285F4"))
                            .cornerRadius(5.5)
                            .padding(.bottom , screenBounds.height * 0.1)
                            .frame(width: screenBounds.width * 0.9,
                                   height: 50,
                                   alignment: .center)
                            .shadow(color: Color.black.opacity(0.2),
                                    radius: 3,
                                    x: 3,
                                    y: 3)
                        }
                    }
        }.onAppear{
            
            if (test_app.gd.signedIn ){
                
             print("user logged in test print out")
           
            }
            
        }
    }
}

struct w_splash_Previews: PreviewProvider {
    static var previews: some View {
        w_splash()
    }
}

I am still new with swiftUI, any ideas why I can't observe the variable?

1 Answers

It looks like you wanted to make GoogleDelegate a singleton.

I suggest you create a static instance of GoogleDelegate:

class GoogleDelegate: NSObject, GIDSignInDelegate, ObservableObject {
    static let shared = GoogleDelegate()
    
    @Published var signedIn: Bool = false
    ...
}

Then, in your views replace:

@ObservedObject static var gd = GoogleDelegate()

with:

@ObservedObject var gd = GoogleDelegate.shared

Also, note that you don't observe GoogleDelegate in your w_splash view, so you need to add it there as well:

struct w_splash: View {
    @ObservedObject var gd = GoogleDelegate.shared

and refer directly to it using gd.signedIn (not test_app.gd.signedIn).

If you want to print something when gd.signedIn changes, you can use onChange:

.onChange(of: gd.signedIn) { signedIn in
    print("signedIn: \(String(signedIn))")
}
Related