Skip to content

Commit

Permalink
Add Default Notification Handling, Action Buttons (#15)
Browse files Browse the repository at this point in the history
* feat: add action buttons

* fix: clean up app delegate add track events to tap actions

* chore: cleanup engage, remove messaging_subscription from open events

* feat: add custom action handling

* chore: cleanup naming, write readme

* chore: cleanup code comments

* chore: fix missing bracket in extension
  • Loading branch information
alanjcharles authored Nov 14, 2023
1 parent e1deae3 commit 45f0fd2
Show file tree
Hide file tree
Showing 9 changed files with 437 additions and 128 deletions.
12 changes: 8 additions & 4 deletions Example/BasicExample/BasicExample.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -458,10 +458,11 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = BasicExample/BasicExample.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"BasicExample/Preview Content\"";
DEVELOPMENT_TEAM = 75C92E9Q7J;
DEVELOPMENT_TEAM = VPZ4UMT2G9;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "";
GENERATE_INFOPLIST_FILE = YES;
Expand All @@ -478,6 +479,7 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.segment.twilioEngage;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "BasicExample/BasicExample-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
Expand All @@ -494,10 +496,11 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = BasicExample/BasicExample.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"BasicExample/Preview Content\"";
DEVELOPMENT_TEAM = 75C92E9Q7J;
DEVELOPMENT_TEAM = VPZ4UMT2G9;
ENABLE_PREVIEWS = YES;
FRAMEWORK_SEARCH_PATHS = "";
GENERATE_INFOPLIST_FILE = YES;
Expand All @@ -514,6 +517,7 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.segment.twilioEngage;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OBJC_BRIDGING_HEADER = "BasicExample/BasicExample-Bridging-Header.h";
SWIFT_VERSION = 5.0;
Expand All @@ -528,7 +532,7 @@
CODE_SIGN_ENTITLEMENTS = TwiliEngageExampleNotificationService/TwiliEngageExampleNotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 75C92E9Q7J;
DEVELOPMENT_TEAM = VPZ4UMT2G9;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = TwiliEngageExampleNotificationService/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = TwiliEngageExampleNotificationService;
Expand Down Expand Up @@ -556,7 +560,7 @@
CODE_SIGN_ENTITLEMENTS = TwiliEngageExampleNotificationService/TwiliEngageExampleNotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 75C92E9Q7J;
DEVELOPMENT_TEAM = VPZ4UMT2G9;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = TwiliEngageExampleNotificationService/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = TwiliEngageExampleNotificationService;
Expand Down
61 changes: 26 additions & 35 deletions Example/BasicExample/BasicExample/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@
import UIKit
import Segment
import UserNotifications
import UserNotificationsUI
import ProgressWebViewController
import TwilioEngage

extension Analytics {
static var main = Analytics(configuration: Configuration(writeKey: "<WRITE_KEY")
static var main = Analytics(configuration: Configuration(writeKey: "<Write_Key>")
.flushAt(1)
.trackApplicationLifecycleEvents(true))
}

@main
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
let engage = TwilioEngage { previous, current in
Tab1ViewController.addPush(s: "Push Status Changed = \(current)")
}

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
Analytics.main.add(plugin: UIKitScreenTracking())

let engage = TwilioEngage { previous, current in
Tab1ViewController.addPush(s: "Push Status Changed = \(current)")
}

Analytics.main.add(plugin: engage)

Analytics.main.screen(title: "home screen shown", category: nil, properties: nil)
Expand All @@ -35,6 +35,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD

let center = UNUserNotificationCenter.current()
center.delegate = self

let customCategory = TwilioEngage.CustomCategory(title: "customized_push", acceptActionTitle: "Accept Title", dismissActionTitle: "Dismiss Title")

let categories = engage.createDefaultCategories(customCategory: customCategory)

UNUserNotificationCenter.current()
.setNotificationCategories(categories)

center.requestAuthorization(options: [.sound, .alert, .badge]) { (granted, error) in
guard granted else {
Analytics.main.declinedRemoteNotifications()
Expand Down Expand Up @@ -68,21 +76,27 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
Tab1ViewController.addPush(s: "Failed to register for Notifications")
}

func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult {
func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler:
@escaping (UNNotificationPresentationOptions) -> Void
) {
let userInfo = notification.request.content.userInfo
Tab1ViewController.addPush(s: "Received in foreground: \(userInfo)")

Analytics.main.receivedRemoteNotification(userInfo: userInfo)
handleNotificiation(notification: userInfo, shouldAsk: true)

return .noData
completionHandler([.banner, .sound, .badge])
}

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void)
{
let userInfo = response.notification.request.content.userInfo
Tab1ViewController.addPush(s: "Received in background: \(userInfo)")
Analytics.main.receivedRemoteNotification(userInfo: userInfo)

handleNotificiation(notification: userInfo, shouldAsk: false)

engage.handleNotificiation(response: response)
completionHandler()
}

func applicationWillEnterForeground(_ application: UIApplication) {
Expand All @@ -109,7 +123,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
extension AppDelegate {
func openWebview(notification: [AnyHashable : Any], shouldAsk: Bool) {
let webViewController = ProgressWebViewController(nibName: "Main", bundle: Bundle.main)

guard var urlString = notification["link"] as? String else { return }
urlString = urlString.replacingOccurrences(of: "engage://", with: "https://")
guard let url = URL(string: urlString) else { return }
Expand Down Expand Up @@ -177,26 +190,4 @@ extension AppDelegate {
mainView?.navigationController?.pushViewController(deepLinkVC, animated: true)
}
}

func handleNotificiation(notification: [AnyHashable: Any], shouldAsk: Bool) {
if let aps = notification["aps"] as? NSDictionary {
if let tapAction = aps["category"] as? String {
switch tapAction {
case "open_url":
// open link in default browser
if let urlString = notification["link"] as? String {
guard let url = URL(string: urlString) else {return}
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
// alternatively, open a webview inside of your app
// openWebview(notification: notification, shouldAsk: shouldAsk)
case "deep_link":
openDeepLinkViewController(notification: notification, shouldAsk: shouldAsk)
default:
return
}
}
}
}
}

13 changes: 13 additions & 0 deletions Example/BasicExample/BasicExample/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,19 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLName</key>
<string>engage://DeepLinkScreen</string>
<key>CFBundleURLSchemes</key>
<array>
<string>DeepLinkScreen</string>
</array>
</dict>
</array>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
Expand Down
62 changes: 37 additions & 25 deletions Example/BasicExample/BasicExample/Tab1ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
//

import UIKit
import TwilioEngage

var mainView: Tab1ViewController? = nil

class Tab1ViewController: UITableViewController {
var pushes = [String]()

override func viewDidLoad() {
super.viewDidLoad()
mainView = self
Expand All @@ -21,33 +22,44 @@ class Tab1ViewController: UITableViewController {
tableView.dataSource = self

self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "pushCell")
}

@IBAction func queryAction(_ sender: Any) {

}

static func addPush(s: String) {
debugPrint(s)
DispatchQueue.main.async {
mainView?.pushes.insert(s, at: 0)
mainView?.tableView.reloadData()
Notification.Name.openButton.onPost { notification in
let name = notification.name
guard let deeplink = notification.userInfo?["link"] as? String else {return}
print("Deep Link in viewDidLoad() \(deeplink)")
let storyboard = UIStoryboard(name: "Main", bundle: nil)

let deepLinkScreen = deeplink.replacingOccurrences(of: "engage://", with: "")
let deepLinkVC = storyboard.instantiateViewController(identifier: deepLinkScreen)
mainView?.navigationController?.pushViewController(deepLinkVC, animated: true)
}
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return pushes.count

@IBAction func queryAction(_ sender: Any) {

}

static func addPush(s: String) {
debugPrint(s)
DispatchQueue.main.async {
mainView?.pushes.insert(s, at: 0)
mainView?.tableView.reloadData()
}
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return pushes.count
}
return 0
}
return 0
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "pushCell") ?? UITableViewCell(style: .default, reuseIdentifier: "pushCell")

let s = pushes[indexPath.row]
cell.textLabel!.text = s

return cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "pushCell") ?? UITableViewCell(style: .default, reuseIdentifier: "pushCell")

let s = pushes[indexPath.row]
cell.textLabel!.text = s

return cell
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@
<dict>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>UNNotificationExtensionCategory</key>
<string>open_url</string>
<key>UNNotificationExtensionUserInteractionEnabled</key>
<true/>
</dict>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.usernotifications.service</string>
<key>NSExtensionPrincipalClass</key>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import UserNotifications
import Segment
import TwilioEngage
import UserNotificationsUI

// add service extension package here
class NotificationService: UNNotificationServiceExtension {
Expand All @@ -17,7 +18,7 @@ class NotificationService: UNNotificationServiceExtension {
if let bestAttemptContent = bestAttemptContent {
var urlString: String? = nil
let mediaArray: NSArray = bestAttemptContent.userInfo["media"] as! NSArray

if let mediaURLString = mediaArray[0] as? String {
urlString = mediaURLString
}
Expand All @@ -39,7 +40,6 @@ class NotificationService: UNNotificationServiceExtension {
contentHandler(bestAttemptContent)
}
}

}

//add an extension to `UNNotificationAttachment` to download/save the image
Expand Down
Loading

0 comments on commit 45f0fd2

Please sign in to comment.