Skip to content

Commit

Permalink
Merge pull request #1 from engage-so/firebase_notifications
Browse files Browse the repository at this point in the history
Firebase notifications
  • Loading branch information
o-ifeanyi authored Nov 24, 2024
2 parents d15aaf1 + 1645a3b commit 0c7ab1e
Show file tree
Hide file tree
Showing 20 changed files with 1,198 additions and 49 deletions.
2 changes: 1 addition & 1 deletion Engage-swift.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'Engage-swift'
s.version = '0.2.0'
s.version = '0.3.0'
s.module_name = 'Engage'
s.summary = 'Official Engage SDK for iOS.'
s.homepage = 'https://engage.so/'
Expand Down
122 changes: 122 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
{
"pins" : [
{
"identity" : "abseil-cpp-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/abseil-cpp-binary.git",
"state" : {
"revision" : "194a6706acbd25e4ef639bcaddea16e8758a3e27",
"version" : "1.2024011602.0"
}
},
{
"identity" : "app-check",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/app-check.git",
"state" : {
"revision" : "3b62f154d00019ae29a71e9738800bb6f18b236d",
"version" : "10.19.2"
}
},
{
"identity" : "firebase-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk",
"state" : {
"revision" : "eca84fd638116dd6adb633b5a3f31cc7befcbb7d",
"version" : "10.29.0"
}
},
{
"identity" : "googleappmeasurement",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "fe727587518729046fc1465625b9afd80b5ab361",
"version" : "10.28.0"
}
},
{
"identity" : "googledatatransport",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleDataTransport.git",
"state" : {
"revision" : "a637d318ae7ae246b02d7305121275bc75ed5565",
"version" : "9.4.0"
}
},
{
"identity" : "googleutilities",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleUtilities.git",
"state" : {
"revision" : "57a1d307f42df690fdef2637f3e5b776da02aad6",
"version" : "7.13.3"
}
},
{
"identity" : "grpc-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/grpc-binary.git",
"state" : {
"revision" : "e9fad491d0673bdda7063a0341fb6b47a30c5359",
"version" : "1.62.2"
}
},
{
"identity" : "gtm-session-fetcher",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/gtm-session-fetcher.git",
"state" : {
"revision" : "a2ab612cb980066ee56d90d60d8462992c07f24b",
"version" : "3.5.0"
}
},
{
"identity" : "interop-ios-for-google-sdks",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
"state" : {
"revision" : "2d12673670417654f08f5f90fdd62926dc3a2648",
"version" : "100.0.0"
}
},
{
"identity" : "leveldb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/leveldb.git",
"state" : {
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
"version" : "1.22.5"
}
},
{
"identity" : "nanopb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/nanopb.git",
"state" : {
"revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1",
"version" : "2.30910.0"
}
},
{
"identity" : "promises",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/promises.git",
"state" : {
"revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
"version" : "2.4.0"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "edb6ed4919f7756157fe02f2552b7e3850a538e5",
"version" : "1.28.1"
}
}
],
"version" : 2
}
6 changes: 6 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ let package = Package(
name: "Engage",
targets: ["Engage"]),
],
dependencies: [
.package(url: "https://github.com/firebase/firebase-ios-sdk.git", "8.7.0"..<"12.0.0"),
],
targets: [
// Targets are the basic building blocks of a package, defining a module or a test suite.
// Targets can depend on other targets in this package and products from dependencies.
.target(
name: "Engage",
dependencies: [
.product(name: "FirebaseMessaging", package: "firebase-ios-sdk")
],
path: "Sources"
),
.testTarget(
Expand Down
142 changes: 142 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Engage iOS SDK

[Engage](https://engage.so/) helps businesses deliver personalized customer messaging and marketing automation through email, SMS and in-app messaging. This iOS SDK makes it easy to identify customers, sync customer data (attributes, events and device tokens) to the Engage dashboard and send in-app messages to customers.

## Features

- Track device token
- Identify users
- Update user attributes
- Track user events

## Getting started

- [Create an Engage account](https://engage.so/) and set up an account to get your public API key.
- Learn about [connecting customer data](https://engage.so/docs/guides/connecting-user-data) to Engage.

## Installation

The SDK is available via SPM or Cocoapods.

### Swift Package Manager (SPM)

1. In Xcode, go to your project’s **Package Dependencies** section.
2. Click the **+** button to add a new package.
3. Enter the following URL:

```
https://github.com/engage-so/engage-ios.git
```

4. Choose the version you want to install, and add it to your project.

### CocoaPods

1. Add the Engage SDK to your `Podfile`:

```ruby
platform :ios, '13.0'

target 'YourAppTarget' do
use_frameworks!

pod 'Engage-swift', :git => 'https://github.com/engage-so/engage-ios.git', :tag => 'v1.0.0'
end
```

2. Install the dependencies by running:

```bash
pod install
```

#### Example of Dependency Declaration in `Package.swift`

If you are using Swift Package Manager programmatically in a `Package.swift` file:

```swift
dependencies: [
.package(url: "https://github.com/engage-so/engage-ios.git", from: "1.0.0")
]
```

## Initialization

Import `Engage` and initialize the SDK.

```swift
// ...
import Engage

@main
struct MainApp: App {
init() {
Engage.shared.initialise(publicKey: "public-api-key")
}
// ...
}
```

## Identify users

Engage uses your user's unique identifier (this is mostly the ID field of the users' table) for data tracking. **Identify** lets you link this ID to the user. With identify, you are able to supply more details about the user.

```swift
let properties = ["first_name": "Jane", "last_name": "Doe", "last_login": Date()]
Engage.shared.identify(uid: "user-id", properties: properties)
```

Engage supports the following standard attributes: `first_name`, `last_name`, `email`, `number` (customer's phone number) but you can use identify to add any customer attribute you want. `last_login` in the example above is an example.

When new users are identified, Engage assumes their signup date to be the current timestamp. You can change this by adding a `created_at` attribute.

```swift
let properties = ["first_name": "Jane", "last_name": "Doe", "created_at": "2021-01-04"]
Engage.shared.identify(uid: "user-id", properties: properties)
```

## Add attributes

To add more attributes to the user's profile, use the `addAttributes` method.

```swift
let attributes = ["plan": "Pro", "age": 14]
Engage.shared.addAttributes(properties: attributes, uid: "optional")
```

## Set device token

Engage integrates with [FCM](https://firebase.google.com/docs/cloud-messaging) to let you send push notifications to your users, either through broadcast or automation. However, to do this, you need to send the user's FCM registration token to Engage. The device registration token is a unique identifier that allows the device receive messages.

```swift
func onNewToken(token: String) {
Engage.shared.setDeviceToken(deviceToken: token, uid: "optional")
}
```

## Track events

Track an event:

```swift
Engage.shared.track(event: "Login", uid: "optional")
```

Track an event with a value:

```swift
Engage.shared.track(event: "Clicked", value: "Login button", uid: "optional")
```

Track an event with properties:

```swift
let properties = ["type": "button", "counter": counter]
Engage.shared.track(event: "Clicked", value: properties, uid: "optional")
```

Engage sets the event date to the current timestamp but if you would like to set a different date, you can add a date as an argument in the `track` method.

```swift
Engage.shared.track(event: "Clicked", value: "Login button", date: Date(), uid: "optional")
```
42 changes: 36 additions & 6 deletions Sources/Engage/Engage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,30 @@ public final class Engage: EngageProtocol {
static public let shared = Engage()

private func userId(uid: String?) -> String {
let id = uid ?? UserDefaults.standard.value(forKey: "uid") as? String
let id = uid ?? UserDefaults.standard.value(forKey: Constants.uid) as? String
guard id != nil else {
let anonymous = UUID().uuidString
UserDefaults.standard.setValue(anonymous, forKey: "uid")
UserDefaults.standard.setValue(anonymous, forKey: Constants.uid)
return anonymous
}
return id!
}


public func initialise(publicKey: String) -> Engage {
UserDefaults.standard.setValue(publicKey, forKey: "publicKey")
UserDefaults.standard.setValue(publicKey, forKey: Constants.publicKey)
NotificationService.shared.initialise()

return .shared
}

public func identify(uid: String, properties: [String : Any]) {
UserDefaults.standard.setValue(uid, forKey: "uid")
let id = UserDefaults.standard.value(forKey: Constants.uid) as? String
if id != nil && id != uid {
merge(source: id!, destination: uid)
}

UserDefaults.standard.setValue(uid, forKey: Constants.uid)

var data: [String : Any] = [:]
var meta: [String : Any] = [:]
Expand All @@ -45,20 +51,28 @@ public final class Engage: EngageProtocol {
data["meta"] = meta

try? Network.shared.request(.identify(uid: uid, data: data.toData))
guard UserDefaults.standard.value(forKey: Constants.hasUsageActivity) as? Bool ?? false else {
UserDefaults.standard.setValue(true, forKey: Constants.hasUsageActivity)
return
}
}

public func setDeviceToken(deviceToken: String, uid: String? = nil) {
UserDefaults.standard.setValue(deviceToken, forKey: "deviceToken")
UserDefaults.standard.setValue(deviceToken, forKey: Constants.deviceToken)

let uid = userId(uid: uid)
let data: [String : Any] = ["device_token": deviceToken, "device_platform": "ios", "app_version": Bundle.version, "app_build": Bundle.build, "app_last_active": Date()]

try? Network.shared.request(.setDeviceToken(uid: uid, data: data.toData))
guard UserDefaults.standard.value(forKey: Constants.hasUsageActivity) as? Bool ?? false else {
UserDefaults.standard.setValue(true, forKey: Constants.hasUsageActivity)
return
}
}

public func logout(deviceToken: String? = nil, uid: String? = nil) {
let uid = userId(uid: uid)
let token = deviceToken ?? UserDefaults.standard.value(forKey: "deviceToken") as? String ?? ""
let token = deviceToken ?? UserDefaults.standard.value(forKey: Constants.deviceToken) as? String ?? ""

try? Network.shared.request(.logout(uid: uid, deviceToken: token))
}
Expand Down Expand Up @@ -122,5 +136,21 @@ public final class Engage: EngageProtocol {
data["timestamp"] = date
}
try? Network.shared.request(.track(uid: uid, data: data.toData))
guard UserDefaults.standard.value(forKey: Constants.hasUsageActivity) as? Bool ?? false else {
UserDefaults.standard.setValue(true, forKey: Constants.hasUsageActivity)
return
}
}

public func onMessageOpened(_ handler: @escaping ([AnyHashable : Any]) -> Void) {
NotificationHandler.shared.setOnMessageOpened(handler)
}

public func onMessageReceived(_ handler: @escaping ([AnyHashable : Any]) -> Void) {
NotificationHandler.shared.setOnMessageReceived(handler)
}

public func showDialog(isCarousel: Bool) {
DialogHandler.shared.showDialog(isCarousel: isCarousel)
}
}
3 changes: 3 additions & 0 deletions Sources/Engage/EngageProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ public protocol EngageProtocol {
func convertToAccount(uid: String?) -> Void
func merge(source: String, destination: String) -> Void
func track(event: String, value: Any?, date: Date?, uid: String?) -> Void
func onMessageOpened(_ handler: @escaping ([AnyHashable : Any]) -> Void) -> Void
func onMessageReceived(_ handler: @escaping ([AnyHashable : Any]) -> Void) -> Void
func showDialog(isCarousel: Bool) -> Void
}
Loading

0 comments on commit 0c7ab1e

Please sign in to comment.