Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notification Service Extension Plugin #17

Merged
merged 3 commits into from
Nov 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 9 additions & 28 deletions Example/BasicExample/BasicExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
46EDC72127C6B92C00B870D7 /* Segment in Frameworks */ = {isa = PBXBuildFile; productRef = 46EDC72027C6B92C00B870D7 /* Segment */; };
82A3C7672B0D32F60036DF9A /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82A3C7662B0D32F60036DF9A /* NotificationService.swift */; };
82A3C76B2B0D32F60036DF9A /* TwilioEngageExampleNotificationServiceExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 82A3C7642B0D32F60036DF9A /* TwilioEngageExampleNotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
82D44CB02B0D56CC0055CF7F /* TwilioEngage in Frameworks */ = {isa = PBXBuildFile; productRef = 82D44CAF2B0D56CC0055CF7F /* TwilioEngage */; };
82F9C4732A8177A200E580E3 /* DeepLinkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82F9C4722A8177A200E580E3 /* DeepLinkViewController.swift */; };
9BC924392A5C9C840003637C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BC924382A5C9C840003637C /* AppDelegate.swift */; };
9BC9243B2A5C9D130003637C /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9BC9243A2A5C9D130003637C /* SceneDelegate.swift */; };
Expand Down Expand Up @@ -54,15 +55,9 @@
46EDC70627C6B8D200B870D7 /* BasicExampleTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicExampleTests.swift; sourceTree = "<group>"; };
46EDC71027C6B8D200B870D7 /* BasicExampleUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicExampleUITests.swift; sourceTree = "<group>"; };
46EDC71227C6B8D200B870D7 /* BasicExampleUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicExampleUITestsLaunchTests.swift; sourceTree = "<group>"; };
82A3C7562B0D321B0036DF9A /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
82A3C7582B0D321B0036DF9A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
82A3C75F2B0D32270036DF9A /* TwilioEngageExmpleNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TwilioEngageExmpleNotificationServiceExtension.entitlements; sourceTree = "<group>"; };
82A3C7642B0D32F60036DF9A /* TwilioEngageExampleNotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TwilioEngageExampleNotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
82A3C7662B0D32F60036DF9A /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
82A3C7682B0D32F60036DF9A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
82D179FA2A8166A700318017 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
82D179FC2A8166A700318017 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
82D209802A840559005118D1 /* TwiliEngageExampleNotificationService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TwiliEngageExampleNotificationService.entitlements; sourceTree = "<group>"; };
82D44CAE2B0D3CF80055CF7F /* TwilioEngageExampleNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TwilioEngageExampleNotificationServiceExtension.entitlements; sourceTree = "<group>"; };
82F9C4722A8177A200E580E3 /* DeepLinkViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeepLinkViewController.swift; sourceTree = "<group>"; };
9BC924352A5C9AE20003637C /* BasicExample.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = BasicExample.entitlements; sourceTree = "<group>"; };
Expand Down Expand Up @@ -91,6 +86,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
82D44CB02B0D56CC0055CF7F /* TwilioEngage in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -104,8 +100,6 @@
46EDC6F427C6B8D100B870D7 /* BasicExample */,
46EDC70527C6B8D200B870D7 /* BasicExampleTests */,
46EDC70F27C6B8D200B870D7 /* BasicExampleUITests */,
82D179F92A8166A700318017 /* TwiliEngageExampleNotificationService */,
82A3C7552B0D321B0036DF9A /* TwilioEngageExmpleNotificationServiceExtension */,
82A3C7652B0D32F60036DF9A /* TwilioEngageExampleNotificationServiceExtension */,
46EDC6F327C6B8D100B870D7 /* Products */,
9BC9244A2A5CA6540003637C /* Frameworks */,
Expand Down Expand Up @@ -165,16 +159,6 @@
path = BasicExampleUITests;
sourceTree = "<group>";
};
82A3C7552B0D321B0036DF9A /* TwilioEngageExmpleNotificationServiceExtension */ = {
isa = PBXGroup;
children = (
82A3C75F2B0D32270036DF9A /* TwilioEngageExmpleNotificationServiceExtension.entitlements */,
82A3C7562B0D321B0036DF9A /* NotificationService.swift */,
82A3C7582B0D321B0036DF9A /* Info.plist */,
);
path = TwilioEngageExmpleNotificationServiceExtension;
sourceTree = "<group>";
};
82A3C7652B0D32F60036DF9A /* TwilioEngageExampleNotificationServiceExtension */ = {
isa = PBXGroup;
children = (
Expand All @@ -185,16 +169,6 @@
path = TwilioEngageExampleNotificationServiceExtension;
sourceTree = "<group>";
};
82D179F92A8166A700318017 /* TwiliEngageExampleNotificationService */ = {
isa = PBXGroup;
children = (
82D209802A840559005118D1 /* TwiliEngageExampleNotificationService.entitlements */,
82D179FA2A8166A700318017 /* NotificationService.swift */,
82D179FC2A8166A700318017 /* Info.plist */,
);
path = TwiliEngageExampleNotificationService;
sourceTree = "<group>";
};
9BC924472A5CA3E30003637C /* Packages */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -249,6 +223,9 @@
dependencies = (
);
name = TwilioEngageExampleNotificationServiceExtension;
packageProductDependencies = (
82D44CAF2B0D56CC0055CF7F /* TwilioEngage */,
);
productName = TwilioEngageExampleNotificationServiceExtension;
productReference = 82A3C7642B0D32F60036DF9A /* TwilioEngageExampleNotificationServiceExtension.appex */;
productType = "com.apple.product-type.app-extension";
Expand Down Expand Up @@ -674,6 +651,10 @@
package = 46EDC71F27C6B92C00B870D7 /* XCRemoteSwiftPackageReference "analytics-swift" */;
productName = Segment;
};
82D44CAF2B0D56CC0055CF7F /* TwilioEngage */ = {
isa = XCSwiftPackageProductDependency;
productName = TwilioEngage;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 46EDC6EA27C6B8D100B870D7 /* Project object */;
Expand Down
2 changes: 1 addition & 1 deletion Example/BasicExample/BasicExample/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
let customCategory = TwilioEngage.CustomCategory(title: "customized_push", acceptActionTitle: "Accept Title", dismissActionTitle: "Dismiss Title")

let categories = engage.createDefaultCategories(customCategory: customCategory)

UNUserNotificationCenter.current()
.setNotificationCategories(categories)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,66 +6,23 @@
//

import UserNotifications
import TwilioEngage

class NotificationService: UNNotificationServiceExtension {
let engage = TwilioEngageServiceExtension()

var contentHandler: ((UNNotificationContent) -> Void)?
var bestAttemptContent: UNMutableNotificationContent?
let userDefaults = UserDefaults(suiteName: "group.com.segment.twilioEngage")

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

if let bestAttemptContent = bestAttemptContent {
// set badge
let badgeAmount = bestAttemptContent.userInfo["badgeAmount"] as? Int ?? 1
let badgeStrategy = bestAttemptContent.userInfo["badgeStrategy"] as? String
var currentBadge = 2

print("****CURRENTBADGE******\(currentBadge)")
switch badgeStrategy {
case "inc":
currentBadge += badgeAmount
case "dec":
currentBadge -= badgeAmount
case "set":
currentBadge = badgeAmount
default:
currentBadge = badgeAmount
}

userDefaults?.set(currentBadge, forKey: "Count")
bestAttemptContent.badge = NSNumber(value: currentBadge)

// handle media
var urlString: String? = nil
if let mediaArray: NSArray = bestAttemptContent.userInfo["media"] as? NSArray {

if let mediaURLString = mediaArray[0] as? String {
urlString = mediaURLString
}

if urlString != nil, let fileURL = URL(string: urlString!){

guard let mediaData = NSData(contentsOf: fileURL) else {
contentHandler(bestAttemptContent)
return
}

guard let mediaAttachment = UNNotificationAttachment.saveImageToDisk(fileIdentifier: "engage-image.png", data: mediaData, options: nil) else {
contentHandler(bestAttemptContent)
return
}

bestAttemptContent.attachments = [ mediaAttachment ]
}
}


engage.handleNotification(content: bestAttemptContent, contentHandler)

contentHandler(bestAttemptContent)
}

}

override func serviceExtensionTimeWillExpire() {
Expand All @@ -77,25 +34,3 @@ class NotificationService: UNNotificationServiceExtension {
}

}

@available(iOSApplicationExtension 10.0, *)
extension UNNotificationAttachment {

static func saveImageToDisk(fileIdentifier: String, data: NSData, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
let fileManager = FileManager.default
let folderName = ProcessInfo.processInfo.globallyUniqueString
let folderURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(folderName, isDirectory: true)

do {
try fileManager.createDirectory(at: folderURL!, withIntermediateDirectories: true, attributes: nil)
let fileURL = folderURL?.appendingPathComponent(fileIdentifier)
try data.write(to: fileURL!, options: [])
let attachment = try UNNotificationAttachment(identifier: fileIdentifier, url: fileURL!, options: options)
return attachment
} catch let error {
print("error \(error)")
}

return nil
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive respo
//an extension for logic for displaying different notification types:
extension AppDelegate {

//Handle the notification bacsed on the `tapAction`
//Handle the notification based on the `tapAction`
func handleNotificiation(notification: [AnyHashable: Any], shouldAsk: Bool) {
if let aps = notification["aps"] as? NSDictionary {
if let tapAction = aps["category"] as? String {
Expand Down
91 changes: 91 additions & 0 deletions Sources/TwilioEngage/TwilioEngageServiceExtension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
//
// TwilioEngageServiceExtension.swift
//
// Created by Alan Charles on 11/21/23.
//

import Foundation
import Segment
import UserNotifications

public class TwilioEngageServiceExtension: UtilityPlugin {
public var type = PluginType.utility
public weak var analytics: Analytics? = nil
let userDefaults = UserDefaults(suiteName: "group.com.segment.twilioEngage")

public init() {
}

public func configure(analytics: Analytics) {
self.analytics = analytics
}

public func handleNotification(content: UNMutableNotificationContent, _ contentHandler: @escaping (UNNotificationContent) -> Void) {

// set badge
let badgeAmount = content.userInfo["badgeAmount"] as? Int ?? 1
let badgeStrategy = content.userInfo["badgeStrategy"] as? String
var currentBadge = 2

switch badgeStrategy {
case "inc":
currentBadge += badgeAmount
case "dec":
currentBadge -= badgeAmount
case "set":
currentBadge = badgeAmount
default:
currentBadge = badgeAmount
}

userDefaults?.set(currentBadge, forKey: "Count")
content.badge = NSNumber(value: currentBadge)

// handle media
var urlString: String? = nil
if let mediaArray: NSArray = content.userInfo["media"] as? NSArray {

if let mediaURLString = mediaArray[0] as? String {
urlString = mediaURLString
}

if urlString != nil, let fileURL = URL(string: urlString!){

guard let mediaData = NSData(contentsOf: fileURL) else {
contentHandler(content)
return
}

guard let mediaAttachment = UNNotificationAttachment.saveImageToDisk(fileIdentifier: "engage-image.png", data: mediaData, options: nil) else {
contentHandler(content)
return
}

content.attachments = [ mediaAttachment ]
}
}
}
}

@available(iOSApplicationExtension 10.0, *)
extension UNNotificationAttachment {

static func saveImageToDisk(fileIdentifier: String, data: NSData, options: [NSObject : AnyObject]?) -> UNNotificationAttachment? {
let fileManager = FileManager.default
let folderName = ProcessInfo.processInfo.globallyUniqueString
let folderURL = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(folderName, isDirectory: true)

do {
try fileManager.createDirectory(at: folderURL!, withIntermediateDirectories: true, attributes: nil)
let fileURL = folderURL?.appendingPathComponent(fileIdentifier)
try data.write(to: fileURL!, options: [])
let attachment = try UNNotificationAttachment(identifier: fileIdentifier, url: fileURL!, options: options)
return attachment
} catch let error {
print("error \(error)")
}

return nil
}
}