Skip to content

Commit

Permalink
feature(tags): add strategy and ttl option (#7)
Browse files Browse the repository at this point in the history
Co-authored-by: worotyns <[email protected]>
  • Loading branch information
worotyns and worotyns authored Jul 13, 2023
1 parent 45c6222 commit e2a17d3
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 76 deletions.
2 changes: 1 addition & 1 deletion PPG_framework.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Pod::Spec.new do |spec|
#

spec.name = "PPG_framework"
spec.version = "1.1.0"
spec.version = "1.2.0"
spec.summary = "PushPushGo framework"

# This description is used to generate tags and improve search results.
Expand Down
2 changes: 1 addition & 1 deletion PPG_framework/PPG_framework.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
C629360D24BDCC5B00485D4B /* ApiService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiService.swift; sourceTree = "<group>"; };
C630D24224BDEAAD00F86145 /* SharedData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharedData.swift; sourceTree = "<group>"; };
C655331E24C034E200A5BE17 /* ApiModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiModels.swift; sourceTree = "<group>"; };
C655332824C050C200A5BE17 /* Beacon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Beacon.swift; sourceTree = "<group>"; };
C655332824C050C200A5BE17 /* Beacon.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = Beacon.swift; sourceTree = "<group>"; tabWidth = 4; };
C655332A24C050D500A5BE17 /* Event.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Event.swift; sourceTree = "<group>"; };
C655337F24DBFB3000EABF8B /* UNNotificationAttachment+Init.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UNNotificationAttachment+Init.swift"; sourceTree = "<group>"; };
C655338124DC30DA00EABF8B /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
Expand Down
39 changes: 39 additions & 0 deletions PPG_framework/PPG_framework/Models/Beacon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,18 @@ public class Beacon {
customId = ""
}

public func appendTag(_ tag: String, _ label: String, _ ttl: Int64 = 0) {
tags.append(BeaconTag(tag: tag, label: label, strategy: .append, ttl: ttl))
}

public func rewriteTag(_ tag: String, _ label: String, _ ttl: Int64 = 0) {
tags.append(BeaconTag(tag: tag, label: label, strategy: .rewrite, ttl: ttl))
}

public func deleteTag(_ tag: String, _ label: String) {
tagsToDelete.append(BeaconTag(tag: tag, label: label))
}

public func addTag(_ tag: String, _ label: String) {
tags.append(BeaconTag(tag: tag, label: label))
}
Expand Down Expand Up @@ -82,15 +94,42 @@ public class Beacon {
}
}


public struct BeaconTag: Codable {

public let tag: String
public let label: String
public let strategy: String
public let ttl: Int64

public init(tag: String) {
self.tag = tag
self.label = "default"
self.strategy = BeaconTagStrategy.append.rawValue
self.ttl = 0
}

public init(tag: String, label: String) {
self.tag = tag
self.label = label
self.strategy = BeaconTagStrategy.append.rawValue
self.ttl = 0
}

public init(tag: String, label: String, strategy: BeaconTagStrategy) {
self.tag = tag
self.label = label
self.strategy = strategy.rawValue
self.ttl = 0
}

public init(tag: String, label: String, strategy: BeaconTagStrategy, ttl: Int64) {
self.tag = tag
self.label = label
self.strategy = strategy.rawValue
self.ttl = ttl
}

}

public struct BeaconSelector: Codable {
Expand Down
5 changes: 5 additions & 0 deletions PPG_framework/PPG_framework/Models/Enums.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@ enum pushCategories: String {
case oneButtonCategory
case twoButtonsCategory
}

public enum BeaconTagStrategy: String, Codable {
case append
case rewrite
}
186 changes: 121 additions & 65 deletions PPG_framework/PPG_framework/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,85 @@

### [ Create certificate and upload it ]

### [ install framework (cocoapods?, direct download?) ]
### [ install framework (cocoapods or direct download), remember to add pod to extension target ]

### Add required code to AppDelegate

Open AppDelegate.swift file and creplace it's code to:
Open AppDelegate.swift file
Add required imports

```
import UIKit
```swift
import UserNotifications
import PPG_framework
```

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
// Initialize PPG framework
PPG.initNotifications("<your_app_id>", application, handler: { result in
switch result {
case .error(let error):
// handle error
print(error)
return
case .success:
return
}
})
let center = UNUserNotificationCenter.current()
center.delegate = self
return true
}
Add initialization code to given functions

```swift
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.

// Initialize PPG framework
PPG.initializeNotifications(projectId: "<your_app_id>", apiToken: "<your_api_token>")

func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
PPG.sendDeviceToken(deviceToken) { _ in }
}
// Register for push notifications if you do not already
PPG.registerForNotifications(application: application, handler: { result in
switch result {
case .error(let error):
// handle error
print(error)
return
case .success:
return
}
})

func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
// Send information about received notification to framework
PPG.notificationReceived(notification: notification) { _ in }
// Display notification when app is in foreground, optional
completionHandler([.alert, .badge, .sound])
}
UNUserNotificationCenter.current().delegate = self

func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
return true
}
```

// Send information about clicked notification to framework
PPG.notificationClicked(response: response) { _ in }
}
```
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
PPG.sendEventsDataToApi()
}
```

```
func application(_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
PPG.sendDeviceToken(deviceToken) { _ in }
}
```

```swift
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {

// Display notification when app is in foreground, optional
completionHandler([.alert, .badge, .sound])
}
```

```swift
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {

// Send information about clicked notification to framework
PPG.notificationClicked(response: response)

// Open external link from push notification
// Remove this section if this behavior is not expected
guard let url = PPG.getUrlFromNotificationResponse(response: response)
else {
completionHandler()
return
}
UIApplication.shared.open(url)
//
completionHandler()
}
```

Expand All @@ -69,54 +92,87 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
4. You can add capability by clicking on `+ Capability` button that is placed under `Signing & Capabilities` button.
5. Add `Background Modes` capability unless it is already on your capability list. Then select `Remote notifications`.
6. Add `Push notifications` capability unless it is already on your capability list.
7. Make sure that your `Provisioning Profile` has required capabilities. If you didn't add them while creating Provisioning Profile for your app you should go to your Apple Developer Center to add them then refresh your profile in Xcode project.
7. Make sure that your `Provisioning Profile` has required capabilities. If you didn't add them while creating Provisioning Profile for your app you should go to your Apple Developer Center to add them. Then refresh your profile in Xcode project.

### Create Notification Service Extension

This step is not required but it will allow application to display notifications with images.
This step is not required but it allows application to display notifications with images.

1. Open your Xcode project and click.
2. `File -> New -> Target`.
1. Open your Xcode project
2. Go to `File -> New -> Target`.
3. Select `Notification Service Extension`.
4. Choose a suitable name for it (for example `PPGNotificationServiceExtension`).
5. Open `NotificationService.swift` file.
6. Change `didReceive` function to:
6. Change `didReceive` function to: (use dispatch_group here to make sure that extension returns only when delivery event is sent and notification content is updated)

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

guard let content = bestAttemptContent else { return }

// Wait for delivery event result & image fetch before returning from extension
let group = DispatchGroup()
group.enter()
group.enter()

PPG.notificationDelivered(notificationRequest: request) { _ in
group.leave()
}

DispatchQueue.global().async { [weak self] in
self?.bestAttemptContent = PPG.modifyNotification(content)
group.leave()
}

group.notify(queue: .main) {
contentHandler(self.bestAttemptContent ?? content)
}
}

```

# Usage guide

### Unsubscribe user
`PPG.unsubscribeUser() { result in ... }`

### Create and send Beacon
```
```swift
let beacon = Beacon()
beacon.addSelector("Test_Selector", "0")

// Methods with strategy and ttl support
// For append tag in concrete category (with ttl, default = 0)
beacon.appendTag("mytag", "mycategory")
beacon.appendTag("mytag", "mycategory", 3600)

// For rewrite tag in concrete category (with ttl, default = 0)
beacon.rewriteTag("mytag", "mycategory")
beacon.rewriteTag("mytag", "mycategory", 3600)

// For delete tag in concrete category (with ttl, default = 0)
beacon.deleteTag("mytag", "mycategory");

// Legacy methods (not supports strategy append/rewrite and ttl)
beacon.addTag("new_tag", "new_tag_label")
beacon.addTagToDelete(BeaconTag(tag: "my_old_tag", label: "my_old_tag_label"))

beacon.send() { result in }
```

### Unsubscribe user
`PPG.unsubscribeUser { result in ... }`

### Send Event
Event's purpose is telling API about newly received notifications.
Event's purpose is to tell API about newly received notifications.
You should send events every time when user:

1. Receive notification
`PPG.notificationReceived(notification: notification) { _ in }`
1. Received notification in extension
`PPG.notificationDelivered(notificationRequest: UNNotificationRequest, handler: @escaping (_ result: ActionResult)`

2. Click on notification
`PPG.notificationClicked(response: response) { _ in }`
`PPG.notificationClicked(response: UNNotificationResponse)`

2. Click button inside notification
`PPG.notificationButtonClicked(response: response, button: 1)`

3. Click button inside notification
`PPG.notificationButtonClicked(response: response, button: 1) { _ in }`
Available values for `button` are `1` and `2`
Loading

0 comments on commit e2a17d3

Please sign in to comment.