How to update FCM token - swift

I am having the same issue where the key gets generated 2 times.
As stated here: https://github.com/firebase/firebase-ios-sdk/issues/6813
My question is how I can always keep my token updated with the Messaging didReceiveRegistrationToken: callback?
extension AppDelegate: MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
let deviceToken:[String: String] = ["token": fcmToken ?? ""]
print("Device token: ", deviceToken)
}
}

The last comment from a contributor on github says:
This is expected. We recently discover that sometimes, the APNS token is collected from Apple with a slight delay after first token request was issued, so client has to issue a second token request with the apns token mapping in it. So you are getting that scenario which is why you are getting the token callback twice.
It wasn't happening before because there was a bug that the second
token request is not triggered and was recently fixed in https://github.com/firebase/firebase-ios-sdk/pull/6669.
This should not affect your work as long as you always keep your token updated with the Messaging didReceiveRegistrationToken: callback."(charlotteliang)
So you should be fine as long as you update the token on every didReceiveRegistrationToken call. You can do that as the documentation describes: https://firebase.google.com/docs/cloud-messaging/ios/client#monitor-token-refresh.
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
print("Firebase registration token: \(String(describing: fcmToken))")
let dataDict: [String: String] = ["token": fcmToken ?? ""]
NotificationCenter.default.post(
name: Notification.Name("FCMToken"),
object: nil,
userInfo: dataDict
)
// TODO: If necessary send token to application server.
// Note: This callback is fired at each app startup and whenever a new token is generated.
}

Related

How do I get an access token for Firebase Authentication?

I'm using Firebase and FirebaseUI in my project. I want to give the user an options to delete his account, but if the user has been in the app longer than 5 minutes I need to reauthenticate again.
I'm not sure how to fill these parameters in the following method:
+ (FIRAuthCredential *)credentialWithProviderID:(NSString *)providerID
accessToken:(NSString *)accessToken;
With the credentials I can call
- (void)reauthenticateAndRetrieveDataWithCredential:(FIRAuthCredential *) credential
completion:(nullable FIRAuthDataResultCallback) completion
I know the ProviderId from:
Auth.auth().currentUser.providerID
But how do I get the access token?
You can call this function and get the Token!
Swift Code:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
if let refreshedToken = InstanceID.instanceID().token() {
print("InstanceID token: \(refreshedToken)")
}
}

Managing user Presense 'onDisconnect' Firebase and Swift?

I have built authentication into my app using Firebase/Facebook Auth and now I would like to build into my app a system for managing a user's presence (eg; updating a 'status' field on Firebase for the user to say 'online or offline') as described in the Firebase Docs here
*My question is... where do I put all this managing presense code?, here is my 'signIntoFirebase' function. would I create a separate function called 'manageUserPresense' and call it straight after 'firebaseLoginComplete'?
func signIntoFirebase(firebaseLoginComplete: #escaping (_ status: Bool, _ error: Error?) -> ()){
//Getting FB authentication
guard let authenticationToken = AccessToken.current?.authenticationToken else { return }
//Getting credential using authentication token
let credential = FacebookAuthProvider.credential(withAccessToken: authenticationToken)
//Signing in to Firebase using FB authentication token
Auth.auth().signIn(with: credential) { (user, error) in
if let error = error { //if there is an error
print (error)
firebaseLoginComplete(false, error)
return
}
firebaseLoginComplete(true, nil)
self.isLoggedIn = true
print ("Successfully authenticated into Firebase")
}
}//end func

Sending a message using SiriKit

I already have a messaging app, and I would like to implement Siri to send a message. I have added the Intents extension and everything, I am just having problems figuring out how to send the message. I have tried to use the same function for sending the messages in the ChatVC, and copy and paste that into the IntentHandler.swift file but it gives me a bunch of compiler errors. Is there some type of framework that I should use to communicate to the app to do it or something? I am using Firebase as my database if that information is needed.
Updated code:
note, this code is the send function that I have when a user sends a normal message, and this is what I copied and pasted into the SiriIntent...
func handle(sendMessage intent: INSendMessageIntent, completion: #escaping (INSendMessageIntentResponse) -> Void) {
// Implement your application logic to send a message here.
sendMessage()
let userActivity = NSUserActivity(activityType: NSStringFromClass(INSendMessageIntent.self))
let response = INSendMessageIntentResponse(code: .success, userActivity: userActivity)
completion(response)
}
func sendMessage(text: String?, date: Date, picture: UIImage?, location: String?, video: NSURL?, audio: String?) {
var outgoingMessage: OutgoingMessage?
if let text = text {
let encryptedText = EncryptText(chatRoomID: chatRoomId, string: text)
outgoingMessage = OutgoingMessage(message: encryptedText, senderId: FUser.currentUser()!.objectId, senderName: FUser.currentUser()!.firstname, date: date, status: kDELIVERED, type: kTEXT)
}
}
Thank you so much for all the help!

firebase token is null and token refresh is called continously in my testFlight

First of all, i have no problem for FCM, firebase token is never null every time tokenRefreshNotification is called. But after, i add Google analytics, i got weird problem for Firebase token. Every time i turn off and turn on notification in my app settings used
UIApplication.shared.registerForRemoteNotifications()
my tokenRefreshNotification is called continously and it doesn't stop looping until i force close my apps. At first, my app crash, and when i try to trace it with NsLog, i found that Firebase token is null. The problem occurs only when i`m using my apps installed from TestFlight / production. When i try it from my Xcode builder, firebase token is null only once, but the second call, firebase token is exist and it stop working.
For google Analytics, it works fine and in my GoogleService-info.plist,
i have set IS_ANALYTICS_ENABLED to YES and IS_GCM_ENABLED to YES also. For the other, IS_ADS_ENABLED = YES, IS_APPINVITE_ENABLED = NO, and IS_SIGNIN_ENABLED = YES
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FIRApp.configure()
NotificationCenter.default.addObserver(self, selector: #selector(self.registerNotification), name: NSNotification.Name(rawValue: "registerNotification"), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.tokenRefreshNotification(_:)), name: .firInstanceIDTokenRefresh, object: nil)
setupGoogleAnalytics()
return true
}
//when firebase token is null, this function is working continously until my firebase token is exist
func tokenRefreshNotification(_ notification: Notification) {
print("token Refresh")
if FIRInstanceID.instanceID().token() == nil{
NSLog("firebase token is null")
}
if (UserDefaults.standard.object(forKey: "id") != nil) && FIRInstanceID.instanceID().token() != nil{
FIRInstanceID.instanceID().getWithHandler({ (instanceID, error) in
NSLog("instanceID: \(instanceID!)")
//save firebase token to my database, sorry i can`t show it
})
}
// Connect to FCM since connection may have failed when attempted before having a token.
connectToFcm()
}
Note: At the first launch, i called my RegisterForRemoteNotifications, at TestFlight version, when tokenRefreshNotification is called, the firebase token is null, but the second call, firebase token is exist, so it could stop. But, when i run my app from Xcode, the first call is success because firebase token is not null.
i have figured it out! just change ANPS Type token from Sandbox to Unknown!
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// With swizzling disabled you must set the APNs token here.
FIRInstanceID.instanceID().setAPNSToken(deviceToken, type: FIRInstanceIDAPNSTokenType.unknown)
}

Validate AWS Cognito Token with Swift

I have nearly completed the process for a developer authenticated sign in using AWS. I cannot seem to authenticate the back-end token that I receive and cannot seem to find any current implementations that are performing developer authentication via a third-party back-end. The error that I get is listed below.
As of right now my code looks like this:
Class containing Custom identity provider:
import Foundation
import AWSCognitoIdentityProvider
class CustomIdentityProvider: NSObject, AWSIdentityProviderManager {
var tokens: [NSString: NSString]?
init(tokens: [NSString: NSString]) {
self.tokens = tokens
}
#objc func logins() -> AWSTask<NSDictionary> {
return AWSTask(result: tokens! as NSDictionary)
}
}
AWS-APIManager.swift {snippet}
/* obtained cognito token from my back-end via getOpenIdTokenForDeveloperIdentity*/
/* From here I my app receives an IdentityId and Token */
let client_cognito_id = String(describing: valid_response)
let session_token = json.dictionaryValue["Token"]!
let login_with_amazon = NSString(string: "cognito-identity.amazonaws.com")
let token = NSString(string: String(describing: session_token))
let customProviderManager = CustomIdentityProvider(tokens: [login_with_amazon: token])
let credentialsProvider = AWSCognitoCredentialsProvider(
regionType: self.AWS_REGION,
identityPoolId: "us-east-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
identityProviderManager: customProviderManager
)
credentialsProvider.setIdentityProviderManagerOnce(customProviderManager)
credentialsProvider.getIdentityId().continue ({ (task: AWSTask!) -> AnyObject! in
if (task.error != nil) {
print("Error!!!: " + (task.error?.localizedDescription)!)
} else {
// the task result will contain the identity id
let cognitoId = task.result
print(cognitoId)
print("SUCCESS!!!")
}
return nil
})
}
For some odd reason odd reason I can cannot authenticate the token that I have received. I get an error "Invalid login token. Can't pass in a Cognito token.". I've tried to follow the documentation and piece together working code that I have found literally hundreds of sources and cannot seem to be able to move past this part of the authentication process. Any help would be greatly appreciated. Thanks!
I believe the issue here is that although you are supplying the token, you are not setting the identity id that you are getting from your backend. As such, it is calling GetId with a Cognito OpenIdConnectToken, which is not supported.
The simplest client implementation of Developer Authenticated Identities is to extend AWSCognitoCredentialsProviderHelper
Apologies for providing this in Objective C instead of Swift. In your implementation just override the token method.
- (AWSTask<NSString *> *)token {
//get the identity id and token from your server
//You can use AWSTaskCompletionSource if you don't have it and need to get it asynchronously.
//Once you have this information, simply set the identity id and return the token
self.identityId = identityId;
return [AWSTask taskWithResult:token];
}