Skip to main content

Notification Integration in IOS

caution

To use this library it is necessary to have the trust-service.json file with valid access credentials. In case you do not have it, follow the following link

How get trust-service.json file

Multimedia Specifications

To get a good visualization of the multimedia content. The images and videos have to satisfy the following dimension constraints.

  • Dialog Notifications: Image with 340x320 aspect ratio
  • Banner Notifications: Image with 340x400 aspect ratio
  • Video Notifications: Video with 320x515 aspect ratio

Implementation

Adding the Pod

If you don’t have any pods, run the following command into the terminal at the project's location:

pod init

The command generates a file called Podfile. Open this file and add the following lines to the Podfile:

source 'https://github.com/trusttechnologies/trustnotificationpodspecs.git'
source 'https://github.com/CocoaPods/Specs.git'

target 'NameApp' do
...
pod 'TrustNotification'
pod 'Firebase/Core'
pod 'Firebase/Messaging'
...
end

Then again in the command line console, run:

pod install

This will install the library code and firebase into your project.

Linking with the firebase project

The Trust Notification Service uses a Firebase project. Please contact us at app@trust.lat to configure a project for your app. We will send you a file GoogleService-Info.plist . Add this file to your project.

Service Notification Extension

The Service Notification Extension handles the view of the notification outside the app. In the image below we have an example.

drawing

To support this content, add the Service Notification Extension to your project. To do this, add a new target to the project clicking on File ---> New ---> Target ... ---> Notification Service Extension. The procedure is in the images below.

drawing drawing

Initialize

For notification initialization consider the following link to implement Firebase, considering the pertinent calls for the use of the library.

import TrustNotification
import FirebaseMessaging
import FirebaseCore
import UserNotifications

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?

let notifications = PushNotificationsInit()
}

extension AppDelegate{
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

...
firebaseConfig()
registerForRemoteNotifications()
...

return true

}

func applicationDidBecomeActive(_ application: UIApplication) {
...
clearBadgeNumber()
...
}
}
// MARK: - Notifications - UNUserNotificationCenterDelegate
extension AppDelegate: UNUserNotificationCenterDelegate {
//MARK: Initial Settings
private func firebaseConfig() {
FirebaseApp.configure()

Messaging.messaging().delegate = self
}

public func registerForRemoteNotifications(){
UNUserNotificationCenter.current().delegate = self

UNUserNotificationCenter.current().requestAuthorization(
options: [.alert, .sound, .badge]) {
(granted, error) in
print("Permission granted: \(granted)")
guard granted else { return }
}
UIApplication.shared.registerForRemoteNotifications()
}

// MARK: - Clear badge number func
public func clearBadgeNumber() {
///If you need to delete App Notification badge and enqueued notifications list
// UIApplication.shared.applicationIconBadgeNumber = 0
///If you need to delete only notification number when applicationDidBecomeActive is in use
// UIApplication.shared.applicationIconBadgeNumber = -1
}

// MARK: Background Notification
public func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
self.notifications.getNotification(response: response)
self.setNotificationObservers()
completionHandler()
}
}

// MARK: Foreground Notification
public func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
notifications.getNotificationForeground(notification: notification)

// With swizzling disabled you must let Messaging know about the message, for Analytics
Messaging.messaging().appDidReceiveMessage(notification.request.content.userInfo)
completionHandler([.alert, .badge, .sound])

setNotificationObservers()
}

// MARK: To know arrived notifications use the following obs
func setNotificationObservers() {
NotificationCenter.default.post(name: Notification.Name("ReceiveData"), object: nil)
NotificationCenter.default.post(name: Notification.Name("NotificationArrived"), object: nil)
}
}

//MARK: Messaging Delegate
extension AppDelegate: MessagingDelegate{
public func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(fcmToken)")

let dataDict:[String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)

guard let bundle = Bundle.main.bundleIdentifier else{
print("Bundle ID Error")
return
}
// MARK: - *** Register Firebase Token. ***
///Once initialized REMEMBER to register the firebase token with the help of the TrustIdentify.
Identify.shared.registerFirebaseToken(firebaseToken: fcmToken, bundleID: bundle)
}
}

To TrustDeviceInfo delegate consider implement the next:

Once client credentials is saved set:

guard let tokenType = savedClientCredentials.tokenType,
let accessToken = savedClientCredentials.accessToken else { return }
KeychainWrapper.standard.set("\(tokenType) \(accessToken)", forKey: "bearerToken")

Once the TrustID is saved set:

KeychainWrapper.standard.set("\(savedTrustID)", forKey: "trustID")

Add this files in Notification Service Extension

DialogNotificationsStructs.siwft

import Foundation

struct GenericStringNotification: Codable{
var type: String!
var typeDialog: String?
var notificationVideo: String?
var notificationDialog: String?
}

struct GenericNotification: Codable {
var type: String!
var typeDialog: String?
var notificationVideo: VideoNotification?
var notificationDialog: NotificationDialog?

enum CodingKeys: String, CodingKey {
case type
case notificationDialog
case notificationVideo
case typeDialog = "type_dialog"
}
}

struct NotificationDialog: Codable {
var textBody: String
var imageUrl: String
var isPersistent: Bool = true
var isCancelable: Bool = true
var buttons: [Button]?

enum CodingKeys: String, CodingKey {
case buttons
case imageUrl = "image_url"
case textBody = "text_body"
}
}

struct VideoNotification: Codable {
var videoUrl: String
var minPlayTime: String
var isPersistent: Bool? = true
var isSound: Bool? = true
var isPlaying: Bool? = true
var buttons: [Button]

enum CodingKeys: String, CodingKey {
case buttons
case videoUrl = "video_url"
case minPlayTime = "min_play_time"
case isSound
case isPlaying
}
}

struct Button: Codable {
var type: String
var text: String
var color: String
var action: String
}

ParseNotifications.swift

import UIKit
import Foundation

func parseStringNotification(content: [AnyHashable: Any]) -> GenericStringNotification {

//take the notification content and convert it to data
guard let jsonData = try? JSONSerialization.data(withJSONObject: content["data"], options: .prettyPrinted)
else {
print("Parsing notification error: Review your JSON structure")
return GenericStringNotification()
}

//decode the notification with the structure of a generic notification
let jsonDecoder = JSONDecoder()
guard let notDialog = try? jsonDecoder.decode(GenericStringNotification.self, from: jsonData) else {
print("Parsing notification error: Review your JSON structure")
return GenericStringNotification() }

return notDialog
}



func parseDialog(content: GenericStringNotification) -> NotificationDialog {

let contentAsString = content.notificationDialog?.replacingOccurrences(of: "\'", with: "\"", options: .literal, range: nil)
//let replacingApos = contentAsString?.replacingOccurrences(of: "'", with: "'", options: .literal, range: nil)

let jsonDecoder = JSONDecoder()
let dialogNotification = try? jsonDecoder.decode(NotificationDialog.self, from: contentAsString!.data(using: .utf8)!)

return dialogNotification ?? NotificationDialog(textBody: "", imageUrl: "", isPersistent: false, isCancelable: true, buttons: [])
}

func parseVideo(content: GenericStringNotification) -> VideoNotification {

let contentAsString = content.notificationVideo?.replacingOccurrences(of: "\'", with: "\"", options: .literal, range: nil)
//let replacingApos = contentAsString?.replacingOccurrences(of: "'", with: "'", options: .literal, range: nil)

let jsonDecoder = JSONDecoder()
guard let videoNotification = try? jsonDecoder.decode(VideoNotification.self, from: contentAsString!.data(using: .utf8)!) else {
return VideoNotification(videoUrl: "", minPlayTime: "0.0", isPersistent: false, buttons: [])
}
return videoNotification
}


Replace content of NotificationService.swift

import UserNotifications

class NotificationService: UNNotificationServiceExtension {

var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?

var downloadTask: URLSessionDownloadTask?

var url:String?

override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
self.contentHandler = contentHandler
bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)

let genericStringNotification = parseStringNotification(content: request.content.userInfo)
switch genericStringNotification.type {
case "dialog":
let dialogNotification = parseDialog(content: genericStringNotification)
url = dialogNotification.imageUrl
case "banner":
let dialogNotification = parseDialog(content: genericStringNotification)
url = dialogNotification.imageUrl
case "video":
let videoNotification = parseVideo(content: genericStringNotification)
url = videoNotification.videoUrl
default:
print("error: must specify a notification type")
}


if let urlString = url, let fileUrl = URL(string: urlString) {
// Download the attachment
URLSession.shared.downloadTask(with: fileUrl) { (location, response, error) in
if let location = location {
// Move temporary file to remove .tmp extension
let tmpDirectory = NSTemporaryDirectory()
let tmpFile = "file://".appending(tmpDirectory).appending(fileUrl.lastPathComponent)
let tmpUrl = URL(string: tmpFile)!
try! FileManager.default.moveItem(at: location, to: tmpUrl)

// Add the attachment to the notification content
if let attachment = try? UNNotificationAttachment(identifier: "", url: tmpUrl) {
self.bestAttemptContent?.attachments = [attachment]
}
}
// Serve the notification content
self.contentHandler!(self.bestAttemptContent!)
}.resume()
}

}

override func serviceExtensionTimeWillExpire() {
// Called just before the extension will be terminated by the system.
// Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent {
contentHandler(bestAttemptContent)
}
}

}

PushNotificationsInit some methods

From an instance of PushNotificationsInit

  • To get last 20 notification saved list, you should use the next method:
getLastTwentyNotifications()

getLastTwentyNotifications() return an "Slice" that could be cast as an array

  • Usage example:
func getNotifications() -> [NotificationInfo] {
let notifications = initPN.getLastTwentyNotifications()
return Array(notifications)
}
  • Set one test notificatión:
setTestNotification()
  • Delete notification list
deleteNotificationsList()
  • You could use "Arrived Notification" & "Receive Data" observers to know about that Events.
// Observers
func initNotificationObservers() {
NotificationCenter.default.addObserver(self, selector: #selector(onNotificationArrived(_:)), name: NSNotification.Name(rawValue: "NotificationArrived"), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(onReceiveData(_:)), name: NSNotification.Name(rawValue: "ReceiveData"), object: nil)
}

@objc func onReceiveData(_ notification: Notification) {}
@objc func onNotificationArrived(_ notification: Notification) {}

// Dont remember remove observer
func removeObservers() {
NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "ReceiveData"), object: nil)
}

Add images to project assets.
download the notifications icons here

Call images with these names:

audio_disabled_icon
audio_enabled_icon
close_icon

Permissions

For the correct use of this library, it is necessary to grant the application overwriting permission

Enable capabilities:

	Keychain sharing

Push Notification

For more details about Keycahin sharing, see the following link in the permissions section https://github.com/trusttechnologies/lat_trust_mobile_ios_trust-identify_library

License

TrustNotification is released under the MIT license. See LICENSE for details.