-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Sample project fixes. * Objective-C fixes. * Added Objective-C compatible source files. * Updated readme.
- Loading branch information
1 parent
8024c4b
commit ad3ed00
Showing
14 changed files
with
1,119 additions
and
390 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,312 @@ | ||
// | ||
// BrazeCommandRunner.swift | ||
// RemoteCommandModulesTests | ||
// | ||
// Created by Jonathan Wong on 11/16/18. | ||
// Copyright © 2018 Tealium. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
import Appboy_iOS_SDK | ||
|
||
@objc | ||
public protocol TealiumApplication { } | ||
extension UIApplication: TealiumApplication { } | ||
|
||
@objc | ||
public protocol BrazeCommandRunnable { | ||
|
||
// MARK: Initialization | ||
func initializeBraze(apiKey: String, application: TealiumApplication, launchOptions: [AnyHashable: Any]?) | ||
|
||
func initializeBraze(apiKey: String, application: TealiumApplication, launchOptions: [AnyHashable: Any]?, appboyOptions: [AnyHashable: Any]?) | ||
|
||
// MARK: User IDs | ||
func changeUser(_ userIdentifier: String) | ||
|
||
func addAlias(_ aliasName: String, label: String) | ||
|
||
// MARK: Events | ||
func logCustomEvent(eventName: String) | ||
|
||
func logCustomEvent(_ eventName: String, properties: [AnyHashable: Any]) | ||
|
||
// MARK: Attributes | ||
func setUserAttribute(key: AppboyUserAttribute, value: String) | ||
|
||
func setUserAttributes(_ attributes: [String: Any]) | ||
|
||
func setCustomAttributes(_ attributes: [String: Any]) | ||
|
||
func setCustomAttributeWithKey(_ key: String, value: AnyHashable) | ||
|
||
func unsetCustomAttributeWithKey(_ key: String) | ||
|
||
func incrementCustomUserAttributes(_ attributes: [String: Int]) | ||
|
||
func incrementCustomUserAttribute(_ key: String, by: Int) | ||
|
||
// MARK: Social Media | ||
func setFacebookUser(_ user: [String: Any]) | ||
|
||
func setTwitterUser(_ user:[String: Any]) | ||
|
||
// MARK: Array Attributes | ||
func setCustomAttributeArrayWithKey(_ key: String, array: [Any]?) | ||
|
||
func addToCustomAttributeArrayWithKey(_ key: String, value: String) | ||
|
||
func removeFromCustomAttributeArrayWithKey(_ key: String, value: String) | ||
|
||
// MARK: Subscriptions | ||
func setEmailNotificationSubscriptionType(value: AppboyNotificationSubscription) | ||
|
||
func setPushNotificationSubscriptionType(value: AppboyNotificationSubscription) | ||
|
||
// MARK: Purchases | ||
func logPurchase(_ productIdentifier: String, currency: String, price: NSDecimalNumber) | ||
|
||
func logPurchase(_ productIdentifier: String, currency: String, price: NSDecimalNumber, quantity: UInt) | ||
|
||
func logPurchase(_ productIdentifier: String, currency: String, price: NSDecimalNumber, properties: [AnyHashable: Any]?) | ||
|
||
func logPurchase(_ productIdentifier: String, currency: String, price: NSDecimalNumber, quantity: UInt, properties: [AnyHashable: Any]?) | ||
|
||
// MARK: Enabling/Wiping | ||
func enableSDK(_ enable: Bool) | ||
|
||
func wipeData() | ||
} | ||
|
||
public protocol BrazeCommandNotifier { | ||
func registerPushToken(_ pushToken: String) | ||
|
||
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) | ||
|
||
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) | ||
|
||
func pushAuthorization(fromUserNotificationCenter: Bool) | ||
} | ||
|
||
public class BrazeCommandRunner: NSObject, BrazeCommandRunnable, BrazeCommandNotifier { | ||
|
||
public func initializeBraze(apiKey: String, application: TealiumApplication, launchOptions: [AnyHashable: Any]?) { | ||
Appboy.start(withApiKey: apiKey, in: application as? UIApplication ?? UIApplication.shared, withLaunchOptions: launchOptions) | ||
} | ||
|
||
public func initializeBraze(apiKey: String, application: TealiumApplication, launchOptions: [AnyHashable: Any]?, appboyOptions: [AnyHashable: Any]?) { | ||
Appboy.start(withApiKey: apiKey, in: application as? UIApplication ?? UIApplication.shared, withLaunchOptions: launchOptions, withAppboyOptions: appboyOptions) | ||
} | ||
|
||
public func changeUser(_ userIdentifier: String) { | ||
Appboy.sharedInstance()?.changeUser(userIdentifier) | ||
} | ||
|
||
public func addAlias(_ aliasName: String, label: String) { | ||
Appboy.sharedInstance()?.user.addAlias(aliasName, withLabel: label) | ||
} | ||
|
||
public func logCustomEvent(eventName: String) { | ||
Appboy.sharedInstance()?.logCustomEvent(eventName) | ||
} | ||
|
||
public func logCustomEvent(_ eventName: String, properties: [AnyHashable: Any]) { | ||
Appboy.sharedInstance()?.logCustomEvent(eventName, withProperties: properties) | ||
} | ||
|
||
public func setUserAttributes(_ attributes: [String : Any]) { | ||
BrazeCommand.appboyUserAttributes.forEach { userAttribute in | ||
let key = userAttribute.description() | ||
guard let value = attributes[key] as? String else { | ||
return | ||
} | ||
setUserAttribute(key: userAttribute, value: value) | ||
} | ||
} | ||
|
||
public func setUserAttribute(key: AppboyUserAttribute, value: String) { | ||
switch key { | ||
case .firstName: | ||
Appboy.sharedInstance()?.user.firstName = value | ||
case .lastName: | ||
Appboy.sharedInstance()?.user.lastName = value | ||
case .email: | ||
Appboy.sharedInstance()?.user.email = value | ||
case .dateOfBirth: | ||
guard let date = DateConverter.shared.iso8601DateFormatter.date(from: value) else { | ||
return | ||
} | ||
Appboy.sharedInstance()?.user.dateOfBirth = date | ||
case .country: | ||
Appboy.sharedInstance()?.user.country = value | ||
case .language: | ||
Appboy.sharedInstance()?.user.language = value | ||
case .homeCity: | ||
Appboy.sharedInstance()?.user.homeCity = value | ||
case .phone: | ||
Appboy.sharedInstance()?.user.phone = value | ||
case .avatarImageURL: | ||
Appboy.sharedInstance()?.user.avatarImageURL = value | ||
case .gender: | ||
guard let gender = ABKUserGenderType(rawValue: AppboyUserGenderType.from(value).rawValue) else { | ||
return | ||
} | ||
Appboy.sharedInstance()?.user.setGender(gender) | ||
} | ||
} | ||
|
||
public func setCustomAttributes(_ attributes: [String : Any]) { | ||
_ = attributes.map { attribute in | ||
guard let value = attribute.value as? AnyHashable else { | ||
return | ||
} | ||
setCustomAttributeWithKey(attribute.key, value: value) | ||
} | ||
} | ||
|
||
public func setCustomAttributeWithKey(_ key: String, value: AnyHashable) { | ||
if let value = value as? Bool { | ||
Appboy.sharedInstance()?.user.setCustomAttributeWithKey(key, andBOOLValue: value) | ||
} else if let value = value as? Int { | ||
Appboy.sharedInstance()?.user.setCustomAttributeWithKey(key, andIntegerValue: value) | ||
} else if let value = value as? Double { | ||
Appboy.sharedInstance()?.user.setCustomAttributeWithKey(key, andDoubleValue: value) | ||
} else if let value = value as? String { | ||
Appboy.sharedInstance()?.user.setCustomAttributeWithKey(key, andStringValue: value) | ||
} else if let value = value as? Date { | ||
Appboy.sharedInstance()?.user.setCustomAttributeWithKey(key, andDateValue: value) | ||
} | ||
} | ||
|
||
public func unsetCustomAttributeWithKey(_ key: String) { | ||
Appboy.sharedInstance()?.user.unsetCustomAttribute(withKey: key) | ||
} | ||
|
||
public func incrementCustomUserAttribute(_ key: String, by: Int) { | ||
Appboy.sharedInstance()?.user.incrementCustomUserAttribute(key, by: by) | ||
} | ||
|
||
public func setCustomAttributeArrayWithKey(_ key: String, array: [Any]?) { | ||
Appboy.sharedInstance()?.user.setCustomAttributeArrayWithKey(key, array: array) | ||
} | ||
|
||
public func addToCustomAttributeArrayWithKey(_ key: String, value: String) { | ||
Appboy.sharedInstance()?.user.addToCustomAttributeArray(withKey: key, value: value) | ||
} | ||
|
||
public func removeFromCustomAttributeArrayWithKey(_ key: String, value: String) { | ||
Appboy.sharedInstance()?.user.removeFromCustomAttributeArray(withKey: key, value: value) | ||
} | ||
|
||
public func setFacebookUser(_ user: [String: Any]) { | ||
guard let userInfo = user[SocialMediaKey.userInfo.rawValue] as? [String: Any], | ||
let friendsCount = user[SocialMediaKey.friendsCount.rawValue] as? Int else { | ||
return | ||
} | ||
let likes: [Any]? = user[SocialMediaKey.likes.rawValue] as? [Any] | ||
Appboy.sharedInstance()?.user.facebookUser = ABKFacebookUser(facebookUserDictionary: userInfo, numberOfFriends: friendsCount, likes: likes) | ||
} | ||
|
||
public func setTwitterUser(_ user: [String: Any]) { | ||
let twitterUser = ABKTwitterUser() | ||
if let userDescription = user[SocialMediaKey.userDescription.rawValue] as? String { | ||
twitterUser.userDescription = userDescription | ||
} | ||
if let twitterName = user[SocialMediaKey.twitterName.rawValue] as? String { | ||
twitterUser.twitterName = twitterName | ||
} | ||
if let profileImageUrl = user[SocialMediaKey.profileImageUrl.rawValue] as? String { | ||
twitterUser.profileImageUrl = profileImageUrl | ||
} | ||
if let screenName = user[SocialMediaKey.screenName.rawValue] as? String { | ||
twitterUser.screenName = screenName | ||
} | ||
if let followersCount = user[SocialMediaKey.followersCount.rawValue] as? Int { | ||
twitterUser.followersCount = followersCount | ||
} | ||
if let friendsCount = user[SocialMediaKey.friendsCount.rawValue] as? Int { | ||
twitterUser.friendsCount = friendsCount | ||
} | ||
if let statusesCount = user[SocialMediaKey.statusesCount.rawValue] as? Int { | ||
twitterUser.statusesCount = statusesCount | ||
} | ||
if let twitterId = user[SocialMediaKey.twitterId.rawValue] as? Int { | ||
twitterUser.twitterID = twitterId | ||
} | ||
Appboy.sharedInstance()?.user.twitterUser = twitterUser | ||
} | ||
|
||
public func setEmailNotificationSubscriptionType(value: AppboyNotificationSubscription) { | ||
switch value { | ||
case .optedIn: | ||
Appboy.sharedInstance()?.user.setEmailNotificationSubscriptionType(.optedIn) | ||
case .subscribed: | ||
Appboy.sharedInstance()?.user.setEmailNotificationSubscriptionType(.subscribed) | ||
case .unsubscribed: | ||
Appboy.sharedInstance()?.user.setEmailNotificationSubscriptionType(.unsubscribed) | ||
} | ||
} | ||
|
||
public func setPushNotificationSubscriptionType(value: AppboyNotificationSubscription) { | ||
switch value { | ||
case .optedIn: | ||
Appboy.sharedInstance()?.user.setPush(.optedIn) | ||
case .subscribed: | ||
Appboy.sharedInstance()?.user.setPush(.subscribed) | ||
case .unsubscribed: | ||
Appboy.sharedInstance()?.user.setPush(.unsubscribed) | ||
} | ||
} | ||
|
||
public func incrementCustomUserAttributes(_ attributes: [String: Int]) { | ||
attributes.forEach { attribute in | ||
incrementCustomUserAttribute(attribute.key, by: attribute.value) | ||
} | ||
} | ||
|
||
public func logPurchase(_ productIdentifier: String, currency: String, price: NSDecimalNumber) { | ||
Appboy.sharedInstance()?.logPurchase(productIdentifier, inCurrency: currency, atPrice: price) | ||
} | ||
|
||
public func logPurchase(_ productIdentifier: String, currency: String, price: NSDecimalNumber, quantity: UInt) { | ||
Appboy.sharedInstance()?.logPurchase(productIdentifier, inCurrency: currency, atPrice: price, withQuantity: quantity) | ||
} | ||
|
||
public func logPurchase(_ productIdentifier: String, currency: String, price: NSDecimalNumber, properties: [AnyHashable: Any]?) { | ||
Appboy.sharedInstance()?.logPurchase(productIdentifier, inCurrency: currency, atPrice: price, withProperties: properties) | ||
} | ||
|
||
public func logPurchase(_ productIdentifier: String, currency: String, price: NSDecimalNumber, quantity: UInt, properties: [AnyHashable: Any]?) { | ||
Appboy.sharedInstance()?.logPurchase(productIdentifier, inCurrency: currency, atPrice: price, withQuantity: quantity, andProperties: properties) | ||
} | ||
|
||
public func registerPushToken(_ pushToken: String) { | ||
Appboy.sharedInstance()?.registerPushToken(pushToken) | ||
} | ||
|
||
public func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) { | ||
Appboy.sharedInstance()?.register(application, didReceiveRemoteNotification: userInfo, fetchCompletionHandler: completionHandler) | ||
} | ||
|
||
public func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { | ||
Appboy.sharedInstance()?.userNotificationCenter(center, didReceive: response, withCompletionHandler: completionHandler) | ||
} | ||
|
||
public func pushAuthorization(fromUserNotificationCenter: Bool) { | ||
Appboy.sharedInstance()?.pushAuthorization(fromUserNotificationCenter: fromUserNotificationCenter) | ||
} | ||
|
||
public func enableSDK(_ enable: Bool) { | ||
if enable { | ||
Appboy.requestEnableSDKOnNextAppRun() | ||
} else { | ||
Appboy.disableSDK() | ||
} | ||
} | ||
|
||
public func wipeData() { | ||
Appboy.wipeDataAndDisableForAppRun() | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// | ||
// DateConverter.swift | ||
// RemoteCommandModules | ||
// | ||
// Created by Jonathan Wong on 1/10/19. | ||
// Copyright © 2019 Tealium. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
public class DateConverter { | ||
|
||
public static let shared = DateConverter() | ||
|
||
public let iso8601DateFormatter: ISO8601DateFormatter = { | ||
if #available(iOS 11.0, *) { | ||
return ISO8601DateFormatter([.withInternetDateTime, .withFractionalSeconds]) | ||
} else { | ||
return ISO8601DateFormatter([.withInternetDateTime]) | ||
} | ||
}() | ||
} | ||
|
||
extension ISO8601DateFormatter { | ||
|
||
public convenience init(_ formatOptions: Options, timeZone: TimeZone? = nil) { | ||
self.init() | ||
self.formatOptions = formatOptions | ||
self.timeZone = timeZone ?? TimeZone(secondsFromGMT: 0) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,29 +1,21 @@ | ||
# Braze Remote Commands | ||
## Tealium Braze | ||
|
||
A [Braze](https://www.braze.com/docs/developer_guide/platform_integration_guides/ios/initial_sdk_setup/initial_sdk_setup/) integration with the [Tealium SDK](https://github.com/tealium/tealium-swift) that enables Braze API calls to be made through Tealium's [track](https://docs.tealium.com/platforms/swift/track/) API. | ||
[](https://github.com/Tealium/tealium-swift/blob/master/LICENSE.txt) | ||
[](https://developer.apple.com/resources/) | ||
|
||
## Getting Started | ||
|
||
Clone this repo and execute the `pod install` command in the project directory. You can then run the sample app to get an idea of the functionality. | ||
|
||
### Prerequisites | ||
## Documentation | ||
For full documentation, please see the Tealium Learning Community: | ||
|
||
* Tealium IQ account | ||
* Braze account | ||
|
||
### Installing | ||
|
||
To include the remote command files in your own project, simply clone this repo and drag the files within the Sources folder into your project. | ||
|
||
Include the [Tealium Swift](https://docs.tealium.com/platforms/swift/install/) and [Braze](https://www.braze.com/docs/developer_guide/platform_integration_guides/ios/initial_sdk_setup/initial_sdk_setup/) frameworks in your project through your desired dependency manager. | ||
|
||
Configure the Tealium IQ _Braze Mobile Remote Command_ tag, send [track](https://docs.tealium.com/platforms/swift/track/) calls with any applicable data and validate in your [Braze Dashboard](https://dashboard.braze.com/sign_in). | ||
[https://docs.tealium.com/platforms/remote-commands/integrations/braze/](https://docs.tealium.com/platforms/remote-commands/integrations/braze/) | ||
|
||
## License | ||
|
||
Use of this software is subject to the terms and conditions of the license agreement contained in the file titled [License.txt](License.txt). Please read the license before downloading or using any of the files contained in this repository. By downloading or using any of these files, you are agreeing to be bound by and comply with the license agreement. | ||
|
||
___ | ||
|
||
Copyright (C) 2012-2019, Tealium Inc. | ||
Use of this software is subject to the terms and conditions of the license agreement contained in the file titled "LICENSE.txt". Please read the license before downloading or using any of the files contained in this repository. By downloading or using any of these files, you are agreeing to be bound by and comply with the license agreement. | ||
|
||
|
||
--- | ||
Copyright (C) 2012-2019, Tealium Inc. |
Oops, something went wrong.