在 Swift 中使用 Google 日历 API 时收到错误“超出未经身份验证使用的每日限制”

Posted

技术标签:

【中文标题】在 Swift 中使用 Google 日历 API 时收到错误“超出未经身份验证使用的每日限制”【英文标题】:Receiving Error "Daily Limit For Unauthenticated Use Exceeded" When Using Google Calendar API in Swift 【发布时间】:2018-02-20 08:01:16 【问题描述】:

我目前正在开发一个需要在 Swift 中使用 Google Calendar API 的应用程序。不幸的是,该项目的进度处于停滞状态,因为我无法确定我需要如何继续才能克服标题中显示的错误。它在执行 google 登录功能后出现。绕过 Firebase 客户端 ID 转而使用通过 Google Developer Console 生成的另一个客户端 ID,似乎也无法解决问题。在代码中的多个场合,我根据另一个 *** 用户的解决方案添加了范围值以及将“https://www.googleapis.com/auth/userinfo.profile”添加到范围中,但都没有解决我的问题。我确实有一个 Google-Info.plist 文件,该文件已正确配置了反向 ID 以及 url 方案,并且还尝试使用该 plist 文件中的客户端 ID 来执行该功能,但它似乎仍然没有工作。下面我包含了来自我的程序的两个主要部分的代码,其中包括对日历 api 或授权函数的引用。让我知道您是否看到任何可能未正确实施的内容,或者我是否错过了使其正常工作的步骤。我的大部分代码都基于此处提供的快速入门代码:https://developers.google.com/google-apps/calendar/quickstart/ios?ver=swift

只需稍作改动即可额外实施 Firebase。 注意:登录似乎可以正常工作,并且可以成功地将数据传送到 firebase,但一旦调用 Google 日历,它就根本不允许进一步的进展。除了我在下面提供的内容之外,还有一个单独的视图控制器,其中包含 google 登录按钮,但我不相信我遇到的问题存在于该类中,因此将其排除在外。

APPDELEGATE
import UIKit
import Firebase
import GoogleSignIn
import FirebaseDatabase
import GoogleAPIClientForREST

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate 

    var scopes = [kGTLRAuthScopeCalendarReadonly, "https://www.googleapis.com/auth/userinfo.profile"]


    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool 
        FirebaseApp.configure()

        GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
        GIDSignIn.sharedInstance().delegate = self
        GIDSignIn.sharedInstance().scopes = scopes


        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = UINavigationController(rootViewController: ViewController())
        window?.makeKeyAndVisible()

        return true
    


    func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) 

        if let err = error 
            print("Failed to log into Google: ", err)

            return
        

        print("Successfully logged into Google", user)
        //Allows information to be stored in Firebase Database
        let ref = Database.database().reference(fromURL: "https://tesseractscheduler.firebaseio.com/")

        guard let idToken = user.authentication.idToken else  return 
        guard let accessToken = user.authentication.accessToken else  return 
        LoginController().service.authorizer = user.authentication.fetcherAuthorizer()
        let credentials = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)

        Auth.auth().signIn(with: credentials, completion:  (user, error) in
            if let err = error 
            print("Failed to create a Firebase User with Google account: ", err)
                return

            

            //successfully authenticated user
            guard let uid = user?.uid else  return 
            print("Successfully logged into Firebase with Google", uid)



            //Creates database entry with users unique identifier, username, and email.  "null" provided to prevent errors.
            ref.updateChildValues(["UID": uid, "username": user?.displayName ?? "null", "Email": user?.email ?? "null"])

            //Pushes to next screen if login has occurred.
            if GIDSignIn.sharedInstance().hasAuthInKeychain()
                //GIDSignIn.sharedInstance().clientID = "197204473417-56pqo0dhn8v2nf5v64aj7o64ui414rv7.apps.googleusercontent.com"
                self.window?.rootViewController = UINavigationController(rootViewController: LoginController())
            
            LoginController().fetchEvents()
        )

    




    func application(_ application: UIApplication, open url: URL, options:
        [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool 




        GIDSignIn.sharedInstance().handle(url,
                                          sourceApplication: options[

                        UIApplicationOpenURLOptionsKey.sourceApplication] as! String!, annotation : options[UIApplicationOpenURLOptionsKey.annotation])

        return true
    

LOGINCONTROLLER
import UIKit
import GoogleSignIn
import Firebase
import GoogleAPIClientForREST

class LoginController: UIViewController 


    let service = GTLRCalendarService()
    let output = UITextView()
    let appDelegate = (UIApplication.shared.delegate as? AppDelegate)



    override func viewDidLoad() 
        super.viewDidLoad()

        navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(didTapSignOut))
         view.backgroundColor = UIColor(red: 61/255, green: 91/255, blue: 151/255, alpha: 1)

        output.frame = view.bounds
        output.isEditable = false
        output.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 20, right: 0)
        output.autoresizingMask = [.flexibleHeight, .flexibleWidth]
        output.isHidden = true
        view.addSubview(output);



        

    func fetchEvents() 
        let query = GTLRCalendarQuery_EventsList.query(withCalendarId: "primary")
        query.maxResults = 10
        query.timeMin = GTLRDateTime(date: Date())
        query.singleEvents = true
        query.orderBy = kGTLRCalendarOrderByStartTime
        service.executeQuery(
            query,
            delegate: self,
            didFinish: #selector(displayResultWithTicket(ticket:finishedWithObject:error:)))
    

    @objc func displayResultWithTicket(
        ticket: GTLRServiceTicket,
        finishedWithObject response : GTLRCalendar_Events,
        error : NSError?) 

        if let error = error 
            showAlert(title: "Error", message: error.localizedDescription)
            return
        

        var outputText = ""
        if let events = response.items, !events.isEmpty 
            for event in events 
                let start = event.start!.dateTime ?? event.start!.date!
                let startString = DateFormatter.localizedString(
                    from: start.date,
                    dateStyle: .short,
                    timeStyle: .short)
                outputText += "\(startString) - \(event.summary!)\n"
            
         else 
            outputText = "No upcoming events found."
        
        output.text = outputText
    

    private func presentViewController(alert: UIAlertController, animated flag: Bool, completion: (() -> Void)?) -> Void 
        UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: flag, completion: completion)
    
    //Shows an error alert with a specified output from the log.
    func showAlert(title : String, message: String) 
        let alert = UIAlertController(
            title: title,
            message: message,
            preferredStyle: UIAlertControllerStyle.alert
        )
        let ok = UIAlertAction(
            title: "OK",
            style: UIAlertActionStyle.default,
            handler: nil
        )
        alert.addAction(ok)
        presentViewController(alert: alert, animated: true, completion: nil)
    

    //Communicated to navigation button to perform logout function.
    @objc func didTapSignOut(_ sender: AnyObject) 
            GIDSignIn.sharedInstance().signOut()
            print("Successfully logged out of Google.")
            showAlert(title: "Log Off", message: "Logout Successful!")
        appDelegate?.window?.rootViewController = UINavigationController(rootViewController: ViewController())

    




        // Do any additional setup after loading the view.
    

如果您需要提供任何其他信息来帮助确定问题,请告诉我。我已经进行了广泛的搜索,但无法找到针对我的特定问题的解决方案。如果这是一个愚蠢的问题,我深表歉意:我对 API 的整合还很陌生。

【问题讨论】:

您为什么要使用 Firebase 身份验证登录才能使用 Google Calender API? 可能有更好的方法,但使用此方法可能更容易为我将在日历工作后实施的第三个 api 提取用户信息。仍然不能 100% 确定它是否有必要,但就我所知。目前,Firebase 提取的信息纯粹用于测试目的,在代码最终确定时可能不会被提取或要求。 【参考方案1】:

我不能确定是否有更有效的解决方法,但现在我已经能够通过剥离所有对 Firebase 的引用的代码并忽略其实现来避免此错误。我使用 Firebase 验证 Google 登录的方式导致了此错误的发生。移除 Firebase 后,这不再是问题。 El Tomato 的问题使我尝试了这种方法,到目前为止,我至少能够取得进步。如果我稍后在项目中有时间,我可能会回来看看是否有可能在不发生错误的情况下同时实现它们,但现在它不是一个重要的功能。

【讨论】:

以上是关于在 Swift 中使用 Google 日历 API 时收到错误“超出未经身份验证使用的每日限制”的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 android 使用日历 API 在谷歌日历上添加事件?

Google 日历 API 在公共日历中插入事件时返回错误 401“需要登录”

在 Google 日历 API 中开会

使用 API 从 Google 日历中检索事件

Google API:通过 Google Talk 通知日历条目更改

使用私有 URL 和 google api v3 共享 google 日历活动