Firebase Refresh Token - ios

Using the method
[FIRInstanceID tokenWithAuthorizedEntity:scope:options:handler]
Im not quite sure what the parameters are calling for? What is the authorized entity and action? Also do I pass in the APNS token from apple to that method?

AUTHORIZED_ENTITY - Basically it asks for the google project id. It is numeric, and if you already had GCM integrated in your project before, it would be GCM_SENDER_ID (something like "568520103762"). Check your Google-info.plist to find it.
SCOPE - kFIRInstanceIDScopeFirebaseMessaging
OPTIONS - #{#"apns_token": deviceToken} (You will get DeviceToken in didRegisterForRemoteNotifications method)
HANDLER - Catch token if you have received token or catch the error here. If token comes nil, then wait for token in "tokenRefreshNotification" method, which will be called automatically if the token is nil in [FIRInstanceID tokenWithAuthorizedEntity:scope:options:handler]
Example:
if (![[FIRInstanceID instanceID] token]) {
[[FIRInstanceID instanceID] tokenWithAuthorizedEntity:_gcmSenderId scope:kFIRInstanceIDScopeFirebaseMessaging options:_registrationOptions handler:^(NSString * _Nullable token, NSError * _Nullable error) {
// Fetch the token or error
}];
}

You can do like this.
[[FIRInstanceID instanceID] setAPNSToken:deviceToken type:FIRInstanceIDAPNSTokenTypeProd];
[[FIRInstanceID instanceID] tokenWithAuthorizedEntity:gcmSenderID scope:kFIRInstanceIDTokenRefreshNotification options:nil handler:^(NSString * _Nullable token, NSError * _Nullable error) {
NSLog(#"GCM Registration token = %#",token);
NSLog(#"GCM Registration error = %#",error);
}];

Version for Swift (based on #HeadOnn's answer):
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
{
Messaging.messaging().setAPNSToken(deviceToken, type: .prod) // may be excess
guard let plistPath = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist"),
let options = FirebaseOptions(contentsOfFile: plistPath)
else { return }
InstanceID.instanceID().token(withAuthorizedEntity: options.gcmSenderID,
scope: InstanceIDScopeFirebaseMessaging,
options: ["apns_token": deviceToken])
{ (token, error) in
// handle token and error
}
}

Related

Firebase iOS Messaging, didReceiveMessage, appData is deprecated

I am getting appData is deprecated below with the new Firebase project. What else should I use for data messages only?
- (void)messaging:(FIRMessaging *)messaging didReceiveMessage:(FIRMessagingRemoteMessage *)remoteMessage {
NSLog(#"Received data message: %#", remoteMessage.appData);
if(remoteMessage.appData[#"action"] != nil)
{
if([#"refresh" isEqual: remoteMessage.appData[#"action"]])
{
[[FIRInstanceID instanceID]deleteIDWithHandler:^(NSError * _Nullable error) {
NSLog(#"%#", error.description);
if(error == nil) {
}
}];
}
}
}
From https://firebase.google.com/support/release-notes/ios:
Deprecated FCM direct channel messaging via shouldEstablishDirectChannel. Instead, use APNs for downstream message delivery. Add content_available key to your payload if you want to continue use legacy APIs, but we strongly recommend HTTP v1 API as it provides full APNs support.

Firebase Phone Auth

I'm trying to add Firebase Phone Auth to an app that I'm making in XCode. However, I'm having trouble with steps 3 of the firebase documentation and everything after that.
I don't understand where my code is supposed to go. I try some of it already and I attached the image of what I have done so far. Please help.
Thank you.
Ok, the code seems right.
Now you must add another textfield where the user can add the verification code arrived from the SMS.
In a new method triggered by the user after adding the code you must set a FIRAuthCredential like in the code of the example:
FIRAuthCredential *credential = [[FIRPhoneAuthProvider provider]
credentialWithVerificationID:verificationID
verificationCode:newTextField.text!];
And then do the signin with:
[[FIRAuth auth] signInAndRetrieveDataWithCredential:credential
completion:^(FIRAuthDataResult * _Nullable authResult,
NSError * _Nullable error) {
if (error) {
// ...
return;
}
// User successfully signed in. Get user data from the FIRUser object
if (authResult == nil) { return; }
FIRUser *user = authResult.user;
// ...
}];

Email-link-auth not working: Firebase Auth always returns false for `isSignIn(withEmailLink:)`

I'm attempting to follow the instructions here: https://firebase.google.com/docs/auth/ios/email-link-auth
... and here (for the dynamic links part): https://firebase.google.com/docs/dynamic-links/ios/receive
... to have my iOS app tell Firebase to send an email with a link, which when the user opens on their device, causes my app to have an authenticated User object.
#objc func handleFirebaseDynamicLink(_ link: DynamicLink) {
guard let link = link.url?.absoluteString else {
WLog("FirebaseProvider handleFirebaseDynamicLink: WARNING, link had no url")
return
}
guard let email = self.emailAddressLastEntered, Auth.auth().isSignIn(withEmailLink: link) else {
WLog("FirebaseProvider handleFirebaseDynamicLink: WARNING, not a signInWithEmailLink or no emailAddress?")
return
}
ISSUE: For some reason, Auth.auth().isSignIn... is returning false, even though the link it is given appears to be correct:
(lldb) po link
"https://<redacted>.firebaseapp.com/__/auth/action?apiKey=<redacted>&mode=signIn&oobCode=123459g71QBFRozWp4fvi-izDstx9BE2o3zhPc_jZQAAAFiU_tqpg&continueUrl=https://<redacted>/applinks/firebaseprovider/signin"
If I ignore this and just call Auth.auth().signIn(withEmail: email, link: link), it crashes with an exception of trying to insert a nil value into an NSDictionary :(
Here is the code i'm calling to generate the email send:
let actionCodeSettings = ActionCodeSettings.init()
actionCodeSettings.url = URL.init(string: "https://<redacted>/applinks/firebaseprovider/signin")
actionCodeSettings.handleCodeInApp = true
actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)
Auth.auth().sendSignInLink(toEmail: emailAddress, actionCodeSettings: actionCodeSettings, completion: { (error) in
if let error = error {
WLog("FirebaseProvider signIn: ERROR on sendSignInLink: \(error.localizedDescription)")
waitingForUserBlock(false)
return
}
self.emailAddressLastEntered = emailAddress
self.signedInBlock = signedInBlock
waitingForUserBlock(true)
})
... and here's the AppDelegate code that gets to the handler:
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray * _Nullable))restorationHandler {
DDLogInfo(#"AppDelegate continueUserActivity: %#", userActivity.debugDescription);
BOOL handled = [[FIRDynamicLinks dynamicLinks] handleUniversalLink:userActivity.webpageURL completion:^(FIRDynamicLink * _Nullable dynamicLink, NSError * _Nullable error) {
if (error) {
DDLogWarn(#"AppDelegate continueUserActivity: ERROR on handleUniversalLink: %#", error.debugDescription);
return;
}
[FirebaseProvider.shared handleFirebaseDynamicLink:dynamicLink];
}];
return handled;
}
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
FIRDynamicLink *dynamicLink = [[FIRDynamicLinks dynamicLinks] dynamicLinkFromCustomSchemeURL:url];
if (dynamicLink) {
[FirebaseProvider.shared handleFirebaseDynamicLink:dynamicLink];
return YES;
} else {
DDLogWarn(#"%s, WARNING: openURL returning FALSE because i didn't know the prefix: %#", __PRETTY_FUNCTION__, url.absoluteString);
}
return false;
}
I also made sure to re-download the GoogleService-Info.plist file, and I see in there that IS_SIGNIN_ENABLED is YES as i'd expect.
All help much appreciated.
Turns out the issue is that one should not handle the dynamicLink oneself. Ie. don't call handleUniversalLink just pass the entire link, dynamic or whatever, straight into isSignIn

In iOS (swift) app, registration of a second Firebase app can't receive remote notifications

I'm having two Firebase projects (on se same account, but could be two different accounts) and each project have an iOS app registered with the same bundle ID (so each .plist files have different sender IDs and project ID, but Bindle ID are the same).
When I configure Firebase messaging for each app separately using FirebaseApp.configure() and the firebase configuration .plist file for the app, it works, I can send FCM message and the app gets it.
(That means that both apps configurations on the Firebase console and Apple APNs keys, plist files are valid.)
But If I want to register both apps to enable multiple senders to send messages to my app, only the one registered as __FIRAPP_DEFAULT receives messages.
My configuration code is :
// this is configuration for the default "__FIRAPP_DEFAULT" using the base GoogleService-Info.plist file
FirebaseApp.configure()
// This is the second app configuration
let bundle = Bundle(for: type(of: self))
let path = bundle.path(forResource: "GoogleService-Info-second-app", ofType: "plist")
let options = FirebaseOptions.init(contentsOfFile: path!)
if options != nil {
FirebaseApp.configure(name: "app2", options: options!)
}
I can verify that both apps are well configured :
let apps = FirebaseApp.allApps
debugPrint(apps!)
Prints :
["app2": <FIRApp: 0x1704585a0>, "__FIRAPP_DEFAULT": <FIRApp: 0x17044a9b0>]
Then when I get the tokens from my AppDelegate using the following function:
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let d = NSData(data: deviceToken)
print(d)
Messaging.messaging().retrieveFCMToken(forSenderID: firstAppSenderIdString) { (message, error) in
print("FCM token for app1: \(message!)")
}
Messaging.messaging().retrieveFCMToken(forSenderID: secondAppSenderIdString) { (message, error) in
print("FCM token for app2: \(message!)")
}
}
I get both valid tokens :
FCM token for app1: fwjJVG2-T9Q:APA91bG8xVN9S-F4aERzh0GtcLWAqOy3dBPed0vPUE4AS_Jt4rau1bmmhvGPjfQgwBt9krdI9e91GaA04x4PXm4eW9PsG52P-Vt8yeo2woWGl3CP6zE09cT8ouRmOoWBhFfZkLbzbGul
FCM token for app2: fwjJVG2-T9Q:APA91bGggGD0YBZO5tpDqwdYKEbGX4vTSXnhwFoc_lrHbLIIWg1WE4RjTS8NYZ--TX-GkoypuEM4Plb4h41mVcP0uYjvo2dGDO3SNyuo3GrsBRb4ISzoieC_bcJZs5MibLKrET97f49j
Also if I configure both apps on a custom app name and none on "__FIRAPP_DEFAULT" I don't get any messages even for the first one.
My guess is that only "__FIRAPP_DEFAULT" app can receive FCM messages. Could you confirm or tell me where I'm wrong ?
If only the default app can handle notifications, what's the use of being able to configure Firebase for more than one app in the same iOS application ?
If both firebase app are same bunder id and push certification, you can get FCM token work with push notification.
Because retrieveFCMToken don't work, I think you forget set APNSToken for FIRMessaging before call retrieveFCMToken
[FIRMessaging messaging].APNSToken = deviceToken;
[[FIRMessaging messaging] retrieveFCMTokenForSenderID:self.firstAppSenderIdString completion:^(NSString * _Nullable FCMToken, NSError * _Nullable error) {
NSLog(#"FCM token for app1: %# - error: %#", FCMToken, error);
}];
In addition, if the default app not config, FIRMessaging will be nil, let second app work you can using tokenWithAuthorizedEntity function.
[[FIRInstanceID instanceID] tokenWithAuthorizedEntity:self.secondAppSenderIdString scope:kFIRInstanceIDScopeFirebaseMessaging options:#{#"apns_token": deviceToken} handler:^(NSString * _Nullable token, NSError * _Nullable error) {
NSLog(#"FCM token for app2: %# - error: %#", token, error);
}];

AMAZON AWS How do i subscribe an endpoint to SNS topic?

I'm implementing push notifications in an iOS app using Amazon SNS and Amazon Cognito services.
Cognito saves tokens successfully, my app gets notified, everything's working well, but there is a thing.
Now, when still in development, I need to manually add endpoints to an SNS topic, so all subscribers can get notifications. When i'll push an update to the App Store, there will be thousands of tokens to add.
I was studying Amazon AWS documentation, but there was no clue whether it's possible to make it happen without that additional effort.
My question: is it possible to automatically subscribe an endpoint to a topic with Amazon services only?
There is no way to automatically subscribe an endpoint to a topic, but you can accomplish all through code.
You can directly call the Subscribe API after you have created your endpoint. Unlike other kinds of subscription, no confirmation is necessary with SNS Mobile Push.
Here is some example Objective-C code that creates an endpoint and subscribes it to a topic:
AWSSNS *sns = [AWSSNS defaultSNS];
AWSSNSCreatePlatformEndpointInput *endpointRequest = [AWSSNSCreatePlatformEndpointInput new];
endpointRequest.platformApplicationArn = MY_PLATFORM_ARN;
endpointRequest.token = MY_TOKEN;
[[[sns createPlatformEndpoint:endpointRequest] continueWithSuccessBlock:^id(AWSTask *task) {
AWSSNSCreateEndpointResponse *response = task.result;
AWSSNSSubscribeInput *subscribeRequest = [AWSSNSSubscribeInput new];
subscribeRequest.endpoint = response.endpointArn;
subscribeRequest.protocols = #"application";
subscribeRequest.topicArn = MY_TOPIC_ARN;
return [sns subscribe:subscribeRequest];
}] continueWithBlock:^id(BFTask *task) {
if (task.cancelled) {
NSLog(#"Task cancelled");
}
else if (task.error) {
NSLog(#"Error occurred: [%#]", task.error);
}
else {
NSLog(#"Success");
}
return nil;
}];
Make sure you have granted access to sns:Subscribe in your Cognito roles to allow your application to make this call.
Update 2015-07-08: Updated to reflect AWS iOS SDK 2.2.0+
This is the original code to subscribe an endpoint to a topic in Swift3
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
//Get Token ENDPOINT
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02X", $1)})
//Create SNS Module
let sns = AWSSNS.default()
let request = AWSSNSCreatePlatformEndpointInput()
request?.token = deviceTokenString
//Send Request
request?.platformApplicationArn = Constants.SNSDEVApplicationARN
sns.createPlatformEndpoint(request!).continue({ (task: AWSTask!) -> AnyObject! in
if task.error != nil {
print("Error: \(task.error)")
} else {
let createEndpointResponse = task.result! as AWSSNSCreateEndpointResponse
print("endpointArn: \(createEndpointResponse.endpointArn)")
let subscription = Constants.SNSEndPoint //Use your own topic endpoint
//Create Subscription request
let subscriptionRequest = AWSSNSSubscribeInput()
subscriptionRequest?.protocols = "application"
subscriptionRequest?.topicArn = subscription
subscriptionRequest?.endpoint = createEndpointResponse.endpointArn
sns.subscribe(subscriptionRequest!).continue ({
(task:AWSTask) -> AnyObject! in
if task.error != nil
{
print("Error subscribing: \(task.error)")
return nil
}
print("Subscribed succesfully")
//Confirm subscription
let subscriptionConfirmInput = AWSSNSConfirmSubscriptionInput()
subscriptionConfirmInput?.token = createEndpointResponse.endpointArn
subscriptionConfirmInput?.topicArn = subscription
sns.confirmSubscription(subscriptionConfirmInput!).continue ({
(task:AWSTask) -> AnyObject! in
if task.error != nil
{
print("Error subscribing: \(task.error)")
}
return nil
})
return nil
})
}
return nil
})
}
If you want to use static credentials instead of using AWSCognito you will need to create those through Amazons IAM console.
Here is the code for initializing the Amazon in your App Delegate
// Sets up the AWS Mobile SDK for iOS
// Initialize the Amazon credentials provider
AWSStaticCredentialsProvider *credentialsProvider =[[AWSStaticCredentialsProvider alloc] initWithAccessKey:AWSAccessID secretKey:AWSSecretKey];
AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:DefaultServiceRegionType credentialsProvider:credentialsProvider];
[AWSServiceManager defaultServiceManager].defaultServiceConfiguration = configuration;
Fissh

Resources