因未捕获的异常 'NSInvalidArgumentException' 而终止应用程序 - iOS Google 登录

5
我正在实施从此教程中获取的Google登录流程。
在这个教程中,作者写道:
“在这些示例中,视图控制器是UIViewController的子类。如果在您的项目中,实现GIDSignInUIDelegate的类不是UIViewController的子类,请实现GIDSignInUIDelegate协议的signInWillDispatch:error:、signIn:presentViewController:和signIn:dismissViewController: 方法。”
因此,我按照他的建议编写了以下内容:
import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {



func application(application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Initialize sign-in
        var configureError: NSError?
        GGLContext.sharedInstance().configureWithError(&configureError)
        assert(configureError == nil, "Error configuring Google services: \(configureError)")

        GIDSignIn.sharedInstance().delegate = self

        return true
}

// [START openurl]
func application(application: UIApplication,
    openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
        return GIDSignIn.sharedInstance().handleURL(url,
            sourceApplication: sourceApplication,
            annotation: annotation)
}
// [END openurl]

@available(iOS 9.0, *)
func application(app: UIApplication, openURL url: NSURL, options: [String : AnyObject]) -> Bool {
    return GIDSignIn.sharedInstance().handleURL(url,
        sourceApplication: options[UIApplicationOpenURLOptionsSourceApplicationKey] as! String?,
        annotation: options[UIApplicationOpenURLOptionsAnnotationKey])
}

// [START signin_handler]
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!,
    withError error: NSError!) {
        if (error == nil) {
            print("Signed in!")
        } else {
            print("\(error.localizedDescription)")
        }
}
// [END signin_handler]

// [START disconnect_handler]
func signIn(signIn: GIDSignIn!, didDisconnectWithUser user:GIDGoogleUser!,
    withError error: NSError!) {
        // Perform any operations when the user disconnects from app here.
        // [START_EXCLUDE]
        NSNotificationCenter.defaultCenter().postNotificationName(
            "ToggleAuthUINotification",
            object: nil,
            userInfo: ["statusText": "User has disconnected."])
        // [END_EXCLUDE]
}

我也有一个名为LoginScreen.swift的类,其中包含:
import UIKit

class LoginScreen: UIViewController, GIDSignInUIDelegate {

     override func viewDidLoad() {
    super.viewDidLoad()
    GIDSignIn.sharedInstance().uiDelegate = self

    // Uncomment to automatically sign in the user.
    GIDSignIn.sharedInstance().signInSilently()

}

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    GIDSignIn.sharedInstance().uiDelegate = self

     GIDSignIn.sharedInstance().signInSilently()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func signInWillDispatch(signIn: GIDSignIn!, error: NSError!) {
    print("Nothing!")
}

// Present a view that prompts the user to sign in with Google
func signIn(signIn: GIDSignIn!,
    presentViewController viewController: UIViewController!) {
        self.presentViewController(viewController, animated: true, completion: nil)
}

// Dismiss the "Sign in with Google" view
func signIn(signIn: GIDSignIn!,
    dismissViewController viewController: UIViewController!) {
        self.dismissViewControllerAnimated(true, completion: nil)
}


}

当我运行该应用程序时,我看到一个按钮使用谷歌登录。 但是,当我单击它时,我会看到以下错误:

*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: 'When |allowsSignInWithWebView| is enabled, uiDelegate must
either be a |UIViewController| or implement the
|signIn:presentViewController:| and |signIn:dismissViewController:| 
methods from |GIDSignInUIDelegate|.'

这里的问题是什么?我以为我已经包含了必要的方法......

============ 编辑 - 作为对 @emrys57 问题的跟进:

我在我的项目中附加了 GoogleService-Info.plist 文件:

enter image description here

当我注释掉这三个方法 (presentViewController, dismissViewControllersignInWillDispatch),没有任何变化 - 我仍然得到相同的错误...

关于屏幕 - 这是我的故事板的样子:

enter image description here

我想在第三个屏幕上显示 Google 登录按钮。

这里的第二个屏幕包含一个 Tutorial,其代码目前如下:

import UIKit

class Tutorial: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        let background = CAGradientLayer().greenBlue()
        background.frame = self.view.bounds
        self.view.layer.insertSublayer(background, atIndex: 0)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

}

还有一件事 - 当我打开应用程序时,现在我看到了谷歌登录按钮: enter image description here 当我点击它时 - 我得到了上述的错误:
2016-02-13 09:47:49.578 myapp[20870:800499] *** Terminating app due
to uncaught exception 'NSInvalidArgumentException', reason: 'When
|allowsSignInWithWebView| is enabled, uiDelegate must either be a
|UIViewController| or implement the |signIn:presentViewController:| and
|signIn:dismissViewController:| methods from |GIDSignInUIDelegate|.'

*** First throw call stack:
(...)

所以我猜当我点击按钮时,LoginScreen正在运行...

=========== 另一个编辑:

当我将代码从我的LoginScreen复制到ViewController类中,并在那里添加按钮时 - 一切都正常工作,我可以看到google登录按钮,并且我可以登录!但是 - 按钮出现在应用的第一个屏幕上,这不是我想要的。我希望它出现在第三个屏幕上(在教程之后)。有人知道发生了什么事情,为什么我不能在第三个屏幕上放置登录按钮吗?


1
LoginScreen实例化的位置并不是很清楚。当出现此消息时,LoginScreen是否正在运行,并且uiDelegate已经设置好了?您是否添加了GoogleService-Info.plist文件?显然,如果您的类不是UIViewcontroller,则只需要3个UIDelegate方法。但是你的视图控制器是的。因此,如果您注释掉这3个委托方法,会发生什么? - emrys57
@emrys57,我回答了你的问题,请看上面的编辑,谢谢! - randomuser1
1
这变得越来越困难了。如果今天晚些时候仍然存在这个问题,我会尝试运行您的代码,但现在我必须去关注我的妻子。 - emrys57
@emrys57 我找到了解决方案... 当然,错误是由于我的疏忽造成的,但这是一个很好的教训,对未来很有帮助。虽然如此,感谢你的参与,很高兴知道我不是唯一一个在寻找解决方案的人 :) - randomuser1
@randomuser1,我遇到了和你一样的问题。请问你找到解决方案了吗?能否分享一下呢? - EI-01
@user3497437,是的,那时候真的是我的错...当我向故事板添加新屏幕时,我忘记填写“自定义类”表单。当我意识到这一点并填写了“类”和“模块”字段时,它开始正常工作了...希望这能帮到你 :) - randomuser1
6个回答

13

更新至Swift 5 / iOS SDK 5的Google登录:

登录按钮操作方法中使用以下代码行:

GIDSignIn.sharedInstance().presentingViewController = self
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().signIn()
注意:如果您在任何视图控制器中使用此代码行之前,请在其上方添加注释...!否则,就没问题了。 享受学习....!

10

我知道现在有点晚,但如果您将GIDSignIn.sharedInstance().uiDelegate = self放入viewDidAppear而不是viewDidLoad,那对其他人会有帮助,这对我有效!


2

func signIn(signIn: GIDSignIn!, presentViewController viewController: UIViewController!)GIDSignInUIDelegate协议中的一个方法,但上面的代码表明AppDelegate采用了GIDSignInDelegate(而不是“UI”)协议,并且你的GIDSignInUIDelegate没有提供这些方法。要么类采用了错误的协议,要么方法在错误的类中。


好的,我将presentViewControllerdismissViewController这两个方法移动到了我的LoginScreen类中,但不幸的是它并没有起作用。我做错了什么? - randomuser1
也许你应该用新代码更新你的问题,或者提一个新的问题。从这里看不太清楚。另外,抱歉,我要去睡觉了。祝好运! - emrys57
在你的建议之后,我编辑了我的问题中的代码,但问题仍然存在。 - randomuser1

0

GIDSignIn.sharedInstance().presentingViewController = self


0
如果有帮助的话,我在另一篇帖子这里发布了这个错误的根本原因。

0

这个问题与本题无关,但这也可能是由于自动 Obj-C 到 Swift 3 命名生成导致的,导致 GIDSignInUIProtocol 的方法签名与 Google SDK 预期的不同。

将这些转发方法添加到 GIDSignInUIProtocol 实现中将解决此情况的问题 -

func signIn(signIn: GIDSignIn!, presentViewController viewController: UIViewController!) {
    self.sign(signIn, present: viewController)
}

func signIn(signIn: GIDSignIn!, dismissViewController viewController: UIViewController!) {
    self.sign(signIn, dismiss: viewController)
}

但是这对我也没有用!这是SDK的问题吗? - Sahil Mahajan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接