How to convert Google iOS Sign-In single page sample AppDelegate.h protocol -> to a segue to LoginPage ViewController AppDelegate.swift protocol? - ios

Google's Sign-In sample on GitHub SignInSampleForPod.xcworkspace creates a single page sign-in using the AppDelegate.h SignInViewController.m etc protocol.
However many apps, such as mine, prefer to segue to a Login Page only when a user makes a choice requiring verification. I just want the basic Google Profile info and authentication token.
I have the Google iOS ClientID configured enough so a segue to my LoginPage.swift shows the Google Sign-In button via AppDelegate.swift:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(
_ app: UIApplication,
open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]
) -> Bool {
var handled: Bool
handled = GIDSignIn.sharedInstance.handle(url)
if handled {
return true
}
// Handle other custom URL types.
// If not handled by this app, return false.
return false
}
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
if error != nil || user == nil {
// Show the app's signed-out state.
} else {
// Show the app's signed-in state.
}
}
return true
}
And LoginPage.swift:
class LoginViewController: UIViewController {
let signInConfig = GIDConfiguration.init(clientID: "foo-bar85.apps.googleusercontent.com")
override func viewDidLoad() {
super.viewDidLoad()
GIDSignIn.sharedInstance.signIn(with: signInConfig, presenting: self) { user, error in
guard error == nil else { return }
guard let user = user else { return }
let emailAddress = user.profile?.email
let fullName = user.profile?.name
let givenName = user.profile?.givenName
let familyName = user.profile?.familyName
let profilePicUrl = user.profile?.imageURL(withDimension: 320)
}
So my question is what is the AppDelegate.swift Google Sign-In code for the fields shown below to display the basic profile info:
// Show the app's signed-out state.
} else {
// Show the app's signed-in state.

I may not able to understand your problem clearly.
But I am trying to answer based on my understanding.
You can create a class (GoogleLoginManager) for all google login related stuff and create a button in UI then call this method (signIn) from button action.
#IBAction func googleButtonAction(_ sender: Any) {
GoogleLoginManager.shared.signIn(controller: self) { (profile) in
print("GoogleLogin profile : \(String(describing: profile.name)), \(String(describing: profile.email))")
} onFailure: { (error) in
print("GoogleLogin error : \(String(describing: error.localizedDescription))")
}
}
import Foundation
import GoogleSignIn
class GoogleLoginManager: SocialLogin {
fileprivate var onSuccess : success?
fileprivate var onFailure : failure?
static let shared = GoogleLoginManager()
private override init() { }
func signIn(controller: UIViewController, onSuccess : #escaping success, onFailure : #escaping failure) {
self.onSuccess = onSuccess
self.onFailure = onFailure
GIDSignIn.sharedInstance().clientID = GOOGLE_CLIENT_ID
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().presentingViewController = controller
GIDSignIn.sharedInstance().signIn()
// Automatically sign in the user.
// GIDSignIn.sharedInstance()?.restorePreviousSignIn()
}
func signOut() {
GIDSignIn.sharedInstance().signOut()
}
}
extension GoogleLoginManager : GIDSignInDelegate {
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!,
withError error: 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 if (error as NSError).code == GIDSignInErrorCode.canceled.rawValue {
print("user canceled the sign in request")
}
else {
print("\(error.localizedDescription)")
}
self.onFailure?(error)
return
}
var profile = SocialProfileModel.init(user: user)
profile.loginSuccess = true
self.onSuccess?(profile)
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!,
withError error: Error!) {
// Perform any operations when the user disconnects from app here.
print("GIDSignIn : didDisconnectWith")
}
}

I just had to modify my above AppDelegate.swift slightly - adding a standard UIbutton linked to the following action - gets the profile info:
#IBAction func LogInButtonTouched(_ sender: UIButton) {
GIDSignIn.sharedInstance.signIn(with: signInConfig, presenting: self) { user, error in
guard error == nil else { return }
guard let user = user else { return }
let emailAddress = user.profile?.email
let fullName = user.profile?.name
let givenName = user.profile?.givenName
let familyName = user.profile?.familyName
let profilePicUrl = user.profile?.imageURL(withDimension: 320)
print("GoogleLogin profile : \(String(describing: user.profile?.name)), \(String(describing: user.profile?.email))")
}
}

Related

How to handle the redirect URLs for the PianoID SDK iOS?

When I try to connect to Facebook in my iOS application, the app redirects me to the Facebook app and then there is a loop between the two apps, meaning that the user is being sent back and forth between the two apps without being able to complete the login process. I suspect that there is something missing in my code to properly handle the redirect URLs for the PianoID SDK and I would like to know what needs to be done to fix this issue.
this is my appDelegate class :
#objc class AppDelegate: FlutterAppDelegate, PianoIDDelegate {
private var flutterResult: FlutterResult? = nil
#Published private(set) var initialized = false
#Published private(set) var token: PianoIDToken?
var cookiessseion = ""
var startdate = ""
var enddate = ""
var pianoToken=""
func pianoID(_ pianoID: PianoOAuth.PianoID, didSignInForToken token: PianoOAuth.PianoIDToken!, withError error: Error!) {}
func pianoID(_ pianoID: PianoOAuth.PianoID, didSignOutWithError error: Error!) {}
func pianoIDSignInDidCancel(_ pianoID: PianoOAuth.PianoID) {}
override func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
PianoID.shared.endpointUrl = Settings.endpoint.api
PianoID.shared.aid = Settings.aid
PianoID.shared.isSandbox = true
PianoID.shared.signUpEnabled = true
PianoID.shared.googleClientId = Settings.clientId
PianoID.shared.delegate = self
PianoOAuth.PianoIDApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
GeneratedPluginRegistrant.register(with: self)
let name = Bundle.main.infoDictionary?["CFBundleName"]
let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"]
GEMConfig.sharedInstance().setAppInfo(name as? String, version: version as? String)
//FirebaseApp.configure()
guard let controller = window?.rootViewController as? FlutterViewController else {
fatalError("rootViewController is not type FlutterViewController")
}
let Channel = FlutterMethodChannel(name: "flutter.native/helper", binaryMessenger: controller.binaryMessenger)
Channel.setMethodCallHandler({
[weak self] (call: FlutterMethodCall, result: #escaping FlutterResult) -> Void in
if(call.method == "testpiano"){
self?.initPianoID()
self?.flutterResult = result
} else {
result(FlutterMethodNotImplemented)
}
})
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
/// Sign In callback
func signIn(result: PianoIDSignInResult!, withError error: Error!) {
if let r = result {
token = r.token
do {
let PianoIDTokenString = try JSONParserSwift.getJSON(object: token)
self.flutterResult?(PianoIDTokenString)
} catch {
print("Unexpected data error: \(error)")
}
} else {
}
}
/// Sign Out callback
func signOut(withError error: Error!) {
token = nil
}
/// Cancel callback
func cancel() {
}
private func initPianoID() {
PianoID.shared.signIn()
}
func openSettings(alert: UIAlertAction!) {
if let url = URL.init(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
override public func applicationDidBecomeActive(_ application: UIApplication) {
debugPrint("applicationDidBecomeActive")
if #available(iOS 14, *) {
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
ATTrackingManager.requestTrackingAuthorization { status in
}
}
}
}
}
extension Date {
func currentTimeMillis() -> Int64 {
return Int64(self.timeIntervalSince1970)
}
}
And this is the documentation : link

swift firebase google sign in not showing on console

I am trying to sign in to firestore auth using the following GoogleSignInViewController but it shows nothing on the firebase console -
import UIKit
import Firebase
import GoogleSignIn
class GoogleSignInViewController: UIViewController {
var googleSignIn = GIDSignIn.sharedInstance()
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
#IBAction func googleLoginBtnAction(_ sender: UIButton) {
print("sign in tapped")
self.googleAuthLogin()
}
func googleAuthLogin() {
self.googleSignIn?.presentingViewController = self
self.googleSignIn?.clientID = "419387986978-pbs8h2drcjk60svqf1d5mgj0pa436r7b.apps.googleusercontent.com"
self.googleSignIn?.delegate = self
self.googleSignIn?.signIn()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detailseg" {
let DestView = segue.destination as! DetailsViewController
}
}
}
extension GoogleSignInViewController: GIDSignInDelegate {
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error!) {
guard let user = user else {
print("Uh oh. The user cancelled the Google login.")
return
}
let userId = user.userID ?? ""
print("Google User ID: \(userId)")
let userIdToken = user.authentication.idToken ?? ""
print("Google ID Token: \(userIdToken)")
let userFirstName = user.profile.givenName ?? ""
print("Google User First Name: \(userFirstName)")
let userLastName = user.profile.familyName ?? ""
print("Google User Last Name: \(userLastName)")
let userEmail = user.profile.email ?? ""
print("Google User Email: \(userEmail)")
let googleProfilePicURL = user.profile.imageURL(withDimension: 150)?.absoluteString ?? ""
print("Google Profile Avatar URL: \(googleProfilePicURL)")
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
}
}
It shows the login page as follows ( only for demonstrational purpose) -
Then, my app (Fireupgoodsa) takes permission from google to sign in -
Then, google takes permissioin to share my email id. information with the project -
Then, it goes to the DetailViewController (shown in red color below)-
Also, it shows alert message in my official email id.that my account was signed in to a new device i.e. my iOS simulator, which proves that sign in HAS taken place.
So far, so good -
but there is nothing on the firebase console -
This also didn't help me - Not getting the email using Google Authentication in Firebase
I had asked a similar bounty question - How to signoutout user from firebase console in swift
The bounty lapsed, but the problem was not sorted.
I have also deleted the project and created a new project. The screenshot of the project overview is shown below -
Now, why does not it show anything on the Firebase console. Is it something with the settings, project name. Do I need to add a tag container or something ? (Also, please see the address bar in the image above to see if something is wrong). What am I missing out on ?
This has been bugging me for quite a while.
I am desperate for help.
Please give me a hand with this, will you ?
I am posting the complete code for "class GoogleSignInViewController" and "class AppDelegate"-
class GoogleSignInViewController:-
import UIKit
import Firebase
import GoogleSignIn
class GoogleSignInViewController: UIViewController {
var googleSignIn = GIDSignIn.sharedInstance()
#IBOutlet weak var emailField: UITextField!
#IBOutlet weak var passwordField: UITextField!
#IBAction func googleLoginBtnAction(_ sender: UIButton) {
print("sign in tapped")
self.googleAuthLogin()
}
#IBAction func googleLogoutBtnAction(_ sender: Any) {
let firebaseAuth = Auth.auth()
do {
try firebaseAuth.signOut()
print ("user is signed out")
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
}
}
func googleAuthLogin() {
self.googleSignIn?.presentingViewController = self
self.googleSignIn?.clientID = "9727299xxxxx-m0brc61v3a32br7b34pdjxxxxxxxxxxx.apps.googleusercontent.com"
self.googleSignIn?.delegate = self
self.googleSignIn?.signIn()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "detailseg" {
let DestView = segue.destination as! DetailsViewController
}
}
}
extension GoogleSignInViewController: GIDSignInDelegate {
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)
guard let idToken = user.authentication.idToken else {return}
guard let accessToken = user.authentication.accessToken else {return}
let credentials = GoogleAuthProvider.credential(withIDToken: idToken, accessToken: accessToken)
Auth.auth().signInAndRetrieveData(with: credentials, completion: { (user, error) in
if let err = error {
print ("failed to create with google account", err)
return
}
print("successfuly logged into Firebase with Google", user?.user.uid)
})
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
}
}
class AppDelegate:-
import UIKit
import GoogleSignIn
import Firebase
import CoreData
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
// Override point for customization after application launch.
GIDSignIn.sharedInstance().clientID = FirebaseApp.app()?.options.clientID
GIDSignIn.sharedInstance().delegate = self
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return GIDSignIn.sharedInstance().handle(url as URL?)
}
func sign(_ signIn: GIDSignIn!,
didSignInFor user: GIDGoogleUser!,
withError error: Error!) {
// 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
}
// Get credential object using Google ID token and Google access token
guard let authentication = user.authentication else {
return
}
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
accessToken: authentication.accessToken)
// Authenticate with Firebase using the credential object
Auth.auth().signIn(with: credential) { (authResult, error) in
if let error = error {
print("Error occurs when authenticate with Firebase: \(error.localizedDescription)")
}
// Post notification after user successfully sign in
// NotificationCenter.default.post(name: .signInGoogleCompleted, object: nil)
}
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
// Perform any operations when the user disconnects from app here.
print("User has disconnected")
}
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:.
}
}
The above codes works for me and show me signed in FirebaseAuth with my gmail id.:-
Note -This answer shows just how the user google/gmail sign-in on the FirebaseAuth console(which is what this question is all about) . I have not posted the code to show details in the DetailsiewController. I will post that code later when I have designed that.
Furthermore, If you want to write your Firebase Auth User UID to Firestore Document ID you can refer to the "class UserIdtoFirestoreViewController" of the question in the link:-
How to Show Firebase Auth User UID and also my Firestore doc uid as Stripe customer id

Firebase google signin authentication AppDelegate- Use of unresolved identifier 'isMFAEnabled'

I'm new to iOS development. I am trying to add google sign in to my app but i am facing an some problems.Code shows some "Use of unresolved identifier 'isMFAEnabled"and "Value of type 'AppDelegate' has no member 'showTextInputPrompt'".Please help me.I'm following this doc- https://firebase.google.com/docs/auth/ios/google-signin#swift_9 enter image description here
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 = FirebaseApp.app()?.options.clientID
GIDSignIn.sharedInstance().delegate = self
return true
}
func application(_ app: 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 let error = error {
print(error.localizedDescription)
return
}
guard let authentication = user.authentication else { return }
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
accessToken: authentication.accessToken)
Auth.auth().signIn(with: credential) { (authResult, error) in
if let error = error {
let authError = error as NSError
if (isMFAEnabled && authError.code == AuthErrorCode.secondFactorRequired.rawValue) {
// The user is a multi-factor user. Second factor challenge is required.
let resolver = authError.userInfo[AuthErrorUserInfoMultiFactorResolverKey] as! MultiFactorResolver
var displayNameString = ""
for tmpFactorInfo in (resolver.hints) {
displayNameString += tmpFactorInfo.displayName ?? ""
displayNameString += " "
}
self.showTextInputPrompt(withMessage: "Select factor to sign in\n\(displayNameString)", completionBlock: { userPressedOK, displayName in
var selectedHint: PhoneMultiFactorInfo?
for tmpFactorInfo in resolver.hints {
if (displayName == tmpFactorInfo.displayName) {
selectedHint = tmpFactorInfo as? PhoneMultiFactorInfo
}
}
PhoneAuthProvider.provider().verifyPhoneNumber(with: selectedHint!, uiDelegate: nil, multiFactorSession: resolver.session) { verificationID, error in
if error != nil {
print("Multi factor start sign in failed. Error: \(error.debugDescription)")
} else {
self.showTextInputPrompt(withMessage: "Verification code for \(selectedHint?.displayName ?? "")", completionBlock: { userPressedOK, verificationCode in
let credential: PhoneAuthCredential? = PhoneAuthProvider.provider().credential(withVerificationID: verificationID!, verificationCode: verificationCode!)
let assertion: MultiFactorAssertion? = PhoneMultiFactorGenerator.assertion(with: credential!)
resolver.resolveSignIn(with: assertion!) { authResult, error in
if error != nil {
print("Multi factor finanlize sign in failed. Error: \(error.debugDescription)")
} else {
self.navigationController?.popViewController(animated: true)
}
}
})
}
}
})
} else {
print(error.localizedDescription)
return
}
// ...
return
}
// User is signed in
// ...
}
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
let firebaseAuth = Auth.auth()
do {
try firebaseAuth.signOut()
} catch let signOutError as NSError {
print ("Error signing out: %#", signOutError)
}
So the boilerplate is wayyyy more code than you need. This is my review of your AppDelegate.
didFinishLaunchingWithOptions looks good as-is.
Pro tip: add this line for staying logged in GIDSignIn.sharedInstance()?.restorePreviousSignIn()
open,options looks good as-is.
didSignInFor user is where it gets tangled. Delete the entire function and replace it with the following extension (outside the class' brackets):
(also delete GIDSignInDelegate in the class protocols)
extension AppDelegate: GIDSignInDelegate {
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
//handle sign-in errors
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 signing into Google \(error.localizedDescription)")
}
return
}
// Get credential object using Google ID token and Google access token
guard let authentication = user.authentication else { return }
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
accessToken: authentication.accessToken)
// Authenticate with Firebase using the credential object
Auth.auth().signIn(with: credential) { (authResult, error) in
if let error = error {
print("authentication error \(error.localizedDescription)")
}
}
}
}
I have tested this in today and it's currently working (Swift 5/ios 13.6).
TL;DR; you can just delete that variable if you don't want to enable multi-factor authentication.
The Firebase documentation provides the variable as a way for you to enable/disable multi-factor (MF) authentication (i.e. when facebook sends you a text message for you to verify). It's more like they are giving you an incomplete template that doesn't compile unless you declare and set this variable (among other things like implementing showTextInputPrompt).
The code provided in firebase documentation is an example, so don't expect it to work out of the box.

Thread 1: EXC_BAD_ACCESS (code=1, address=0x0) When working in swift trying to login to spotify

Code:
//
// AppDelegate.swift
// SplitterSwift3
//
// Created by VideoLabN on 4/8/18.
// Copyright © 2018 VideoLabN. All rights reserved.
//
import UIKit
import AWSAuthCore
import AWSMobileClient
import AWSCore
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var auth = SPTAuth()
// Add a AWSMobileClient call in application:open url
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
// called when user signs into spotify. Session data saved into user defaults, then notification posted to call updateAfterFirstLogin in ViewController.swift. Modeled off recommneded auth flow suggested by Spotify documentation
if auth.canHandle(auth.redirectURL) {
auth.handleAuthCallback(withTriggeredAuthURL: url, callback: { (error, session) in
if error != nil {
print("error!")
}
let userDefaults = UserDefaults.standard
let sessionData = NSKeyedArchiver.archivedData(withRootObject: session)
print(sessionData)
userDefaults.set(sessionData, forKey: "SpotifySession")
userDefaults.synchronize()
NotificationCenter.default.post(name: Notification.Name(rawValue: "loginSuccessfull"), object: nil)
})
return true
}
return false
}
//Add a AWSMobileClient call in application:didFinishLaunching
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions:
[UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return AWSMobileClient.sharedInstance().interceptApplication(
application, didFinishLaunchingWithOptions:
launchOptions)
}
}
//
// ViewController.swift
// SplitterSwift3
//
// Created by VideoLabN on 4/8/18.
// Copyright © 2018 VideoLabN. All rights reserved.
//
import UIKit
import SafariServices
import AVFoundation
import AWSAuthCore
import AWSAuthUI
class ViewController: UIViewController, SPTAudioStreamingPlaybackDelegate, SPTAudioStreamingDelegate {
// Variables
var auth = SPTAuth.defaultInstance()!
var session:SPTSession!
// Initialzed in either updateAfterFirstLogin: (if first time login) or in viewDidLoad (when there is a check for a session object in User Defaults
var player: SPTAudioStreamingController?
var loginUrl: URL?
// Outlets
#IBOutlet weak var loginSpotify: UIButton!
#IBOutlet weak var loginSplitter: UIButton!
#IBOutlet weak var testLabel: UILabel!
override func viewDidLoad() {
print("test")
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.setup()
//NotificationCenter.default.addObserver(self, selector: #selector(ViewController.updateAfterFirstLogin, name: NSNotification.Name(rawValue: "loginSuccessfull"), object: nil)
//self.updateAfterFirstLogin()
}
func setup () {
// insert redirect your url and client ID below
let redirectURL = "splitter-app://callback" // put your redirect URL here
let clientID = "207ce42c908f42e485c540be11720888" // put your client ID here
auth.redirectURL = URL(string: redirectURL)
auth.clientID = "client id goes here"
auth.requestedScopes = [SPTAuthStreamingScope, SPTAuthPlaylistReadPrivateScope, SPTAuthPlaylistModifyPublicScope, SPTAuthPlaylistModifyPrivateScope]
loginUrl = auth.spotifyWebAuthenticationURL()
//print("test")
}
func initializePlayer(authSession:SPTSession){
if self.player == nil {
self.player = SPTAudioStreamingController.sharedInstance()
self.player!.playbackDelegate = self
self.player!.delegate = self
try! player!.start(withClientId: auth.clientID)
self.player!.login(withAccessToken: authSession.accessToken)
}
}
#objc func updateAfterFirstLogin () {
loginSpotify.isHidden = true
let userDefaults = UserDefaults.standard
if let sessionObj:AnyObject = userDefaults.object(forKey: "SpotifySession") as AnyObject? {
let sessionDataObj = sessionObj as! Data
let firstTimeSession = NSKeyedUnarchiver.unarchiveObject(with: sessionDataObj) as! SPTSession
self.session = firstTimeSession
initializePlayer(authSession: session)
}
}
func audioStreamingDidLogin(_ audioStreaming: SPTAudioStreamingController!) {
// after a user authenticates a session, the SPTAudioStreamingController is then initialized and this method called
print("logged in")
//
self.player?.playSpotifyURI("spotify:track:58s6EuEYJdlb0kO7awm3Vp",
startingWith: 0, startingWithPosition: 0, callback: { (error) in
// if (error != nil) {
// print("playing!")
// }
//
// })
}
#IBAction func spotifyButtonPressed(_ sender: Any) {
let svc = SFSafariViewController(url: loginUrl!)
self.present(svc, animated: true, completion: nil)
//UIApplication.shared.open(loginUrl!, options: [:])
}
}
The application compiles just fine and launches on the simulator IPhone. The button to login to Spotify works, and opens a Safari instance prompting the user to login to Spotify.
Once the user has logged in, it then asks for permissions. Once the user accepts the permissions, the app crashes on line 16 of the appDelegate class with this error:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x0).
I have read up on this online and people are saying it is the equivalent to a null pointer exception, but I cannot find what is causing this error. Can anyone find the error?
Edit: Thanks to those that have responded! Here is my console output:
objc[19082]: Class VCWeakObjectHolder is implemented in both
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/AVConference.framework/Frameworks/ViceroyTrace.framework/ViceroyTrace
(0x12b9174d0) and
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/PrivateFrameworks/AVConference.framework/AVConference
(0x12aa65e38). One of the two will be used. Which one is undefined.
test 2018-04-15 13:33:50.341600-0400 SplitterSwift3[19082:1059086]
[AXRun-PID] Client requesting unsuspension of PID:-1 Name:
2018-04-15 13:33:50.441522-0400 SplitterSwift3[19082:1058985] [MC]
System group container for systemgroup.com.apple.configurationprofiles
path is
/Users/videolabn/Library/Developer/CoreSimulator/Devices/CEC32A65-63E0-4499-AB25-6BD13A7AE013/data/Containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2018-04-15 13:33:50.442782-0400 SplitterSwift3[19082:1058985] [MC]
Reading from private effective user settings. 2018-04-15
13:33:50.536744-0400 SplitterSwift3[19082:1058985] [App] if we're in
the real pre-commit handler we can't actually add any new fences due
to CA restriction (lldb)
The UIApplicationDelegate function application(_:open:sourceApplication:annotation:) was deprecated in iOS 10.
As of iOS 11.3 it seems that apps using this function will crash when it is invoked. The solution is is to use the replacement application(_:open:options:) instead.
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if auth.canHandle(auth.redirectURL) {
auth.handleAuthCallback(withTriggeredAuthURL: url, callback: { (error, session) in
if error != nil {
print("error!")
}
let userDefaults = UserDefaults.standard
let sessionData = NSKeyedArchiver.archivedData(withRootObject: session)
print(sessionData)
userDefaults.set(sessionData, forKey: "SpotifySession")
NotificationCenter.default.post(name: Notification.Name(rawValue: "loginSuccessfull"), object: nil)
})
return true
}
return false
}
Also, there is no need to call synchronize for UserDefaults

Not presenting Safari view on click of Google sign in button

I am clicking on the google sign in button but it is not presenting the SafariView, but the delegate methods of GIDSignInUIDelegate is called.
Besides this the delegate methods of GIDSignInDelegate are not called from the App Delegate .
What are the possible reasons? Below is the code given:
My URL Scheme:
com.googleusercontent.apps.1028134765971-6ok9n9pemgs3709q70so3bn5u08e84f6
AppDelegate.h
//
// AppDelegate.swift
// ESO
//
// Created by BBI USER 1027 on 23/05/17.
// Copyright © 2017 BBI. All rights reserved.
//
import UIKit
import Firebase
import GoogleSignIn
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
let signIn = GIDSignIn.sharedInstance()
signIn?.clientID = FirebaseApp.app()?.options.clientID!
signIn?.scopes = ["https://www.googleapis.com/auth/plus.login"]
signIn?.delegate = self
return true
}
func application(_ application: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any])
-> Bool {
print(GIDSignIn.sharedInstance().handle(url,
sourceApplication:options[UIApplicationOpenURLOptionsKey.sourceApplication] as? String,
annotation: [:]))
return GIDSignIn.sharedInstance().handle(url,
sourceApplication:options[UIApplicationOpenURLOptionsKey.sourceApplication] as? String,
annotation: [:])
}
//MARK : Google sign in delegate methods
func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!,
withError error: NSError!) {
if (error == nil) {
// Perform any operations on signed in user here.
let userId = user.userID // For client-side use only!
let idToken = user.authentication.idToken // Safe to send to the server
let fullName = user.profile.name
let givenName = user.profile.givenName
let familyName = user.profile.familyName
let email = user.profile.email
// ...
} else {
print("\(error.localizedDescription)")
}
}
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!, withError error: Error?) {
// ...
if let error = error {
// ...
return
}
guard let authentication = user.authentication else { return }
let credential = GoogleAuthProvider.credential(withIDToken: authentication.idToken,
accessToken: authentication.accessToken)
// ...
Auth.auth().signIn(with: credential) { (user, error) in
if let error = error {
// ...
return
}
// User is signed in
// ...
}
}
}
FBGoogleSigninViewController.swift
//
// FBGoogleSigninViewController.swift
// LoginModule
//
// Created by Shubham Ojha on 8/4/17.
// Copyright © 2017 BBI. All rights reserved.
//
import UIKit
import Firebase
import GoogleSignIn
class FBGoogleSigninViewController: UIViewController,GIDSignInUIDelegate {
#IBOutlet weak var segmentView: UISegmentedControl!
#IBOutlet weak var loginIDCustomTextField: CustomTextField!
#IBOutlet weak var passwordCustomTextField: CustomTextField!
#IBOutlet weak var loginIdLabel: UILabel!
// On click of this button I am not getting any response.
#IBOutlet weak var SignInButton: GIDSignInButton!
override func viewDidLoad() {
super.viewDidLoad()
GIDSignIn.sharedInstance().uiDelegate = self;
GIDSignIn.sharedInstance().signIn()
self.SignInButton.layer.cornerRadius = 5.0;
self.navigationController?.setNavigationBarHidden(false, animated: true)
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func segmentValueChanged(_ sender: Any) {
let segment = sender as! UISegmentedControl
if segment.selectedSegmentIndex == 0 {
self.loginIdLabel.text = "Login ID"
self.SignInButton.backgroundColor = UIColor.blue
}
else{
self.loginIdLabel.text = "Email ID"
self.SignInButton.backgroundColor = UIColor.red
}
}
// MARK: google sign in delegate methods
public func sign(inWillDispatch signIn: GIDSignIn!, error: Error!){
}
func sign(_ signIn: GIDSignIn!, present viewController: UIViewController!){
print(viewController.description)
}
}

Resources