Apple sign in delegate methods not calling? - swift

I implemented apple sign in in separate NSObject class and calling from viewController.Whenever I click apple signing button, signin dialog appears with password field.After filling password dialog, signin dialog dismisses and delegate methods not calling.Any idea why delegates not calling.
Note: I added all configurations in Xcode and developer portals.
import AuthenticationServices
class AppleSignin: NSObject {
var successCompletionHandler : ResponseCompletionHandler?
private var authorizationController: ASAuthorizationController?
func signIn(completion: #escaping ResponseCompletionHandler) {
self.vc = vc
self.successCompletionHandler = completion
let appleIDProvider = ASAuthorizationAppleIDProvider()
let request = appleIDProvider.createRequest()
request.requestedScopes = [.fullName, .email]
let authorizationController = ASAuthorizationController(authorizationRequests: [request])
authorizationController.delegate = self
authorizationController.presentationContextProvider = getWindow()
authorizationController.performRequests()
self.authorizationController = authorizationController
}
}
extension AppleSignin: ASAuthorizationControllerDelegate {
// Authorization Failed
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
successCompletionHandler?(.failure(error))
}
// Authorization Succeeded
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential {
var response = SignInResponse()
response.firstName = appleIDCredential.fullName?.givenName
response.lastName = appleIDCredential.fullName?.familyName
response.emailId = appleIDCredential.email
successCompletionHandler?(.success(response))
} else if let passwordCredential = authorization.credential as? ASPasswordCredential {
// Get user data using an existing iCloud Keychain credential
var response = SignInResponse()
response.firstName = passwordCredential.user
response.emailId = passwordCredential.password
successCompletionHandler?(.success(response))
}
}
}

Related

```webAuthSession.presentationContextProvider = self``` ERROR: cannot find self in scope

I am trying to implement a web authentication service in my app however, when I try to put webAuthSession.presentationContextProvider = self , I get an error saying Cannot find 'self' in scope. All the turorials I have followed did the same thing without any errors. I am truly desperate so any help would be appreciated.
Thank you very much in advance!
import Foundation
import AuthenticationServices
import CryptoKit
typealias ASPresentationAnchor = UIWindow
class SignInViewModel: NSObject, ObservableObject, ASWebAuthenticationPresentationContextProviding {
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return ASPresentationAnchor()
}
}
public func UrlGenerator() -> URL {
func randomString(length: Int) -> String {
let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
return String((0..<length).map{ _ in letters.randomElement()! })
}
let code_verifier = randomString(length: 86)
let hashdata = Data(code_verifier.utf8)
let code_challenge_data = SHA256.hash(data: hashdata)
let code_challenge_generated = code_challenge_data.compactMap { String(format: "%02x", $0) }.joined()
let url = "auth.tesla.com/oauth2/v3/authorize"
let client_id = "ownerapi"
let code_challenge = "\(code_challenge_generated)"
let code_challenge_method = "S256"
let redirect_uri = "https://auth.tesla.com/void/callback"
let response_type = "code"
let scope = "openid+email+offline_access"
let state = "\(code_verifier)"
let TeslaLink = "\(url)?client_id=\(client_id)&code_challenge=\(code_challenge)&code_challenge_method=\(code_challenge_method)&redirect_uri=\(redirect_uri)&response_type=\(response_type)&scope=\(scope)&state=\(state)"
let TeslaLinkURL = URL(string: TeslaLink)!
return TeslaLinkURL
}
let webAuthSession = ASWebAuthenticationSession.init(
url: UrlGenerator(),
callbackURLScheme: "TESRIUM",
completionHandler: { (callback:URL?, error:Error?) in
})
public func TeslaSignIn() {
webAuthSession.presentationContextProvider = self
webAuthSession.prefersEphemeralWebBrowserSession = false
webAuthSession.start()
}
To answer your question, the reason self is not available is because you're referring to it in the global context and self has no meaning in the global context. self must refer to an object and self in the global scope is an environment, not an object.
The reason your specific code doesn't work is because you've separated the instantiation of webAuthSession from the work you perform on it. In the tutorial, webAuthSession = ASWebAuthenticationSession.init... and webAuthSession?.presentationContextProvider = self are in the same scope. Therefore, simply merge them together into the same function. Now, where that function is also matters because if it's a global function you'll have the same problem. You need to place this function into the right object so self is referring to what it's supposed to refer to.
public func TeslaSignIn() {
let webAuthSession = ASWebAuthenticationSession.init(
url: UrlGenerator(),
callbackURLScheme: "TESRIUM",
completionHandler: { (callback:URL?, error:Error?) in
})
webAuthSession.presentationContextProvider = self
webAuthSession.prefersEphemeralWebBrowserSession = false
webAuthSession.start()
}

SwiftUI - Firebase Apple Auth not authenticating

im fairly new to swiftUI... pardon the ignorance :) I have most of the code entered in my project from the instructions on the Firebase website. For some reason apple authentication will not successfully authenticate. No idea why, I suspect the nonce part of the code located in 'ConentView' is potentially not being linked to the service. If anyone has any thoughts on why this is occurring I would be greatly appreciative for any help?
Xcode simulator - will not load past this screen
ContentView:
import SwiftUI
import FirebaseAuthUI
import CryptoKit
import AuthenticationServices
struct ContentView: View {
private func sha256(_ input: String) -> String {
let inputData = Data(input.utf8)
let hashedData = SHA256.hash(data: inputData)
let hashString = hashedData.compactMap {
String(format: "%02x", $0)
}.joined()
return hashString
}
#ObservedObject private var authStateManager =
FirebaseAuthStateManager()
#State var isShowSheet = false
#State var currentNonce:String?
private func randomNonceString(length: Int = 32) ->
String {
precondition(length > 0)
let charset: [Character] =
***key***
var result = ""
var remainingLength = length
while remainingLength > 0 {
let randoms: [UInt8] = (0 ..< 16).map { _ in
var random: UInt8 = 0
let errorCode =
SecRandomCopyBytes(kSecRandomDefault, 1, &random)
if errorCode != errSecSuccess {
fatalError(
"Unable to generate nonce. SecRandomCopyBytes
failed with OSStatus \(errorCode)"
)
}
return random
}
randoms.forEach { random in
if remainingLength == 0 {
return
}
if random < charset.count {
result.append(charset[Int(random)])
remainingLength -= 1
}
}
}
return result
}
func authorizationController(controller:
ASAuthorizationController, didCompleteWithAuthorization
authorization: ASAuthorization) {
if let appleIDCredential = authorization.credential
as? ASAuthorizationAppleIDCredential {
guard let nonce = currentNonce else {
fatalError("Invalid state: A login callback was
received, but no login request was sent.")
}
guard let appleIDToken =
appleIDCredential.identityToken else {
print("Unable to fetch identity token")
return
}
guard let idTokenString = String(data: appleIDToken,
encoding:
.utf8) else {
print("Unable to serialize token string from data: \
(appleIDToken.debugDescription)")
return
}
// Initialize a Firebase credential.
let credential =
OAuthProvider.credential(withProviderID:"apple.com",
idToken: idTokenString,rawNonce: nonce)
// Sign in with Firebase.
Auth.auth().signIn(with: credential) { (authResult,
error) in
if (error != nil) {
// Error. If error.code ==
.MissingOrInvalidNonce, make sure
// you're sending the SHA256-hashed nonce as a
hex string with
// your request to Apple.
print(error?.localizedDescription as Any)
return
}
// User is signed in to Firebase with Apple.
// ...
}
}
func authorizationController(controller:
ASAuthorizationController, didCompleteWithError error:
Error) {
// Handle error.
print("Sign in with Apple errored: \(error)")
}
}
var body: some View {
VStack {
if authStateManager.signInState == false {
// Sign-Out
Button(action: {
self.isShowSheet.toggle()
}) {
Text("Sign-In")
}
} else {
// Sign-In
Button(action: {
do {
try Auth.auth().signOut()
} catch {
print("Error")
}
}) {
Text("Sign-Out")
}
}
}
.sheet(isPresented: $isShowSheet) {
FirebaseUIView(isShowSheet: self.$isShowSheet)
}
}
}
FirebaseUIView:
import SwiftUI
import FirebaseAuthUI
import FirebaseGoogleAuthUI
import FirebaseOAuthUI
import CryptoKit
import AuthenticationServices
import FirebaseEmailAuthUI
struct FirebaseUIView: UIViewControllerRepresentable {
#Binding var isShowSheet: Bool
class Coordinator: NSObject,
FUIAuthDelegate {
// FirebaseUIView
let parent: FirebaseUIView
//
init(_ parent: FirebaseUIView) {
self.parent = parent
}
// MARK: - FUIAuthDelegate
func authUI(_ authUI: FUIAuth, didSignInWith user:
User?, error: Error?) {
// handle user and error as necessary
if let error = error {
//
print("Auth NG:\
(error.localizedDescription)")
}
if let _ = user {
//
}
// Sheet(ModalView)
parent.isShowSheet = false
}
}
func makeCoordinator() -> Coordinator {
// Coordinator
Coordinator(self)
}
func makeUIViewController(context: Context) ->
UINavigationController {
let authUI = FUIAuth.defaultAuthUI()!
// You need to adopt a FUIAuthDelegate protocol to
receive callback
authUI.delegate = context.coordinator
let providers: [FUIAuthProvider] = [
FUIGoogleAuth(authUI: authUI),
FUIOAuth.microsoftAuthProvider(),
// FUIFacebookAuth(authUI: authUI),
// FUIOAuth.twitterAuthProvider(),
FUIEmailAuth(),
// FUIPhoneAuth(authUI:authUI),
FUIOAuth.appleAuthProvider(),
]
authUI.providers = providers
// FirebaseUI
let authViewController = authUI.authViewController()
return authViewController
}
func updateUIViewController(_ uiViewController:
UINavigationController, context: Context) {
}
}
[ContentView[][2]2
Check out SignInWithApple from FirebaseService: https://github.com/rebeloper/FirebaseService
Turns out there was nothing wrong with my code. The moment I switched from simulator to the actual iPhone device the code worked perfectly. This is a known BUG with the simulator in Xcode.

Google Spreadsheets APIS, confused

I had this working before but now it seems to have stopped. I am trying to run various googlesheets APIS such as read/write/create. I have installed the appropriate cocoa pods:
platform :ios, '10.0'
target 'Safety_App-Prototype' do
use_frameworks!
pod 'GoogleAnalytics'
pod 'GoogleAPIClientForREST/Sheets'
pod 'GoogleAPIClientForREST/Drive'
pod 'GoogleSignIn'
pod 'SVProgressHUD'
pod 'Firebase/Core'
pod 'Firebase/Analytics'
pod 'Firebase/Auth'
pod 'Firebase/Firestore'
end
I have created a google developer console project and included all relevant information into my app. (this includes the URL type under projects -> info tab as well as in my app delegate shown below:
//
// AppDelegate.swift
// Created by Michael Szabo on 2021-01-28.
//
import UIKit
import GoogleSignIn
#main
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
GIDSignIn.sharedInstance().clientID = "FORMYEYESONLY.apps.googleusercontent.com"
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?,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
annotation: options[UIApplication.OpenURLOptionsKey.annotation])
}
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 {
print("\(error.localizedDescription)")
}
return
}
// 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
// ...
print(fullName)
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
// Perform any operations when the user disconnects from app here.
print("User has disconnected")
}
// 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.
}
}
I have added a google signing button which allows me to sign in and asks for permission to read/write to sheets and added functions in my script to create/read/write to sheets as seen below:
// Created by Michael Szabo on 2021-02-21.
//
import GoogleAPIClientForREST
import GoogleSignIn
import UIKit
class JHA_pg1: UIViewController, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITextFieldDelegate, GIDSignInUIDelegate, GIDSignInDelegate {
var rowstart:NSNumber = 0
var rowend:NSNumber = 0
var columnstart:NSNumber = 0
var columnend:NSNumber = 0
var red:NSNumber = 1
var blue:NSNumber = 1
var green:NSNumber = 1
var range1 = ""
var text1 = ""
var text2 = ""
var text3 = ""
var bordertype = "SOLID"
var borderthick:NSNumber = 3
var inbortype = "NONE"
var inborthick:NSNumber = 0
var spreadsheetId = ""
#IBOutlet weak var BeginAssessment: UIButton! //SubmitButton
let today = Date()
let formatter1 = DateFormatter()
let formatter = DateFormatter()
var date = String()
var buttontitle = String()
let defaults = UserDefaults.standard
private let scopes = [kGTLRAuthScopeSheetsSpreadsheets]
private let service = GTLRSheetsService()
//=========================================================================================================
//=========================================================================================================
override func viewDidLoad() {
super.viewDidLoad()
//=========================================================================================================
// Configure Google Sign-in.
GIDSignIn.sharedInstance().delegate = self
GIDSignIn.sharedInstance().uiDelegate = self
GIDSignIn.sharedInstance().scopes = scopes
GIDSignIn.sharedInstance().signInSilently()
}
//=========================================================================================================
//=========================================================================================================
//Submit Function
#IBAction func BeginAssessment(_ sender: Any) {
if(GIDSignIn.sharedInstance()?.currentUser != nil)
{
print("loggedIn")
}
else
{
print("not loggedIn")
}
spreadsheetId = "SOME ID"
rowstart = 0
rowend = 5
columnstart = 0
columnend = 7
unmergecell()
CreateSpreadSheet()
print(spreadsheetId)
}
//========================================================================================================
//Write To Sheet Function
func write() {
let range = range1
let updateValues = [[text1,text2,text3]]
let valueRange = GTLRSheets_ValueRange() // GTLRSheets_ValueRange holds the updated values and other params
valueRange.majorDimension = "ROWS" // Indicates horizontal row insert
valueRange.range = range
valueRange.values = updateValues
let query = GTLRSheetsQuery_SpreadsheetsValuesAppend.query(withObject: valueRange, spreadsheetId: spreadsheetId, range: range)
query.valueInputOption = "USER_ENTERED"
service.executeQuery(query) { ticket, object, error in}
}
//========================================================================================================
//Unmerge Cell Function
func unmergecell() {
let request = GTLRSheets_Request.init()
let test = GTLRSheets_GridRange.init()
test.startRowIndex = rowstart
test.endRowIndex = rowend
test.startColumnIndex = columnstart
test.endColumnIndex = columnend
request.unmergeCells = GTLRSheets_UnmergeCellsRequest.init()
request.unmergeCells?.range = test
let batchUpdate = GTLRSheets_BatchUpdateSpreadsheetRequest.init()
batchUpdate.requests = [request]
let createQuery = GTLRSheetsQuery_SpreadsheetsBatchUpdate.query(withObject: batchUpdate, spreadsheetId: spreadsheetId)
service.executeQuery(createQuery) { (ticket, result, NSError) in
}
}
}
//========================================================================================================
//Create Spreadsheet Function
func CreateSpreadSheet()
{
print("==============================================")
print("Createsheet Function")
let newSheet = GTLRSheets_Spreadsheet.init()
let properties = GTLRSheets_SpreadsheetProperties.init()
properties.title = "Daily JHA Form - "+date
newSheet.properties = properties
let query = GTLRSheetsQuery_SpreadsheetsCreate.query(withObject:newSheet)
query.fields = "spreadsheetId"
query.completionBlock = { (ticket, result, NSError) in
if let error = NSError {
print("error!!!!!!!!!!!!!!!!!!!!!!!!!!")
print(error)
}
else {
let response = result as! GTLRSheets_Spreadsheet
let identifier = response.spreadsheetId
self.spreadsheetId = identifier!
GlobalVariable1.sheetID = self.spreadsheetId
print(self.spreadsheetId)
}
}
service.executeQuery(query, completionHandler: nil)
}
//=========================================================================================================
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 {
print("\(error.localizedDescription)")
}
return
}
// 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
// ...
print(fullName)
}
//=========================================================================================================
// Display (in the UITextView) the names and majors of students in a sample
// spreadsheet:
//https://docs.google.com/spreadsheets/d/e/2PACX-1vTxKKu-0BwyOPq9HTYH237jGlMrf3q8kLwe5R2eH2dbkGqNbk3D7L9_MKxpO4b3g9cy09w2davohJzq/pubhtml
func listMajors() {
let range = "A1:Q"
let query = GTLRSheetsQuery_SpreadsheetsValuesGet
.query(withSpreadsheetId: spreadsheetId, range:range)
service.executeQuery(query) { (ticket, result, error) in
if let error = error {
self.showAlert(title: "Error", message: error.localizedDescription)
return
}
guard let result = result as? GTLRSheets_ValueRange else {
return
}
let rows = result.values!
if rows.isEmpty {
// self.output.text = "No data found."
return
}
// self.output.text = "Number of rows in sheet: \(rows.count)"
}
}
// Process the response and display output
func displayResultWithTicket(ticket: GTLRServiceTicket,
finishedWithObject result : GTLRSheets_ValueRange,
error : NSError?) {
if let error = error {
showAlert(title: "Error", message: error.localizedDescription)
return
}
var majorsString = ""
let rows = result.values!
if rows.isEmpty {
// output.text = "No data found."
return
}
majorsString += "Name, Major:\n"
for row in rows {
let name = row[0]
let major = row[4]
majorsString += "\(name), \(major)\n"
}
// output.text = majorsString
}
// Helper for showing an alert
func showAlert(title : String, message: String) {
let alert = UIAlertController(
title: title,
message: message,
preferredStyle: UIAlertController.Style.alert
)
let ok = UIAlertAction(
title: "OK",
style: UIAlertAction.Style.default,
handler: nil
)
alert.addAction(ok)
present(alert, animated: true, completion: nil)
}
}
struct GlobalVariable1
{
static var sheetID = ""
}
extension UIViewController {
func hideKeyboardWhenTappedAround() {
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(UIViewController.dismissKeyboard))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
#objc func dismissKeyboard() {
view.endEditing(true)
}
}
HOWEVER I get the following error:
Optional(Error Domain=com.google.GTLRErrorObjectDomain Code=401 "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project." UserInfo={GTLRStructuredError=GTLRErrorObject 0x600001182310: {errors:[1] message:"Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project." code:401 status:"UNAUTHENTICATED"}, NSLocalizedDescription=Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.})"
What am I doing wrong?
Looking to the error generated by your code, and the scopes you try to require, it seems they are not enough. Indeed you set only:
private let scopes = [kGTLRAuthScopeSheetsSpreadsheets]
According to this google official doc about scopes you can find more details about all the scopes.
In the middle part of your code you read profile informations and these info could be readed adding scopes about google sign in:
profile
email
It appears that I was missing an instruction in my functions being called. I also had to update a bit of my code for newer pod file "pod 'GoogleSignIn', '~> 5.0.2'" The instructions for this migration can be found here:
https://developers.google.com/identity/sign-in/ios/quick-migration-guide
The portion of code I needed to add to my functions is a simple line which can be seen here:
service.authorizer = GIDSignIn.sharedInstance().currentUser.authentication.fetcherAuthorizer()
I hope this helps someone else out (pass it on.)
Thank you.

Passing data from Scene Delegate to ViewController when opening app with URL

I need to Show a View on my initial controller and set a UILabel when the app launches through URL Dynamic Link during Firebase Email Verification.
Problem I'm having is the label is not initialised so app crashes during the process. I have tried many approaches but can't get it to show my view and set the label when opening a Dynamic Link, even when the App is already open.
Scene Delegate
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
if let link = userActivity.webpageURL?.absoluteString
{
if Auth.auth().isSignIn(withEmailLink: link) {
Config().verifyEmail(link: link)
}
}
}
AppDelegate
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
var errorText: String?
var errorType: Bool?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
return true
}
ViewController
func loadErrorInfo()
{
let appDelegate = UIApplication.shared.delegate as! AppDelegate
if let eText = appDelegate.errorText, let eType = appDelegate.errorType {
errorCall(message: eText, error: eType)
} else {
errorBox.isHidden = true
}
}
func errorCall(message: String, error: Bool)
{
if error {
self.errorLabel.textColor = UIColor.yellow
self.errorLabel.text = message
self.errorBox.isHidden = false
self.errorBox.shake()
} else {
self.errorLabel.textColor = UIColor.white
self.errorLabel.text = message
self.errorBox.isHidden = false
self.errorBox.shakeL()
}
}
Custom Config NSObject Class
import UIKit
import FirebaseAuth
open class Config: NSObject {
public func verifyEmail(link: String)
{
var email = ""; var password = ""
if let x = UserDefaults.standard.object(forKey: "Email") as? String { email = x }
if let y = UserDefaults.standard.object(forKey: "Password-\(email)") as? String { password = y }
if password != "" && email != ""
{
Auth.auth().signIn(withEmail: email, link: link) { (user, error) in
if let use = user, error == nil
{
Auth.auth().currentUser?.updatePassword(to: password) { (error) in
if let error = error
{
print(error)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.errorText = error.localizedDescription
appDelegate.errorType = true
ViewController().loadErrorInfo()
}
else
{
print(use, "Logged In")
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.errorText = "\(use) Logged In"
appDelegate.errorType = false
ViewController().loadErrorInfo()
}
}
}
}
}
}
}
Not sure what other method will work. To summarise, after clicking a Dynamic Link in an Email, I want to Change my UILabel on main ViewController which is an initial controller. At the moment every approach causes it to crash as the UILabel is not Set, even if the controller is already initialised.
Managed to fix it by initialising the controller again and updating the root controller.
// SceneDelegate
func changeRootViewController(_ vc: UIViewController, animated: Bool = true)
{
guard let window = self.window else {
return
}
window.rootViewController = vc
}
//Reinitialise
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let destinationNavigationController = storyboard.instantiateViewController(withIdentifier: "ViewController2")
(UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.changeRootViewController(destinationNavigationController)

How to get Unauthenticated identity using Swift

I have initialized the credentials provider per this AWS Developer Guide. I'm not sure if it worked, and how to check. I can't seem to find any documentation on how to use Cognito with Swift. I'm running it as a unit test, and the test passes and the line print("identityId", identityId) outputs:
identityId <AWSTask: 0x17d5fde0; completed = NO; cancelled = NO; faulted = NO;>
However, during debug the property identityProvider.identityId is nil.
Here are my files:
// MyAuth.swift
import Foundation
import AWSCognito
class MyAuth {
func getUnauthCognitoId()->Bool {
let identityProvider = MyIdentityProvider()
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.USEast1, identityProvider: identityProvider, unauthRoleArn: Constants.ARNUnauth.value, authRoleArn: Constants.ARNAuth.value)
let defaultServiceConfiguration = AWSServiceConfiguration(region: .USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration
if let identityId = identityProvider.getIdentityId() {
print("identityId", identityId)
return true
} else {
return false
}
}
}
And
// MyIdentityProvider.swift
import Foundation
import AWSCognito
class MyIdentityProvider: AWSAbstractCognitoIdentityProvider {
var _token: String!
var _logins: [ NSObject : AnyObject ]!
// Header stuff you may not need but I use for auth with my server
/*let acceptHeader = "application/vnd.exampleapp-api+json;version=1;"
let authHeader = "Token token="
let userDefaults = NSUserDefaults.standardUserDefaults()
let authToken = self.userDefaults.valueForKey("authentication_token") as String*/
// End point that my server gives amazon identityId and tokens to authorized users
let url = "https://api.myapp.com/api/amazon_id/"
func authenticatedWithProvider()->Bool {
if let logins = _logins {
return logins["ProviderName"] == nil
}
else {
return false
}
}
override var token: String {
get {
return _token
}
}
override var logins: [ NSObject : AnyObject ]! {
get {
return _logins
}
set {
_logins = newValue
}
}
override func getIdentityId() -> AWSTask! {
if self.identityId != nil {
return AWSTask(result: self.identityId)
}
else if(!self.authenticatedWithProvider()) {
return super.getIdentityId()
}
else{
return AWSTask(result: nil).continueWithBlock({ (task) -> AnyObject! in
if self.identityId == nil {
return self.refresh()
}
return AWSTask(result: self.identityId)
})
}
}
override func refresh() -> AWSTask! {
let task = AWSTaskCompletionSource()
if(!self.authenticatedWithProvider()) {
return super.getIdentityId()
}
else {
// TODO: Authenticate with developer
return task.task
}
/*let request = AFHTTPRequestOperationManager()
request.requestSerializer.setValue(self.acceptHeader, forHTTPHeaderField: "ACCEPT")
request.requestSerializer.setValue(self.authHeader+authToken, forHTTPHeaderField: "AUTHORIZATION")
request.GET(self.url, parameters: nil, success: { (request: AFHTTPRequestOperation!, response: AnyObject!) -> Void in
// The following 3 lines are required as referenced here: http://stackoverflow.com/a/26741208/535363
var tmp = NSMutableDictionary()
tmp.setObject("temp", forKey: "ExampleApp")
self.logins = tmp
// Get the properties from my server response
let properties: NSDictionary = response.objectForKey("properties") as NSDictionary
let amazonId = properties.objectForKey("amazon_identity") as String
let amazonToken = properties.objectForKey("token") as String
// Set the identityId and token for the ExampleAppIdentityProvider
self.identityId = amazonId
self._token = amazonToken
task.setResult(response)
}, failure: { (request: AFHTTPRequestOperation!, error: NSError!) -> Void in
task.setError(error)
})*/
return task.task
}
}
And
import XCTest
#testable import My
class MyTests: XCTestCase {
override func setUp() {
super.setUp()
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
super.tearDown()
}
func testExample() {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
func testPerformanceExample() {
// This is an example of a performance test case.
self.measureBlock {
// Put the code you want to measure the time of here.
}
}
func testGetUnauthCognitoId() {
let myAuth = MyAuth()
XCTAssertTrue(myAuth.getUnauthCognitoId())
}
}
It turns out that if you create a default service configuration within the application:didFinishLaunchingWithOptions: application delegate method in your app delegate file as described here:
let credentialsProvider = AWSCognitoCredentialsProvider(
regionType: AWSRegionType.USEast1, identityPoolId: cognitoIdentityPoolId)
let defaultServiceConfiguration = AWSServiceConfiguration(
region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = defaultServiceConfiguration
The SDK will use an unauthenticated identity whenever you try to use any of the AWS services, and you don't necessarily need to create a cognitoIdentity object.
getIdentityId returns an AWSTask. Since AWSTask is essentially BFTask with a different name, you can get the identityId using the continueWithBlock syntax shown on the BFTask page. Something like:
credentialProvider.getIdentityId().continueWithBlock {
(task: AWSTask!) -> AWSTask in
if task.error() {
// failed to retrieve identityId.
} else {
print("identityId", task.result())
}