AWS Cognito API `AWSMobileClient.default().addUserStateListener` only fires when user authentication state changes - swift

I am using xcode 11 with swift 4. I am following the docs for aws cognito here https://aws-amplify.github.io/docs/ios/authentication and in AppDelegate.swift, I have:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// initialize AWS amplify
let apiPlugin = AWSAPIPlugin(modelRegistration: AmplifyModels())
do {
try Amplify.add(plugin: apiPlugin)
try Amplify.configure()
} catch {
// Navigate to page showing bad network connection
print("Failed to configure Amplify \(error)")
}
AWSMobileClient.default().addUserStateListener(self) { (userState, info) in
switch (userState) {
case .signedOut:
// user clicked signout button and signedout
print("AppDelegate.application state: user signed out")
case .signedIn:
print("AppDelegate.application state: user signed in: \(userState)")
case .signedOutUserPoolsTokenInvalid:
print("need to login again.")
default:
print("unsupported")
}
}
return true
}
The AWSMobileClient.default().addUserStateListener only fires when the user is logging in or signing up for the first time. if the user is already authenticated. then addUserStateListener does not fire. This is an issue because I need to get the user's account token to access his/her information. Am I using the wrong Cognito API? Or is addUserStateListener used in the wrong function.
If I use the other Cognito API
AWSMobileClient.default().initialize { (userState, error) ... }
It fires each time, but I cannot access the user token from this api.

You can access the user token by using the AWSAppSync api and this method in you app delegate either by extending appDelegate or using your own custom class as I did.
class CognitoPoolProvider : AWSCognitoUserPoolsAuthProviderAsync {
func getLatestAuthToken(_ callback: #escaping (String?, Error?) -> Void) {
AWSMobileClient.default().getTokens { (token, error) in
if let error = error {
callback(nil,error)
}
callback(token?.accessToken?.tokenString, error)
}
}
}
So, in my appDelegate I did something like this
var appSyncClientBridge : AWSAppSyncClient?
/// Sets the configuration settings for application's AWSAppSync Client.
func appSyncSetup()throws -> AWSAppSyncClientConfiguration{
let cache = try AWSAppSyncCacheConfiguration()
let serviceConfig = try AWSAppSyncServiceConfig()
let appSyncConfiguration = try AWSAppSyncClientConfiguration(appSyncServiceConfig: serviceConfig,
userPoolsAuthProvider: CognitoPoolProvider(),
cacheConfiguration: cache)
return appSyncConfiguration
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
do {
let configFile = try appSyncSetup()
appSyncClientBridge = try AWSAppSyncClient(appSyncConfig: configFile)
}
catch(let error){
print(error.localizedDescription)
}
return true
}
UPDATE:
If the user is already logged in. You can create a method like this one.
func getTokens(){
let getPool = CognitoPoolProvider()
func getToken(completion: #escaping (Result<String,Error>)->Void){
getPool.getLatestAuthToken { (token, error) in
if let error = error {
completion(.failure(error))
}
if let token = token {
completion(.success(token))
}
}
}
getToken { (result) in
print(("This is the token — \(String(describing: try? result.get() as String))"))
}
}
If you place this in your viewDidLoad you'll be able to access the user token. In this example it's just printed out, but I think from here you'll be able to use it for what you need.

Related

Ionic capacitor push-notifications duplicate tokens

I have an Ionic 5 angular app with push notifications, using the #capacitor/push-notifications plugin. Set up correctly as described here, and running on iOS.
PushNotificationService:
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Capacitor } from '#capacitor/core';
import {
ActionPerformed,
PushNotificationSchema,
PushNotifications,
Token,
} from '#capacitor/push-notifications';
import TXTS from '../../assets/strings.json';
import CFG from '../../app-config.json';
import { AppError } from './../error-handlers/app-errors';
#Injectable({ providedIn: 'root' })
export class PushNotificationService {
private registerationToken: Token;
constructor(
private http: HttpClient
) {}
/** initialize push plugin and add event listers to push notification events
*/
init() {
if (!this.isPushAvailable())
return;
// On success, we should be able to receive notifications
PushNotifications.addListener('registration', (token: Token) => {
console.log('Push registration success, token: ' + token.value);
this.registerationToken = token;
this.updateUserRegisterationToken();
});
PushNotifications.addListener('registrationError', (error: any) => {
console.log('Error on registration: ' + JSON.stringify(error));
});
PushNotifications.addListener('pushNotificationReceived',
(notification: PushNotificationSchema) => {
// Show us the notification payload if the app is open on our device
console.log('Push received: ' + JSON.stringify(notification));
}
);
// Method called when tapping on a notification
PushNotifications.addListener('pushNotificationActionPerformed',
(notification: ActionPerformed) => {
console.log('Push action performed: ' + JSON.stringify(notification));
}
);
}
/** Request permission to use push notifications
*/
requestPermissions() {
if (!this.isPushAvailable())
return;
PushNotifications.requestPermissions().then((result) => {
if (result.receive === 'granted') {
// Register with Apple / Google to receive push via APNS/FCM
PushNotifications.register();
} else {
throw new AppError(TXTS.userWarnings.noPushPermissions);
}
});
}
private isPushAvailable() {
return Capacitor.isPluginAvailable('PushNotifications');
}
private updateUserRegisterationToken() {
this.http
.post(
CFG.apiEndpoints.userPushRegistrationToken,
{ token: this.registerationToken.value }
)
.subscribe(
() => this.handleSuccessfulRegistrationTokenUpdate(),
(error) => this.handleFailedRegistrationTokenUpdate(error)
);
}
private handleSuccessfulRegistrationTokenUpdate() {
console.log('Registration token was updated on server');
}
private handleFailedRegistrationTokenUpdate(error) {
throw new Error('Error updating push registration token on server. Error: ' + error); // Not AppError! Not to show error to the user.
}
}
The push service is initialized by the app by calling:
this.pushService.requestPermissions();
this.pushService.init();
The problem:
Push Notifications 'registration' event is fired twice, each with a different token:
// from xCode logs:
Push registration success, token: 2014C60FE7FB063F2ED833E7B4DF3D0220EE31EEF3350E56C3C0CE3006BD62BE
Push registration success, token: dx7g0rZPZUBCkxFFpgPaQr:APA91bF6xCk9oZje7NNrAu1-_OB1y2Kek9RxOQMGVrxahqgCDh8YZv5W_aekKgJJtFAQqA0e__K-qqtB5c9T28PFc542R7MuYQYuKkztOet3gWpPU-zF3lUsLLeXwU45On7KDpEuG5I1
I understand that the first token is an APN token, and the second is a firebase (FCM) token. My project needs only the firebase token, and the APN token causes confusion.
My AppDeligate.swift looks like his:
import UIKit
import Firebase
import Capacitor
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
return true
}
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken)
Messaging.messaging().apnsToken = deviceToken
Messaging.messaging().token(completion: { (token, error) in
if let error = error {
NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
} else if let token = token {
NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: token)
}
})
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
}
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(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
// Called when the app was launched with a url. Feel free to add additional processing here,
// but if you want the App API to support tracking app url opens, make sure to keep this call
return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
// Called when the app was launched with an activity, including Universal Links.
// Feel free to add additional processing here, but if you want the App API to support
// tracking app url opens, make sure to keep this call
return ApplicationDelegateProxy.shared.application(application, continue: userActivity, restorationHandler: restorationHandler)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
let statusBarRect = UIApplication.shared.statusBarFrame
guard let touchPoint = event?.allTouches?.first?.location(in: self.window) else { return }
if statusBarRect.contains(touchPoint) {
NotificationCenter.default.post(name: .capacitorStatusBarTapped, object: nil)
}
}
}
Two questions:
Gow to prevent those duplicate 'registration' events without using another
FCM plugin as described here?
How to diffrentiate APN from the FCM token in an elgant way?
You have two NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications lines, that's what sends the push token to the JS side.
Remove the NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken) one as that's the one sending the APNS token.

400 Invalid_request You can't sign in to this app because it doesn't comply with Google's OAuth 2.0 policy for keeping apps secure

I am getting this error when I am trying to register with Google in my IOS app. I have got the REVERSED-CLIEND_ID which looks like something like this: com.googleusercontent.apps..... So far I can open the google window and I get the 400 error.
AppDelegate:
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
ApplicationDelegate.shared.application(application,didFinishLaunchingWithOptions: launchOptions)
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
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
ApplicationDelegate.shared.application(
app,
open: url,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
annotation: options[UIApplication.OpenURLOptionsKey.annotation]
)
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
}
}
ViewController:
let signInConfig = GIDConfiguration.init(clientID: "REVERSED_URL_THING")
#IBAction func googleRegister(_ sender: UIButton) {
GIDSignIn.sharedInstance.signIn(
with: signInConfig,
presenting: self
) { user, error in
guard error == nil else { return }
guard let user = user else { return }
// Your user is signed in!
}
}
If anyone came across the same issue, in Xcode's URL Types add iOS URL scheme and do not use reversed url like it was said in many tutorials. Use the CLIEND ID which Google provides:
let signInConfig = GIDConfiguration.init(clientID: "CLIENT ID ")

Google Sign In Button error when trying to login

I have followed all the steps of the Firebase instructions for adding a Google Sign In Button. I have two problems when I open the app I have to wait a couple of minutes before pressing the Google button otherwise it gives me an error, after the first sign in if I try more still gives me the error.
(I added all the pods, all the app delegate function requested, the url in the target section of the app, the google.key-value list, and tried all possible solutions from other similar questions)
The errors I get are
Optional(Error Domain=com.google.GIDSignIn Code=-5 "The user canceled the sign-in flow." UserInfo={NSLocalizedDescription=The user canceled the sign-in flow.})
Please if someone could help, cause I tried all stack overflow and google possibilities, and still not working.
Here is snippet of my code:
import Firebase
import GoogleSignIn
class ViewController: UIViewController {
var googleButton : GIDSignInButton!
viewDidLoad(){
self.googleButton = GIDSignInButton()
self.googleButton.style = .iconOnly
self.googleButton.frame = CGRect(x: 120, y: 300, width: 75, height: 75)
self.googleButton.addTarget(self, action: #selector(configureGoogleButton), for: .allTouchEvents)
self.view.addSubview(self.googleButton)
}
function configureGoogleButton(){
//get client Id
guard let clientID = FirebaseApp.app()?.options.clientID else {return}
let config = GIDConfiguration(clientID: clientID)
GIDSignIn.sharedInstance.signIn(with: config, presenting: self)
{ user,error in
guard error == nil else {
print("The app is not working")
print(error)
return }
guard
let authentication = user?.authentication,
let idToken = authentication.idToken
else {
return
}
let credential = GoogleAuthProvider.credential(withIDToken: idToken,
accessToken: authentication.accessToken)
self.googleCredential = credential
print(user?.profile?.email)
print(user?.profile?.name)
}
Here is part of the app delegate:
import Firebase
import UIKit
import GoogleSignIn
#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
}
// 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(
_ 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
}
}

Swift 4 Firebase online status update

I build chat app. I have field in each user table which allow to check if user Online. I use just database reference to get isOnline status and update it when pull to refresh. I seen that apps update online status automatically when user open or fold app. How i can do that? Do i need any listener or any framework can help me upgrade my code)) Something like ReactiveCocoa/ReactiveSwift...
P.S sorry for cyrillic text on field isOnline) it means Online/Offline
When application start you can update user online in AppDelegate
Update user online
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
// status parameter indicate user Online
if Auth.auth().currentUser != nil {
OnlineOfflineService.online(for: (Auth.auth().currentUser?.uid)!, status: true){ (success) in
print("User ==>", success)
}
}
return true
}
Update user Offline
func applicationWillTerminate(_ application: UIApplication) {
if Auth.auth().currentUser != nil {
OnlineOfflineService.online(for: (Auth.auth().currentUser?.uid)!, status: false){ (success) in
print("User ==>", success)
}
}
}
Firebase online and offline update service
import UIKit
import FirebaseDatabase
struct OnlineOfflineService {
static func online(for uid: String, status: Bool, success: #escaping (Bool) -> Void) {
//True == Online, False == Offline
let onlinesRef = Database.database().reference().child(uid).child("isOnline")
onlinesRef.setValue(status) {(error, _ ) in
if let error = error {
assertionFailure(error.localizedDescription)
success(false)
}
success(true)
}
}
}
Also you need to take care about user network connection. If user network connection off you just call OnlineOfflineService with parameters
I know this is an older question, but if you want to set the online/offline value to false when user closes app, use .onDisconnectSetValue():
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
setInactivityObservers()
return true
}
func setInactivityObservers() {
guard let user = Auth.auth().currentUser else { return }
// get user branch of database
let ref = Database.database().reference()
let usersRef = ref.child("Users")
let userRef = usersRef.child(user.uid)
// set "isOnline" branch to true when app launches
userRef.child("isOnline").setValue(true)
// set value to false when user terminates app
userRef.child("isOnline").onDisconnectSetValue(false)
}
First
Database.database().isPersistenceEnabled = true
Then manage the "presence"
let presenceRef = Database.database().reference(withPath: "disconnectmessage");
// Write a string when this client loses connection
presenceRef.onDisconnectSetValue("I disconnected!")
Then when the user is disconnected
presenceRef.onDisconnectRemoveValue { error, reference in
if let error = error {
print("Could not establish onDisconnect event: \(error)")
}
}
And Finally, to detect the status
let connectedRef = Database.database().reference(withPath: ".info/connected")
connectedRef.observe(.value, with: { snapshot in
if snapshot.value as? Bool ?? false {
print("Connected")
} else {
print("Not connected")
}
})
Is it ok now ?

0Auth2 Stuck on Permission Page

Currently having an issue with 0auth2 permissions. It keeps on getting stuck to this page: Stuck101. It doesn't crash, just remains completely dormant.
The debug console shows this:
[Debug] OAuth2: Initialization finished
[Debug] OAuth2: Looking for items in keychain
[Debug] OAuth2: Starting authorization
[Debug] OAuth2: No access token, checking if a refresh token is available
[Debug] OAuth2: Error refreshing token: I don't have a refresh token, not
trying to refresh
[Debug] OAuth2: Opening authorize URL embedded: https://login.microsoftonline.com/common/oauth2/v2.0/authorize?state=7A3CEE60&response_type=code&scope=openid+profile+offline_access+User.Read+Mail.Read+Calendars.Read&redirect_uri=KTracker2%3A%2F%2Foauth2%2Fcallback&client_id=584bb6db-5b71-4d7c-9015-fab8a9dfae4c
2018-05-09 04:49:47.198828+0100 KTracker2[8281:180974] [App] if we're in the real pre-commit handler we can't actually add any new fences due to CA restriction
My App delegate file houses this code:
// AppDelegate.swift
// KTracker2
//
// Created by CaudyMac on 07/05/2018.
// Copyright © 2018 Kallum Caudwell. All rights reserved.
//
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey: Any] = [:]) -> Bool {
if url.scheme == "KTracker2" {
let service = OutlookService.shared()
service.handleOAuthCallback(url: url)
return true
}
else {
return false
}
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
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:.
}
}
Service Code is here:
// OutlookService.swift
// KTracker2
// Created by CaudyMac on 09/05/2018.
// Copyright © 2018 Kallum Caudwell. All rights reserved.
import Foundation
import p2_OAuth2
import SwiftyJSON
class OutlookService {
// Configure the OAuth2 framework for Azure
private static let oauth2Settings = [
"client_id" : "584bb6db-5b71-4d7c-9015-fab8a9dfae4c",
"authorize_uri": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
"token_uri": "https://login.microsoftonline.com/common/oauth2/v2.0/token",
"scope": "openid profile offline_access User.Read Mail.Read Calendars.Read",
"redirect_uris": ["KTracker2://oauth2/callback"],
"verbose": true,
] as OAuth2JSON
private static var sharedService: OutlookService = {
let service = OutlookService()
return service
}()
private let oauth2: OAuth2CodeGrant
private init() {
oauth2 = OAuth2CodeGrant(settings: OutlookService.oauth2Settings)
oauth2.authConfig.authorizeEmbedded = true
//oauth2.authConfig.ui.useSafariView = false
userEmail = ""
}
class func shared() -> OutlookService {
return sharedService
}
var isLoggedIn: Bool {
get {
return oauth2.hasUnexpiredAccessToken() || oauth2.refreshToken != nil
}
}
func handleOAuthCallback(url: URL) -> Void {
oauth2.handleRedirectURL(url)
}
func login(from: AnyObject, callback: #escaping (String?) -> Void) -> Void {
oauth2.authorizeEmbedded(from: from) {
result, error in
if let unwrappedError = error {
callback(unwrappedError.description)
} else {
if let unwrappedResult = result, let token = unwrappedResult["access_token"] as? String {
// Print the access token to debug log
NSLog("Access token: \(token)")
callback(nil)
}
}
}
}
func logout() -> Void {
oauth2.forgetTokens()
}
func makeApiCall(api: String, params: [String: String]? = nil, callback: #escaping (JSON?) -> Void) -> Void {
// Build the request URL
var urlBuilder = URLComponents(string: "https://graph.microsoft.com")!
urlBuilder.path = api
if let unwrappedParams = params {
// Add query parameters to URL
urlBuilder.queryItems = [URLQueryItem]()
for (paramName, paramValue) in unwrappedParams {
urlBuilder.queryItems?.append(
URLQueryItem(name: paramName, value: paramValue))
}
}
let apiUrl = urlBuilder.url!
NSLog("Making request to \(apiUrl)")
var req = oauth2.request(forURL: apiUrl)
req.addValue("application/json", forHTTPHeaderField: "Accept")
let loader = OAuth2DataLoader(oauth2: oauth2)
// Uncomment this line to get verbose request/response info in
// Xcode output window
//loader.logger = OAuth2DebugLogger(.trace)
loader.perform(request: req) {
response in
do {
let dict = try response.responseJSON()
DispatchQueue.main.async {
let result = JSON(dict)
callback(result)
}
}
catch let error {
DispatchQueue.main.async {
let result = JSON(error)
callback(result)
}
}
}
}
private var userEmail: String
func getUserEmail(callback: #escaping (String?) -> Void) -> Void {
// If we don't have the user's email, get it from
// the API
if (userEmail.isEmpty) {
makeApiCall(api: "/v1.0/me") {
result in
if let unwrappedResult = result {
let email = unwrappedResult["mail"].stringValue
self.userEmail = email
callback(email)
} else {
callback(nil)
}
}
} else {
callback(userEmail)
}
}
func getInboxMessages(callback: #escaping (JSON?) -> Void) -> Void {
let apiParams = [
"$select": "subject,receivedDateTime,from",
"$orderby": "receivedDateTime DESC",
"$top": "10"
]
makeApiCall(api: "/v1.0/me/mailfolders/inbox/messages", params: apiParams) {
result in
callback(result)
}
}
func getEvents(callback: #escaping (JSON?) -> Void) -> Void {
let apiParams = [
"$select": "subject,start,end",
"$orderby": "start/dateTime ASC",
"$top": "10"
]
makeApiCall(api: "/v1.0/me/events", params: apiParams) {
result in
callback(result)
}
}
func getContacts(callback: #escaping (JSON?) -> Void) -> Void {
let apiParams = [
"$select": "givenName,surname,emailAddresses",
"$orderby": "givenName ASC",
"$top": "10"
]
makeApiCall(api: "/v1.0/me/contacts", params: apiParams) {
result in
callback(result)
}
}
}
I also have KTracker2 added in the plist files
Any ideas to why my app lies dormant would be great. Thanks a bunch.