Unable to navigate to other view controller after Google sign-in - swift

How can I go to another view controller after successfully signing with google? I've tried "self.inputViewController?.performSegue(withIdentifier: "goToMain", sender: self)" in my App Delegate but not getting any respond. Am I supposed to add the method in App Delegate or the view controller with the sign-in button?
App Delegate
import UIKit
import Firebase
import GoogleSignIn
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate{
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
GIDSignIn.sharedInstance()?.clientID = "my_client_id"
GIDSignIn.sharedInstance()?.delegate = self
return true
}
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if let error = error {
print(error)
return
}
guard
let authentication = user?.authentication,
let idToken = authentication.idToken
else {
return
}
let credential = GoogleAuthProvider.credential(withIDToken: idToken,
accessToken: authentication.accessToken)
Auth.auth().signIn(with: credential) { authResult, error in
if let error = error {
let authError = error as NSError
print(authError.localizedDescription)
return
}
self.inputViewController?.performSegue(withIdentifier: "goToMain", sender: self)
}
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return GIDSignIn.sharedInstance().handle(url)
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}

Are you sure about the inputViewController is not nil? This may a reason for not working.
You can add a function to test this, or you can use the print function to check, or, you can use debug point to check inputViewController is nil or not.
I'd like to add comment but I don't have enough reputation point :).
Good luck.

Related

Google login user profile not updated to Firebase

I am new to Xcode and I am working on my Google sign-in project. After successfully logging in with google, I cannot find the user profile in firebase. I think I am missing the code for uploading user credentials to firebase. I can barely understand the documentation and I don't know what to do. By the way, how can I navigate to another view controller after signing in? I tried lots of ways but none of them work. Any help is appreciated.
My AppDelegate code:
import UIKit
import Firebase
import GoogleSignIn
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate{
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
GIDSignIn.sharedInstance()?.clientID = "//I have it in my actual code"
GIDSignIn.sharedInstance()?.delegate = self
return true
}
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if let error = error {
print(error)
return
}
guard
let authentication = user?.authentication,
let idToken = authentication.idToken
else {
return
}
let credential = GoogleAuthProvider.credential(withIDToken: idToken,
accessToken: authentication.accessToken)
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return GIDSignIn.sharedInstance().handle(url)
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
The code of the log-in view controller
import UIKit
import GoogleSignIn
class WelcomeViewController: UIViewController {
#IBOutlet weak var gooleButton: GIDSignInButton!
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
GIDSignIn.sharedInstance()?.presentingViewController = self
gooleButton.style = .wide
gooleButton.colorScheme = .dark
}
}
From what I see your code signs the user in with Google to get the credentials, but then doesn't call signIn(with: ) which is needed in order to sign in to Firebase Authentication.
Have a look at Step 3: authenticate with Firebase. While the code there looks a bit intimidating, that's mostly because it handled many different cases. At its minimum you can sign in to Firebase with your credentials by doing:
Auth.auth().signIn(with: credential) { authResult, error in
if let error = error {
let authError = error as NSError
print(error.localizedDescription)
return
}
// User is signed in
// ...
}

Can't get Firebase Dynamic Link

I am following this tutorial from Firebase to implement Direct Links into my app: Firebase Dynamic Links
My code in my app delegate never seems to run properly. When I run the project I am able to use the link and open the app. But none of the print statements will run so I can't tell if it ran successfully or not:
import UIKit
import Firebase
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
return true
}
func handleincomingDynamicLink(_ dynamicLink: DynamicLink) {
guard let url = dynamicLink.url else {
print("Thats weird. My dynamic object link has no url")
return
}
print("Your incoming link parameter is \(url.absoluteString)")
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity,
restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
let handled = DynamicLinks.dynamicLinks()
.handleUniversalLink(userActivity.webpageURL!) { dynamiclink, error in
guard error == nil else {
print("Found an error! \(error!.localizedDescription)")
return
}
if let dynamicLink = dynamiclink {
self.handleincomingDynamicLink(dynamicLink)
}
}
return handled
}
#available(iOS 9.0, *)
func application(_ app: UIApplication, open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any]) -> Bool {
return application(app, open: url,
sourceApplication: options[UIApplication.OpenURLOptionsKey
.sourceApplication] as? String,
annotation: "")
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?,
annotation: Any) -> Bool {
if let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) {
return true
}
return false
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
Xcode gives me this error after I use the link:
[connection] nw_read_request_report [C1] Receive failed with error "Software caused connection abort"
use below delegate method in SceneDelegate Class:
func scene(_ scene: UIScene, continue userActivity: NSUserActivity)

What is the best way to sign out and sign back into google in an iOS app?

I am currently signing my user out like this:
print(GIDSignIn.sharedInstance()?.currentUser != nil) // true - signed in
GIDSignIn.sharedInstance()?.signOut()
print(GIDSignIn.sharedInstance()?.currentUser != nil) // false - signed out
Here is my is My AppDelegate
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
// Intializing Google Sign In...
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().scopes = []
// FirebaseApp.app()?.options.clientID = "674329356626-ev6hn62oiqcj0o228nt85vv2bgroa45j.apps.googleusercontent.com"
return true
}
func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any])
-> Bool {
return GIDSignIn.sharedInstance().handle(url)
}
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
if error != nil{
print(error.localizedDescription)
return
}
let credential = GoogleAuthProvider.credential(withIDToken: user.authentication.idToken, accessToken: user.authentication.accessToken)
// Logging to Firebase...
Auth.auth().signIn(with: credential) { (res, err) in
if err != nil{
print((err?.localizedDescription)!)
return
}
// User Logged In Successfully...
// Sending Notification To UI...
NotificationCenter.default.post(name: NSNotification.Name("SIGNIN"), object: nil)
// Printing Email ID
print(res?.user.email)
}
// Check for sign in error
if let error = error {
if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue {
print("The user has not signed in before or they have since signed out.")
} else {
print("\(error.localizedDescription)")
}
return
}
// Post notification after user successfully sign in
NotificationCenter.default.post(name: .signInGoogleCompleted, object: nil)
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
Sign in code:
GIDSignIn.sharedInstance()?.signIn()
Once the user is signed in, what is the best way for me to sign them out and prompt for them to sign in again? Please note that I am using the GoogleSignIn api.
Also note that I setup my google sign in functionality from here https://developers.google.com/identity/sign-in/ios/start?ver=swift
What seems to be happening in my app is the when my sign out function executes the current user is set to nil. However, when the user is signed out I can still access the data from the signed out user. I want the user to be able to sign out of their current account and sign into a new account for which I can access data from their newly signed in account.
My app should not retain data from the previous logged out user.
GIDSignIn.sharedInstance()?.signOut()
I also setup my google sign with firebase which seemed to help

Clicking the Firebase dynamic link does not call the application (_: continue: restorationHandler :) method in AppDelegate

Using Firebase Dynamic Links, I want to be able to click a link to open an iOS app.
The app is under development and is not yet on the AppStore.
I set it while looking at the document, but even if the app is started by clicking the link, the application (_: continue: restorationHandler :) method in AppDelegate is not called.
I set it according to the following procedure. Is something wrong?
 
Add "pod 'Firebase / DynamicLinks'" to Podfile and install
Open the .xcworkspace file
Create Dynamic Links “https://XXXX.page.link/test”
Access “https://XXXX.page.link/apple-app-site-association”
{"applinks":{"apps":[],"details":[{"appID":"XXXXXXX.[Bundle
ID]","paths":["NOT /_/","/"]}]}}
Create a URL type to use for dynamic links
Enable "Associated Domains" and add "applinks: XXXX.page.link"
Implement AppDelegate as below
import UIKit
import Firebase
import FirebaseDynamicLinks
#UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
return true
}
// MARK: UISceneSession Lifecycle
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity,
restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
let handled = DynamicLinks.dynamicLinks().handleUniversalLink(userActivity.webpageURL!) { (dynamiclink, error) in
// ...
}
return handled
}
#available(iOS 9.0, *)
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
return application(app, open: url,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
annotation: "")
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
if let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) {
// Handle the deep link. For example, show the deep-linked content or
// apply a promotional offer to the user's account.
// ...
return true
}
return false
}
}
I was calling the scene method of SceneDelegate.
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
// Create the SwiftUI view that provides the window contents.
let rootView = ContentView()
// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: rootView)
self.window = window
window.makeKeyAndVisible()
}
guard let userActivity = connectionOptions.userActivities.first(where: { $0.webpageURL != nil }) else { return }
print("url: \(userActivity.webpageURL!)")
}
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
print("url: \(userActivity.webpageURL!)")
}
...
}
Implementation should be in SceneDelgate instead of AppDelegate

can't get notification from firebase - swift 4

I can't get any push Notidication.
I tried to send a notification from Firebase console, to all the users of the app.
The Console says that the notification been sent to one device (my device), but I do not get anything on my iPhone.
I'm running this code at AppDelegate.swift:
//
// AppDelegate.swift
// mt
//
// Created by ES on 15.6.2018.
// Copyright © 2018 ES. All rights reserved.
//
import UIKit
import Firebase
import FirebaseMessaging
import UserNotifications
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
UIApplication.shared.applicationIconBadgeNumber = 0
registerForPushNotifications()
FirebaseApp.configure()
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable : Any],
fetchCompletionHandler completionHandler: #escaping (UIBackgroundFetchResult) -> Void) {
let dict = userInfo["aps"] as! NSDictionary
let title = dict["alert"]
print ("#", title!)
}
func registerForPushNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) {
(granted, error) in
print("Permission granted: \(granted)")
guard granted else { return }
let viewAction = UNNotificationAction(identifier: "addToCal",
title: "New date available!",
options: [.foreground])
let newsCategory = UNNotificationCategory(identifier: "NEW_SESSION",
actions: [viewAction],
intentIdentifiers: [],
options: [])
UNUserNotificationCenter.current().setNotificationCategories([newsCategory])
self.getNotificationSettings()
}
}
func getNotificationSettings() {
UNUserNotificationCenter.current().getNotificationSettings { (settings) in
print("Notification settings: \(settings)")
guard settings.authorizationStatus == .authorized else { return }
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
}
}
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let tokenParts = deviceToken.map { data -> String in
return String(format: "%02.2hhx", data)
}
let token = tokenParts.joined()
print("Device Token: \(token)")
}
func application(_ application: UIApplication,
didFailToRegisterForRemoteNotificationsWithError error: Error) {
print("Failed to register: \(error)")
}
}
(I got the Token, so I think that my app have the permission to get notifications)