Code:
let signIn = GPPSignIn.sharedInstance()
signIn.shouldFetchGooglePlusUser = true
signIn.clientID = "912597493260-qg351fl8olmnmjl8qobos8n6u909jp0o.apps.googleusercontent.com"
signIn.scopes = [kGTLAuthScopePlusLogin];
signIn.trySilentAuthentication();
GIDSignIn.sharedInstance().signInSilently()
signIn.delegate = self
due to uncaught exception 'NSInvalidArgumentException', reason: 'You must specify |clientID| for |GIDSignIn|
I double checked my code.Even i set client-id getting this exception.Where i went wrong?any help will be appreciated.thanks in advance
I was following Google's own guide for adding Sign-In here. I followed it step by step - integrated the google configuration file too. As per the guide, if the configuration file was included, setting the client id manually was not required. Unfortunately, I encountered exactly the same error when I run the app and hit the Sign-In button:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'You must specify |clientID| for |GIDSignIn|'
Solution:
For some reason, clientID was not automatically picked from the configuration file. We should instead configure the GIDSignIn object directly, (using the client ID found in the GoogleService-Info.plist file) in the app delegate's application:didFinishLaunchingWithOptions: method:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Initialize sign-in
var configureError: NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError)")
GIDSignIn.sharedInstance().clientID = "Cliend id From GoogleService-Info.plist file"
GIDSignIn.sharedInstance().delegate = self
return true
}
Also, if you are using Firebase, you can do it this way too:
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
It looks like the auto-generated config file, GoogleService-Info.plist, will include the wrong credentials by default; it includes the Web Client credentials instead of the iOS app credentials.
You need to correct the Client ID and the Reverse Client ID in the GoogleService-Info.plist.
Since these credentials are also used in your app's URLSchemes, you need to correct this there too.
I was also facing the same issue. I followed every step as per the documentation by https://firebase.google.com/docs/auth/ios/google-signin#swift_9 .
At last, I tried adding Client ID manually on my Controller's viewDidLoad and it worked after a long struggle.
Refer the code below. Replace your project specific Client-ID from GoogleService-info.plist in place of ClientID :
class IntroController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
GIDSignIn.sharedInstance().clientID = "*ClientID*"
GIDSignIn.sharedInstance()?.presentingViewController = self
GIDSignIn.sharedInstance().signIn()
}
}
The clientId definitely does get picked up from the .plist file. If it appears not to be, it is likely that your code is attempting to use the sign-in object before it has been properly configured. Set a breakpoint on your configureWithError line, and make sure that it gets hit before any attempt to set a delegate, perform silent sign-in, etc.
Looks like the sign in method has now been updated by google, I was implementing the Google Calendar for iOS app and I found the following code for Sign In:
func applicationDidFinishLaunching(_ application: UIApplication) {
// Initialize sign-in
var configureError: NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError!)")
}
in their document which gave the same error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'You must specify |clientID| for |GIDSignIn|'
I took the lines which were inside:
func applicationDidFinishLaunching(_ application: UIApplication)
and put them in this method and sign in worked:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
Code for refernce:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// Initialize sign-in
var configureError: NSError?
GGLContext.sharedInstance().configureWithError(&configureError)
assert(configureError == nil, "Error configuring Google services: \(configureError!)")
return true
}
You may need to obtain GoogleService-Info.plist from https://console.firebase.google.com rather than https://console.developers.google.com/.
Using Firebase remember also that you have to call Firebase.configure() function before you set the clientId. Otherwise, it won't work.
Related
Problem:
In iOS app I am using google signIn to facilitate the process of getting the authCode, which later is sent into the server and it is exchanged for a refresh_token in google calendar API. The bad news is that user.serverAuthCode is always nil.
What happens now:
I have followed the google's documentation for implementing it. At this moment when I click the google sign-in button I go to a page where I fill in my credentials and I consent to all the scopes. Then it redirects me back to iOS app but I don't get the authCode.
Code:
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate{
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if (error == nil) {
print("Authcode is : \(user.serverAuthCode)") // This is nil :(
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
GIDSignIn.sharedInstance().clientID = "MY_CLIENT_ID"
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().scopes.append("https://www.googleapis.com/auth/calendar")
GIDSignIn.sharedInstance().scopes.append("https://www.googleapis.com/auth/calendar.events")
return true
}
}
I've also added URL type in target info as described in google's documentation
Lastly I have a viewController which uses GIDSignInButton to start the log-in process.
Is there anything I am missing? I took a look at this post but I could not solve the problem. Thank you for your time!
After some time spending on searching the solution was found :)
Problem fixed after adding:
GIDSignIn.sharedInstance()?.serverClientID = "SERVER_CLIENT"
If you don't know how to get these: SERVER_CLIENT vs CLIENT_ID
I use Firebase for my backend, Remote Notifications, and use Google Maps and Places APIs inside my iOS app. Everything works fine but I want to hide my api credentials.
To send a Remote Notification I need the server key from Firebase and to access the Google Maps and Places APIs I need their API Credentials
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
static var fbServerKey = "someReallyLongFirebaseServerKey"
override init() {
super.init()
Messaging.messaging().delegate = self
FirebaseApp.configure()
GMSPlacesClient.provideAPIKey("my_Places_API_Key") // places api credential key
GMSServices.provideAPIKey("my_Maps_API_Key") // maps api credential key
GMSPlacesClient.openSourceLicenseInfo()
GMSServices.openSourceLicenseInfo()
GADMobileAds.sharedInstance().start(completionHandler: nil)
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
}
}
To send a push notification I access the fbServerKey from AppDelegate:
let fbServerKey = AppDelegate.fbServerKey // *** 1. the server key is accessed here and used below ***
var params = [String: Any]() // add keys and values to params
var request = URLRequest(url: URL(string: "https://fcm.googleapis.com/fcm/send")!)
request.httpMethod = "POST"
// *** 2. the server key is used HERE ***
request.setValue("key=\(fbServerKey)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in ...
I have my Firebase Rules in place but if you look at the above code the fbServerKey and maps/places API credentials are all in plain text.
To avoid that problem I switched to using CloudKit:
// these keys are all set prior to going live and won't be inside the user's applications
NSUbiquitousKeyValueStore().set("someReallyLongFirebaseServerKey", forKey: "fbServerKey")
NSUbiquitousKeyValueStore().set("my_Places_API_Key", forKey: "placesAPIKey")
NSUbiquitousKeyValueStore().set("my_Maps_API_Key", forKey: "mapsAPIKey")
NSUbiquitousKeyValueStore().synchronize()
To retrieve the keys:
static var fbServerKey = NSUbiquitousKeyValueStore()string(forKey: "fbServerKey")
GMSPlacesClient.provideAPIKey(NSUbiquitousKeyValueStore()string(forKey: "placesAPIKey"))
GMSServices.provideAPIKey(NSUbiquitousKeyValueStore()string(forKey: "mapsAPIKey"))
The problem here is if the user isn't connected to iCloud then they won't be able to access the keys.
Now I'm in the process of switching to Firebase Cloud Functions. The thing is I'm not clear how to use it.
1- In terminal I cd to my Xcode project folder and run
// $ firebase init functions *** I initially used this command but DO NOT RUN THIS line >firebase init functions<. Read the first comment below from #DougStevenson for the reason to avoid it
$ npm install -g firebase-tools
$ npm install --save firebase-functions#latest
2- I choose the fb project I want to deploy the cloud functions to
3- I set the keys using the below which I'm lost at because I don't know what someservice.key is nor do I know what someservice.id is nor am i 100% sure where to find my client id (I'm assuming it's the CLIENT_ID from the GoogleService-Info.plist)
$ firebase functions:config:set someservice.key="THE API KEY" someservice.id="THE CLIENT ID
4- Inside the provided functions/index.js folder I add some code to set the code from step3
const functions = require('firebase-functions'); // already present
// don't know what to add here???
5- To deploy the code I run:
$ firebase deploy --only functions
6- Now that the code is in the cloud I can somehow call that code from within in my app to safely access the keys?
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
static var fbServerKey = somehow_Call_The_Firebase_GetFunction_For_This_Server_Key
override init() {
super.init()
Messaging.messaging().delegate = self
FirebaseApp.configure()
GMSPlacesClient.provideAPIKey(somehow_Call_The_Firebase_GetFunction_For_This_Places_Key) // places api credential key
GMSServices.provideAPIKey(somehow_Call_The_Firebase_GetFunction_For_This_Maps_Key) // maps api credential key
GMSPlacesClient.openSourceLicenseInfo()
GMSServices.openSourceLicenseInfo()
GADMobileAds.sharedInstance().start(completionHandler: nil)
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
}
}
I need help with steps 3, 4, and 6
This randomly started happening and I cannot get passed it. My app crashes on launch with this in the debug area.
2016-10-29 14:31:57.606 gigMe[2285:73317] Firebase automatic screen reporting is enabled. Call +[FIRAnalytics setScreenName:setScreenClass:] to set the screen name or override the default screen class name. To disable automatic screen reporting, set the flag FirebaseAutomaticScreenReportingEnabled to NO in the Info.plist
2016-10-29 14:31:57.783 gigMe[2285] [Firebase/Core][I-COR000003] The default Firebase app has not yet been configured. Add [FIRApp configure] to your application initialization. Read more: gives google address that i cant post on here
2016-10-29 14:31:57.911 gigMe[2285:73317] * Terminating app due to uncaught exception 'FIRAppNotConfigured', reason: 'Failed to get default FIRDatabase instance. Must call FIRApp.configure() before using FIRDatabase.' * First throw call stack:
I really dont understand this at all because i havent messed with anything that has to do with the database and this is my didFinishLaunchingWithOptions method:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
print("wtf")
FIRApp.configure()
return true
}
im not getting anything printed in the debugger either. anyone know what is going on?
This is not FIRApp.configure() error. You might be declaring a global variable with some class function in any of your class, like
class viewCon : UIViewController{
let ref = FIRDatabase.database().reference() // or a Storage reference
// This might be the error
}
The reason why this happens is because , you are trying to initialise a variable with a class function/property which might not even be configured as of yet. So try this:-
class viewCon : UIViewController{
let ref : FIRDatabaseReference!
// This might be the error or a Storage reference
override func viewDidLoad(){
super.viewDidLoad()
ref = FIRDatabase.database().reference()
}
}
To support above theory, try using breakpoints on let ref = FIRDatabase.database().reference() and FIRApp.configure(), and see which one gets called first. If let ref = FIRDatabase.database().reference() is called first , you are bound to have this error, as ref is trying to access FIRDatabase class, which hasn't been configured yet..
According to Google Doc here I tried whatever they said to do but all my efforts are in vain due to this error. But I didn't any change in info.plist.
2016-10-08 16:55:36.045 ContactApp[2674:83727] *** Terminating app due to uncaught exception 'GMSPlacesException', reason: 'Google Places API for iOS must be initialized via [GMSPlacesClient provideAPIKey:...] prior to use'
In my AppDelegate.swift I did look like below
import UIKit
import GoogleMaps
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
GMSServices.provideAPIKey("**********************")
return true
}
}
and I simply copied code and pasted to my controller. Here is also a link of my controller here
what can I do? Please provide any suggestion.
Use
GMSPlacesClient.provideAPIKey("YOUR_API_KEY")
instead of
GMSServices.provideAPIKey("**********************")
I am trying to integrate the Quickblox Webrtc Video Calling feature into a iOS Swift App. However, i'm having a lot of trouble with their SDK & api documentation, and it seems they don't have a tech team to help people with questions about their platforms, so maybe we can all help each other, so here are a few questions that I've noticed a lot of people have been asking on both StackOverFlow and Github regarding their webrtc SDK. Please restrict answers to the Swift language. The docs link is
http://quickblox.com/developers/SimpleSample-videochat-ios
My code so far:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
//Firebase config
FIRApp.configure()
//Quickblox config
QBSettings.setApplicationID(xxxxx)
QBSettings.setAuthKey("xxxxxxxxxxx")
QBSettings.setAuthSecret("xxxxxxxx-xxxx")
QBSettings.setAccountKey("xxxxxxxxxxxxxxxxxxxx")
return true
}
Thats my appdelegate.swift now for the part that giving me problems the actual videochatviewcontroller. The documentation is very vague at the start all is says is:
// Initialize QuickbloxWebRTC and configure signaling
// You should call this method before any interact with
QuickbloxWebRTC QBRTCClient.initializeRTC() // Call this method when
you finish your work with QuickbloxWebRTC
QBRTCClient.deinitializeRTC()
I do not know if I am to call this in my appdelegate.swift or if I should call this in VideoChatViewController's viewDidLoad method or should I create a new method altogether?
Secondly,the docs say to CALL USERS use this method, but its not a method, just random variables, also it doesn't tell tell whether it goes to the viewDidLoad or to a newly created method :
QBRTCClient.instance().addDelegate(self) // self class must conform to QBRTCClientDelegate protocol
// 2123, 2123, 3122 - opponent's
let opponentsIDs = [3245, 2123, 3122]
let newSession = QBRTCClient.instance().createNewSessionWithOpponents(opponentsIDs, withConferenceType: QBRTCConferenceType.Video)
// userInfo - the custom user information dictionary for the call. May be nil.
let userInfo :[String:String] = ["key":"value"]
newSession.startCall(userInfo)
Next, they are vague regarding the method to receive a new session, below they refer to self.session which they never explain where this variable is from or what it consist of
func didReceiveNewSession(session: QBRTCSession!, userInfo: [NSObject : AnyObject]!) {
if self.session != nil {
// we already have a video/audio call session, so we reject another one
// userInfo - the custom user information dictionary for the call from caller. May be nil.
let userInfo :[String:String] = ["key":"value"]
session.rejectCall(userInfo)
}
else {
self.session = session
}
}
Does quickblox require authenticated Quickblox users to use their webrtc or can I Authenticate users with Firebase or parse?
Where do I use QBRTCConfig in the appdelegate or the viewDidLoad? I have tried both and have seen it used in both methods.