Push messages are an important part of several features in Token SDK. Those would be:
Step 1. Enable push notifications
When using push functionality for your app the first step is asking the user for permission to receive push notifications.
public func registerForFirebaseNotifications(application: UIApplication) {
if #available(iOS 10.0, *) {
// For iOS 10 display notification (sent via APNS)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: {_, _ in })
} else {
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
}
}
Note!
If you don’t ask for permission or the user doesn’t give permission for notifications, the user will not be able to receive push notifications.
We recommend calling the permission after some kind of boarding process to show the user why the app uses push notifications.
Firebase Instance Token
The default push service deployed with SxS is Firebase. Firebase should be added as a dependency to the project. For detailed instructions, please visit official site: https://firebase.google.com/docs/ios/setup.
Register token for push
To obtain the latest Firebase token use the Messaging module from Firebase and use the received firebaseRegistrationId to register it with your ASEE token.
Messaging.messaging().token { (result, error) in
if let error = error {
debugPrint("Error fetching remote instance ID: \(error)")
} else if let firebaseRegistrationId = result {
do {
try assecoToken.registerTokenForPushWithId(serverInfo: serverInfo!,
registrationId: firebaseRegistrationId,
success: {
//continue
}, failure: { (error) in
debugPrint(error)
})
} catch let error {
debugPrint(error)
}
}
}
However, the firebaseRegistrationId token is refreshed from time to time. To be notified whenever the token is updated, supply a delegate conforming to the messaging delegate protocol. The following example registers the delegate and adds the proper delegate method:
Messaging.messaging().delegate = self
…
extension AppDelegate: MessagingDelegate {
public func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
do {
guard let fcmToken = fcmToken else { return }
try TokenFacade.registerTokenForPushWithAuthenticationTag(tokenName: tokenName, registrationId: fcmToken, serverInfo: serverInfo, keychainAccessGroup: keychainAccessGroup) {
} failure: { error in
debugPrint(error)
}
} catch {
// NO-OP
}
}
}
This callback is fired at each app startup and whenever a new token is generated.
Non-loaded token
It is also possible to register a token for push using the method called registerTokenForPushWithAuthenticationTag. With this method, non-loaded tokens can be registered for push messages if registerTokenForPushWithID is called at least once.
Note!
This method is a precautionary measure in case a new fcm token arrives and the token has not yet been loaded into memory using, for example, the loadToken method.
Step 2. Consume push message content
Receiving Message
When push message is received, it must be determined what type of message is received. When confirming/rejecting transaction the message type will be TokenNotificationType.NOTIFICATION_TYPE_MAC.
It can be found out like this:
public func checkTransaction(userInfo: [AnyHashable : Any]) {
let messageType = userInfo["jwtType"] as? String
guard let payload = userInfo["jsonWebToken"] as? String else { return }
switch messageType {
case TokenNotificationType.NOTIFICATION_TYPE_MAC:
case TokenNotificationType.NOTIFICATION_TYPE_RECOVERY_START:
case TokenNotificationType.NOTIFICATION_TYPE_RECOVERY_CHALLENGE:
case TokenNotificationType.NOTIFICATION_TYPE_MTM_CONSENT:
case TokenNotificationType.NOTIFICATION_TYPE_LOGIN_BY_TOKEN:
default:
break
}
}
MACNotificationPayload Object Description
MACNotificationPayload is the object that contains payload data when push notification is received. Payload data consists of three important parts:
To obtain these values, use the method processMACNotification:
let macNotificationPayload = try TokenFacade.processMACNotification(encodedPayload: encodedPayload, publicKeyModulus: pushModulusKey, publicKeyExponent: serverInfo.publicKeyExponent)
MAC values and transaction ID are used in payment confirmation. While content is not needed for payment confirmation, it is important because it gives user some info about payment. It is usually displayed at Confirm payment screen.
This is example how content should look like in json form:
{"en":[{"Payment provider":"iPay"}, {"Accounts":["AT611904300234573201","AT611904300234573201"]},
{"Permissions":["Read Balances","Read Transactions"]}, {"Calls per day":"10"},{"Valid until":"1.10.2018"}]}
Step 3. Confirm/Reject Payment
A received transaction should be handled and confirmed or rejected. Otherwise, the transaction will be available in the notification inbox until an action is taken.
This is how the flow for confirming payment should look like:
try tokenFacade.confirmPayment(
serverInfo: config.serverInfo!,
applicationName: CharArrayExt.valueOf(string: “MAC_APP”),
encodedPayload: encodedPayload,
publicKeyModulus: pushModulusKey,
publicKeyExponent: config.serverInfo!.publicKeyExponent!,
success: {
…
}
},
failure: { error in
…
})
System integrators are responsible for providing applicationName used for confirming payment. Default application name is MAC_APP.
One important thing to do when confirming a transaction is correctly using publicKeyModulus. Most often with push notifications, you have to use pushKeyModulus. When confirming transactions with a QR code, you confirm the transaction with qrPushModulus.
System integrators are also reponseble for providing pushKeyModulus. Please check with them if you should use pushKeyModulus or publicKeyModulus for confirming payment.
Reject Payment
After push is received and parsed the payload, transactionId should be passed to TokenFacade.rejectPayment(transactionId) method.
try tokenFacade.rejectPayment(serverInfo: config.serverInfo!,
transactionId: transactionId,
success: {
…
}, failure: { (_) in
…
})
Confirm/reject consent
In essence, consent push messages are processed in the same way as transaction notifications are. The only difference between payment and consent push messages is jwtType, which is TokenNotificationType.NOTIFICATION_TYPE_CONSENT for consent ones. Payload is processed the same way, by invoking: TokenFacade.processMACNotification() method.
The only difference is that consents are confirmed or rejected via the following methods:
Karolina is an iOS Software Developer. She works on preventing security attacks on iOS phones and frequently tests ASEE’s applications. Her greatest passions are designing and developing new applications.