You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS应用Google Sign In流程中断报错(Code-4/-5)求助

iOS Google Sign In 流程中断(错误码-4/-5)排查与修复

问题描述

开发iOS应用集成Google Sign In,编译正常,但点击登录按钮后,授权弹窗几秒后自动消失,报错:

This is the error: Optional("The operation couldn’t be completed. (com.google.GIDSignIn error -4.)")
error with signing in: Optional(Error Domain=com.google.GIDSignIn Code=-5 "The user canceled the sign-in flow." UserInfo={NSLocalizedDescription=The user canceled the sign-in flow.})

错误码解析

  • Error -4: 钥匙链访问错误,通常是应用没有正确的钥匙链权限,或者Client ID配置不匹配
  • Error -5: 表面显示用户取消,但实际是登录流程因底层错误(如-4)被强制终止,并非用户主动操作

解决方案

1. 检查Google Cloud控制台配置

  • 确认使用的是iOS类型的Client ID,而非Web或Android类型
  • 验证控制台中填写的Bundle ID与Xcode项目的Bundle Identifier完全一致(大小写敏感)
  • 确保已在控制台启用Google Sign In API
  • 检查Redirect URI格式是否正确:com.googleusercontent.apps.{你的Client ID}:/oauth2redirect

2. Xcode项目配置修复

  • 添加URL Scheme:在Info.plist中添加CFBundleURLTypes数组,其中CFBundleURLSchemes包含你的Google Client ID的反向ID(即com.googleusercontent.apps.xxxxxxxxx,可从控制台复制)
  • 添加查询Scheme:在Info.plist中添加LSApplicationQueriesSchemes数组,包含以下项:
    <string>google</string>
    <string>googleusercontent</string>
    
  • 启用Keychain Sharing:进入项目Target -> Signing & Capabilities -> 点击+ Capability,添加Keychain Sharing,并添加团队ID前缀+Bundle ID的组(例如TEAMID.com.yourcompany.appname)

3. 代码逻辑优化

当前代码在viewDidLoad和signInPressed中重复调用googleSignIn,导致登录流程冲突,建议调整:

修改signInPressed方法

@IBAction func signInPressed(_ sender: UIButton) {
    print("Sign in pressed")
    
    let user = GIDSignIn.sharedInstance.currentUser
    if user == nil {
        // 直接发起新登录,跳过restore流程
        let signInConfig = GIDConfiguration(clientID: K.clientID)
        GIDSignIn.sharedInstance.signIn(with: signInConfig, presenting: self) { gUser, signInError in
            if signInError == nil {
                guard let gUser = gUser else {
                    sender.setTitle("Sign in", for: .normal)
                    return
                }
                self.requestScopes(googleUser: gUser) { success in
                    sender.setTitle(success ? "Sign out" : "Sign in", for: .normal)
                }
            } else {
                print("error with signing in: \(String(describing: signInError)) ")
                self.service.authorizer = nil
                sender.setTitle("Sign in", for: .normal)
            }
        }
    } else {
        GIDSignIn.sharedInstance.signOut()
        self.service.authorizer = nil
        sender.setTitle("Sign in", for: .normal)
    }
}

调整googleSignIn方法(仅用于恢复登录)

func googleSignIn(completionHandler: @escaping (Bool) -> Void) {
    GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
        if let user = user {
            print("Managed to restore previous sign in!\nScopes: \(String(describing: user.grantedScopes))")
            self.requestScopes(googleUser: user) { success in
                completionHandler(success)
            }
        } else {
            print("No previous user!\nThis is the error: \(String(describing: error?.localizedDescription))")
            completionHandler(false)
        }
    }
}

修复requestScopes中的认证逻辑

替换错误的user?.authentication.do写法:

func requestScopes(googleUser: GIDGoogleUser, completionHandler: @escaping (Bool) -> Void) {
    let grantedScopes = googleUser.grantedScopes
    if grantedScopes == nil || !grantedScopes!.contains(K.grantedScopes) {
        let additionalScopes = K.additionalScopes
        GIDSignIn.sharedInstance.addScopes(additionalScopes, presenting: self) { user, scopeError in
            if scopeError == nil, let user = user {
                // 正确获取认证信息
                if let authentication = user.authentication {
                    let authorizer = authentication.fetcherAuthorizer()
                    self.service.authorizer = authorizer
                    completionHandler(true)
                } else {
                    print("Failed to get authentication")
                    completionHandler(false)
                }
            } else {
                completionHandler(false)
                print("Error with adding scopes: \(String(describing: scopeError?.localizedDescription))")
            }
        }
    } else {
        print("Already contains the scopes!")
        // 直接设置授权器
        if let authentication = googleUser.authentication {
            self.service.authorizer = authentication.fetcherAuthorizer()
        }
        completionHandler(true)
    }
}

4. 模拟器测试注意事项

  • 确保模拟器已登录Google账号(设置 -> 密码与账户 -> 添加Google账户)
  • 若仍有问题,尝试使用真机测试,模拟器的钥匙链权限有时会有异常

内容的提问来源于stack exchange,提问作者user17792511

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 20:05:45