google / GoogleSignIn-iOS

Enables iOS and macOS apps to sign in with Google.
https://developers.google.com/identity/sign-in/ios
Apache License 2.0
457 stars 182 forks source link

Using v6 in SwiftUI: `.signIn()` workaround and suggestions for SwiftUI support #49

Open peterkos opened 2 years ago

peterkos commented 2 years ago

Background

With SwiftUI being the way forward for iOS dev, I would have hoped GoogleSignIn had better support for SwiftUI.

Unfortunatley there isn't any SwiftUI-focused documentation, and the patterns changed in v6 (e.g., no delegates) seem to make implementing GIDSignIn harder in SwifUI.

The biggest issue I've had (and clearest example) is below:

Sign In

The main issue I've run into is with this function:

- (void)signInWithConfiguration:(GIDConfiguration *)configuration
       presentingViewController:(UIViewController *)presentingViewController
                       callback:(nullable GIDSignInCallback)callback;

SwiftUI doesn't have view controllers, but we need to instantiate a sign-in view from SwiftUI.

There's two workarounds:

  1. Create a UIViewRepresentable view that accesses the root view controller with something like UIApplication.shared.windows.last?.rootViewController
  2. Create a UIViewRepresentable view that instantiates a dummy UIViewController that then calls some AuthManager singleton, which in turn calls sharedInstance.signIn(...).

This is so confusing to implement primarily because there already existed a delegate pattern and a non-presentingVC parameter before v6 of this library.

Tying it all together would be something like this:

// AuthManager.swift

class AuthManager {

    var shared = AuthManager()
    var config = GIDConfiguration()

    func signIn(withVC vc: UIViewController) {
        GIDSignIn.signIn(with: config, presenting: vc) { /* ... */ }
    }
}

// AuthWrapper.swift 

class AuthVC: UIViewController {
    func signIn() {
        AuthManager.shared.signIn(withVC: self)
    }
}

class AuthVCWrapper: UIViewRepresentable {
    let authVC = AuthVC() // strong ref
    func makeUIViewController() {
        return authVC
    }
    func signIn() {
        authVC.signIn() // single responsibility principle
    }
}

// SignIn.swift

class SignIn: View {
    var authWrapper = AuthVCWrapper()

    var body: some View {
        ZStack {
            authWrapper
            Button(action: authWrapper.signIn()) {
                Text("Sign In")
            }
        }
    }
}

To me personally this seems verbose.

Delegates

In addition, the delegate pattern seems to have been removed. This would have made it much easier to work alongside a more detached MVVM pattern instead of routing everything through the sharedInstance singleton anyways.

Is there a reason for why the delegate pattern was removed?

Suggestions

Given that SFSafariViewController is a UIKit component, having GIDSignIn instantiate the UIViewControllerRepresentable and alongisde an overloaded sharedInstance.signIn() for SwiftUI users would vastly shorten the above example.

The other suggestion I have is maybe a timeline on SwiftUI support, or some documentation on existing workarounds, as most blog posts are written pre-v6, and instruct users to create delegates and such, which is no longer supported.

Final Thoughts

I guess this brings me to my final question: is there SwiftUI support planned at all?

I'd be happy to write a sample project to catch up the Objective-C one currently in this repo, but without any official documentation for SwiftUI support it'd need a good chunk of review.

TurkeyKittin commented 2 years ago

I'm struggling to implement GoogleSignIn into SwiftUI just like this. Do you have a functioning solution (a more complete version of the snippet you provided above)? (i.e. I'm getting errors that GIDSignIn.signin(...) has no member type signin(...) eventhough it autocompletes :S )

crspybits commented 2 years ago

Have you seen https://stackoverflow.com/questions/59570306/bringing-up-the-google-signin-screen-in-swiftui ?

Not what you might call a native SwiftUI solution, but it's working for me.

peterkos commented 2 years ago

@mdmathias I'm not sure why this issue was closed; I'm encouraged that a SwiftUI sample is available but the method still does not fundamentally support SwiftUI, which is the focus of this issue. The signIn method still requires a UIViewController which requires a workaround, and the example PR simply implements the workaround with no further discussion.

Is there any timeline for direct SwiftUI support?

mdmathias commented 2 years ago

Hi @peterkos; thanks for the comment and the feedback. I agree that the sample app we merged in #63 does not resolve the issue at stake here. We meant to associate the issue with the PR and not close it. I'm reopening this issue so we can keep track of native SwiftUI support.

trzy commented 5 months ago

How were you able to import the package in the first place? I can't get it to work with either CocoaPods or Swift Package Manager.