diff --git a/Cartfile b/Cartfile index f73838a..c3ad7ab 100644 --- a/Cartfile +++ b/Cartfile @@ -1,2 +1,2 @@ github "tealium/tealium-swift" -github "Appboy/appboy-ios-sdk" == 3.16.0 \ No newline at end of file +binary "https://raw.githubusercontent.com/Appboy/appboy-ios-sdk/master/appboy_ios_sdk_core.json" diff --git a/Cartfile.resolved b/Cartfile.resolved index 6935f7d..cedc2f0 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,3 +1,3 @@ -github "Appboy/appboy-ios-sdk" "3.16.0" -github "tealium/plcrashreporter" "1.3.5" -github "tealium/tealium-swift" "1.7.1" +binary "https://raw.githubusercontent.com/Appboy/appboy-ios-sdk/master/appboy_ios_sdk_core.json" "3.20.4" +binary "https://tags.tiqcdn.com/dle/tealiummobile/tealium-ios-carthage/tealium-carthage-plcrashreporter.json" "1.3.6" +github "tealium/tealium-swift" "1.7.3" diff --git a/Sources/BrazeCommand.swift b/Sources/BrazeCommand.swift index c47b968..f61044a 100644 --- a/Sources/BrazeCommand.swift +++ b/Sources/BrazeCommand.swift @@ -8,7 +8,13 @@ import UIKit import Appboy_iOS_SDK +#if COCOAPODS import TealiumSwift +#else +import TealiumCore +import TealiumTagManagement +import TealiumRemoteCommands +#endif public enum AppboyUserAttribute: String, CaseIterable { @@ -298,14 +304,13 @@ public class BrazeCommand { return } let prices = priceDouble.map { price in - NSDecimalNumber(floatLiteral: price) - + NSDecimalNumber(floatLiteral: price) } - var products = (productId: productIdentifier, price: prices) + let products = (productId: productIdentifier, price: prices) if let quantity = payload[AppboyKey.quantity] as? [Int] { let unsignedQty = quantity.map { UInt($0) } - var products = (productId: productIdentifier, price: prices, quantity: unsignedQty) + let products = (productId: productIdentifier, price: prices, quantity: unsignedQty) if let properties = payload[AppboyKey.purchaseProperties] as? [AnyHashable: Any] { for (index, element) in products.productId.enumerated() { return self.brazeTracker.logPurchase(element, currency: currency, price: products.price[index], quantity: products.quantity[index], properties: properties) diff --git a/Sources/BrazeTracker.swift b/Sources/BrazeTracker.swift index 462d124..4eff757 100644 --- a/Sources/BrazeTracker.swift +++ b/Sources/BrazeTracker.swift @@ -8,308 +8,314 @@ import Foundation import Appboy_iOS_SDK +#if COCOAPODS import TealiumSwift +#else +import TealiumCore +import TealiumTagManagement +import TealiumRemoteCommands +#endif public protocol TealiumApplication { } extension UIApplication: TealiumApplication { } public protocol BrazeTrackable { - - // 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() + + // 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) + func registerDeviceToken(_ deviceToken: Data) + + 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 BrazeTracker: BrazeTrackable, BrazeCommandNotifier { - - public init() { - - } - - 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]) { - _ = AppboyUserAttribute.allCases.map { - guard let value = attributes["\($0.rawValue)"] as? String else { - return - } - setUserAttribute(key: $0, value: value) + + public init() { + + } + + 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 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 logCustomEvent(eventName: String) { + Appboy.sharedInstance()?.logCustomEvent(eventName) } - } - - 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 logCustomEvent(_ eventName: String, properties: [AnyHashable: Any]) { + Appboy.sharedInstance()?.logCustomEvent(eventName, withProperties: properties) } - } - - 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 setUserAttributes(_ attributes: [String : Any]) { + _ = AppboyUserAttribute.allCases.map { + guard let value = attributes["\($0.rawValue)"] as? String else { + return + } + setUserAttribute(key: $0, value: 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 + + 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) + } } - 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 + + public func setCustomAttributes(_ attributes: [String : Any]) { + _ = attributes.map { attribute in + guard let value = attribute.value as? AnyHashable else { + return + } + setCustomAttributeWithKey(attribute.key, value: value) + } } - if let twitterName = user[SocialMediaKey.twitterName.rawValue] as? String { - twitterUser.twitterName = twitterName + + 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) + } } - if let profileImageUrl = user[SocialMediaKey.profileImageUrl.rawValue] as? String { - twitterUser.profileImageUrl = profileImageUrl + + public func unsetCustomAttributeWithKey(_ key: String) { + Appboy.sharedInstance()?.user.unsetCustomAttribute(withKey: key) } - if let screenName = user[SocialMediaKey.screenName.rawValue] as? String { - twitterUser.screenName = screenName + + public func incrementCustomUserAttribute(_ key: String, by: Int) { + Appboy.sharedInstance()?.user.incrementCustomUserAttribute(key, by: by) } - if let followersCount = user[SocialMediaKey.followersCount.rawValue] as? Int { - twitterUser.followersCount = followersCount + + public func setCustomAttributeArrayWithKey(_ key: String, array: [Any]?) { + Appboy.sharedInstance()?.user.setCustomAttributeArrayWithKey(key, array: array) } - if let friendsCount = user[SocialMediaKey.friendsCount.rawValue] as? Int { - twitterUser.friendsCount = friendsCount + + public func addToCustomAttributeArrayWithKey(_ key: String, value: String) { + Appboy.sharedInstance()?.user.addToCustomAttributeArray(withKey: key, value: value) } - if let statusesCount = user[SocialMediaKey.statusesCount.rawValue] as? Int { - twitterUser.statusesCount = statusesCount + + public func removeFromCustomAttributeArrayWithKey(_ key: String, value: String) { + Appboy.sharedInstance()?.user.removeFromCustomAttributeArray(withKey: key, value: value) } - if let twitterId = user[SocialMediaKey.twitterId.rawValue] as? Int { - twitterUser.twitterID = twitterId + + 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) } - 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 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 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 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 incrementCustomUserAttributes(_ attributes: [String: Int]) { - attributes.forEach { attribute in - incrementCustomUserAttribute(attribute.key, by: attribute.value) + + 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 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 registerDeviceToken(_ deviceToken: Data) { + Appboy.sharedInstance()?.registerDeviceToken(deviceToken) + } + + 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() } - } - - public func wipeData() { - Appboy.wipeDataAndDisableForAppRun() - } } diff --git a/Sources/Info.plist b/Sources/Info.plist index d80c0cf..82790df 100644 --- a/Sources/Info.plist +++ b/Sources/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 0.0.3 + $(MARKETING_VERSION) CFBundleVersion $(CURRENT_PROJECT_VERSION) diff --git a/TealiumBraze.podspec b/TealiumBraze.podspec index 266e86c..49e484b 100644 --- a/TealiumBraze.podspec +++ b/TealiumBraze.podspec @@ -3,7 +3,7 @@ Pod::Spec.new do |s| # ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # s.name = "TealiumBraze" s.module_name = "TealiumBraze" - s.version = "0.0.3" + s.version = "0.0.4" s.summary = "Tealium Swift and Braze integration" s.description = <<-DESC Tealium's integration with Braze for iOS. @@ -31,6 +31,6 @@ Pod::Spec.new do |s| # ――― Dependencies ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― # s.ios.dependency 'tealium-swift', '~> 1.7.1' - s.ios.dependency 'Appboy-iOS-SDK', '~> 3.16.0' + s.ios.dependency 'Appboy-iOS-SDK', '~> 3.20' end diff --git a/TealiumBraze.xcodeproj/project.pbxproj b/TealiumBraze.xcodeproj/project.pbxproj index 167087f..4fa560b 100644 --- a/TealiumBraze.xcodeproj/project.pbxproj +++ b/TealiumBraze.xcodeproj/project.pbxproj @@ -11,19 +11,45 @@ 4BCDE3E322E626AF000A501B /* BrazeCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BCDE3E022E626AF000A501B /* BrazeCommand.swift */; }; 4BCDE3E422E626AF000A501B /* BrazeTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BCDE3E122E626AF000A501B /* BrazeTracker.swift */; }; 4BCDE3E522E626AF000A501B /* DateConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BCDE3E222E626AF000A501B /* DateConverter.swift */; }; - 4BCDE3E922E6272D000A501B /* MockBrazeCommandRunner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BCDE3E722E6272D000A501B /* MockBrazeCommandRunner.swift */; }; - 4BCDE3EA22E6272D000A501B /* BrazeTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BCDE3E822E6272D000A501B /* BrazeTrackerTests.swift */; }; + 4BF49180236CC18C00CA46EC /* Appboy_iOS_SDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BF4917F236CC18C00CA46EC /* Appboy_iOS_SDK.framework */; }; + 4BF49182236CC19400CA46EC /* TealiumCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BF49181236CC19400CA46EC /* TealiumCore.framework */; }; + 4BF49184236CC19800CA46EC /* TealiumDelegate.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BF49183236CC19800CA46EC /* TealiumDelegate.framework */; }; + 4BF49186236CC19C00CA46EC /* TealiumRemoteCommands.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BF49185236CC19C00CA46EC /* TealiumRemoteCommands.framework */; }; + 4BF49188236CC1AE00CA46EC /* TealiumTagManagement.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4BF49187236CC1AE00CA46EC /* TealiumTagManagement.framework */; }; + 4BF49193236CC25700CA46EC /* TealiumBraze.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4B8DB65C22E622E00074687A /* TealiumBraze.framework */; }; + 4BF4919B236CC47000CA46EC /* BrazeTrackerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BCDE3E822E6272D000A501B /* BrazeTrackerTests.swift */; }; + 4BF4919C236CC47000CA46EC /* MockBrazeTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BCDE3E722E6272D000A501B /* MockBrazeTracker.swift */; }; + 4BF4919D236CC47000CA46EC /* HttpTestHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF49199236CC28000CA46EC /* HttpTestHelpers.swift */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 4BF49194236CC25700CA46EC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 4B8DB65322E622E00074687A /* Project object */; + proxyType = 1; + remoteGlobalIDString = 4B8DB65B22E622E00074687A; + remoteInfo = TealiumBraze; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXFileReference section */ + 4B38232C236CDDBF00C3AE37 /* SDWebImage.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDWebImage.framework; path = Carthage/Build/iOS/SDWebImage.framework; sourceTree = ""; }; 4B8DB65C22E622E00074687A /* TealiumBraze.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = TealiumBraze.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 4B8DB65F22E622E00074687A /* TealiumBraze.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TealiumBraze.h; sourceTree = ""; }; 4B8DB66022E622E00074687A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4BCDE3E022E626AF000A501B /* BrazeCommand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrazeCommand.swift; sourceTree = ""; }; 4BCDE3E122E626AF000A501B /* BrazeTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrazeTracker.swift; sourceTree = ""; }; 4BCDE3E222E626AF000A501B /* DateConverter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DateConverter.swift; sourceTree = ""; }; - 4BCDE3E722E6272D000A501B /* MockBrazeCommandRunner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockBrazeCommandRunner.swift; sourceTree = ""; }; + 4BCDE3E722E6272D000A501B /* MockBrazeTracker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockBrazeTracker.swift; sourceTree = ""; }; 4BCDE3E822E6272D000A501B /* BrazeTrackerTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrazeTrackerTests.swift; sourceTree = ""; }; + 4BF4917F236CC18C00CA46EC /* Appboy_iOS_SDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Appboy_iOS_SDK.framework; path = Carthage/Build/iOS/Appboy_iOS_SDK.framework; sourceTree = ""; }; + 4BF49181236CC19400CA46EC /* TealiumCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TealiumCore.framework; path = Carthage/Build/iOS/TealiumCore.framework; sourceTree = ""; }; + 4BF49183236CC19800CA46EC /* TealiumDelegate.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TealiumDelegate.framework; path = Carthage/Build/iOS/TealiumDelegate.framework; sourceTree = ""; }; + 4BF49185236CC19C00CA46EC /* TealiumRemoteCommands.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TealiumRemoteCommands.framework; path = Carthage/Build/iOS/TealiumRemoteCommands.framework; sourceTree = ""; }; + 4BF49187236CC1AE00CA46EC /* TealiumTagManagement.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TealiumTagManagement.framework; path = Carthage/Build/iOS/TealiumTagManagement.framework; sourceTree = ""; }; + 4BF4918E236CC25700CA46EC /* TealiumBrazeTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TealiumBrazeTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 4BF49192236CC25700CA46EC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 4BF49199236CC28000CA46EC /* HttpTestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HttpTestHelpers.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -31,6 +57,19 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 4BF49180236CC18C00CA46EC /* Appboy_iOS_SDK.framework in Frameworks */, + 4BF49182236CC19400CA46EC /* TealiumCore.framework in Frameworks */, + 4BF49186236CC19C00CA46EC /* TealiumRemoteCommands.framework in Frameworks */, + 4BF49184236CC19800CA46EC /* TealiumDelegate.framework in Frameworks */, + 4BF49188236CC1AE00CA46EC /* TealiumTagManagement.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 4BF4918B236CC25700CA46EC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4BF49193236CC25700CA46EC /* TealiumBraze.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -43,6 +82,7 @@ 4B8DB65E22E622E00074687A /* Sources */, 4BCDE3E622E626E4000A501B /* Tests */, 4B8DB65D22E622E00074687A /* Products */, + 4BF4917E236CC18C00CA46EC /* Frameworks */, ); sourceTree = ""; }; @@ -50,6 +90,7 @@ isa = PBXGroup; children = ( 4B8DB65C22E622E00074687A /* TealiumBraze.framework */, + 4BF4918E236CC25700CA46EC /* TealiumBrazeTests.xctest */, ); name = Products; sourceTree = ""; @@ -70,11 +111,26 @@ isa = PBXGroup; children = ( 4BCDE3E822E6272D000A501B /* BrazeTrackerTests.swift */, - 4BCDE3E722E6272D000A501B /* MockBrazeCommandRunner.swift */, + 4BCDE3E722E6272D000A501B /* MockBrazeTracker.swift */, + 4BF49199236CC28000CA46EC /* HttpTestHelpers.swift */, + 4BF49192236CC25700CA46EC /* Info.plist */, ); path = Tests; sourceTree = ""; }; + 4BF4917E236CC18C00CA46EC /* Frameworks */ = { + isa = PBXGroup; + children = ( + 4B38232C236CDDBF00C3AE37 /* SDWebImage.framework */, + 4BF49187236CC1AE00CA46EC /* TealiumTagManagement.framework */, + 4BF49185236CC19C00CA46EC /* TealiumRemoteCommands.framework */, + 4BF49183236CC19800CA46EC /* TealiumDelegate.framework */, + 4BF49181236CC19400CA46EC /* TealiumCore.framework */, + 4BF4917F236CC18C00CA46EC /* Appboy_iOS_SDK.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -97,6 +153,7 @@ 4B8DB65822E622E00074687A /* Sources */, 4B8DB65922E622E00074687A /* Frameworks */, 4B8DB65A22E622E00074687A /* Resources */, + 4BF49189236CC1C700CA46EC /* Carthage */, ); buildRules = ( ); @@ -107,12 +164,31 @@ productReference = 4B8DB65C22E622E00074687A /* TealiumBraze.framework */; productType = "com.apple.product-type.framework"; }; + 4BF4918D236CC25700CA46EC /* TealiumBrazeTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 4BF49196236CC25700CA46EC /* Build configuration list for PBXNativeTarget "TealiumBrazeTests" */; + buildPhases = ( + 4BF4918A236CC25700CA46EC /* Sources */, + 4BF4918B236CC25700CA46EC /* Frameworks */, + 4BF4918C236CC25700CA46EC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 4BF49195236CC25700CA46EC /* PBXTargetDependency */, + ); + name = TealiumBrazeTests; + productName = TealiumBrazeTests; + productReference = 4BF4918E236CC25700CA46EC /* TealiumBrazeTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 4B8DB65322E622E00074687A /* Project object */ = { isa = PBXProject; attributes = { + LastSwiftUpdateCheck = 1110; LastUpgradeCheck = 1010; ORGANIZATIONNAME = "Jonathan Wong"; TargetAttributes = { @@ -120,6 +196,9 @@ CreatedOnToolsVersion = 10.1; LastSwiftMigration = 1010; }; + 4BF4918D236CC25700CA46EC = { + CreatedOnToolsVersion = 11.1; + }; }; }; buildConfigurationList = 4B8DB65622E622E00074687A /* Build configuration list for PBXProject "TealiumBraze" */; @@ -135,6 +214,7 @@ projectRoot = ""; targets = ( 4B8DB65B22E622E00074687A /* TealiumBraze */, + 4BF4918D236CC25700CA46EC /* TealiumBrazeTests */, ); }; /* End PBXProject section */ @@ -147,23 +227,72 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 4BF4918C236CC25700CA46EC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 4BF49189236CC1C700CA46EC /* Carthage */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "$(SRCROOT)/Carthage/Build/iOS/Appboy_iOS_SDK.framework", + "$(SRCROOT)/Carthage/Build/iOS/TealiumCore.framework", + "$(SRCROOT)/Carthage/Build/iOS/TealiumRemoteCommands.framework", + "$(SRCROOT)/Carthage/Build/iOS/TealiumDelegate.framework", + "$(SRCROOT)/Carthage/Build/iOS/TealiumTagManagement.framework", + ); + name = Carthage; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/usr/local/bin/carthage copy-frameworks\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 4B8DB65822E622E00074687A /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 4BCDE3E422E626AF000A501B /* BrazeTracker.swift in Sources */, - 4BCDE3EA22E6272D000A501B /* BrazeTrackerTests.swift in Sources */, 4BCDE3E322E626AF000A501B /* BrazeCommand.swift in Sources */, - 4BCDE3E922E6272D000A501B /* MockBrazeCommandRunner.swift in Sources */, 4BCDE3E522E626AF000A501B /* DateConverter.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; + 4BF4918A236CC25700CA46EC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 4BF4919B236CC47000CA46EC /* BrazeTrackerTests.swift in Sources */, + 4BF4919C236CC47000CA46EC /* MockBrazeTracker.swift in Sources */, + 4BF4919D236CC47000CA46EC /* HttpTestHelpers.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 4BF49195236CC25700CA46EC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 4B8DB65B22E622E00074687A /* TealiumBraze */; + targetProxy = 4BF49194236CC25700CA46EC /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin XCBuildConfiguration section */ 4B8DB66222E622E00074687A /* Debug */ = { isa = XCBuildConfiguration; @@ -298,14 +427,19 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MARKETING_VERSION = 0.0.4; PRODUCT_BUNDLE_IDENTIFIER = com.tealium.TealiumBraze; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -326,14 +460,19 @@ DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); INFOPLIST_FILE = "$(SRCROOT)/Sources/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", "@loader_path/Frameworks", ); + MARKETING_VERSION = 0.0.4; PRODUCT_BUNDLE_IDENTIFIER = com.tealium.TealiumBraze; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; @@ -342,6 +481,52 @@ }; name = Release; }; + 4BF49197236CC25700CA46EC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = XC939GDC9P; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); + INFOPLIST_FILE = Tests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.tealium.TealiumBrazeTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 4BF49198236CC25700CA46EC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = XC939GDC9P; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PROJECT_DIR)/Carthage/Build/iOS", + ); + INFOPLIST_FILE = Tests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.1; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@loader_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.tealium.TealiumBrazeTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -363,6 +548,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 4BF49196236CC25700CA46EC /* Build configuration list for PBXNativeTarget "TealiumBrazeTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 4BF49197236CC25700CA46EC /* Debug */, + 4BF49198236CC25700CA46EC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 4B8DB65322E622E00074687A /* Project object */; diff --git a/TealiumBraze.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/TealiumBraze.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/TealiumBraze.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/TealiumBraze.xcodeproj/xcshareddata/xcschemes/TealiumBraze.xcscheme b/TealiumBraze.xcodeproj/xcshareddata/xcschemes/TealiumBraze.xcscheme index b88a150..2e9a1bd 100644 --- a/TealiumBraze.xcodeproj/xcshareddata/xcschemes/TealiumBraze.xcscheme +++ b/TealiumBraze.xcodeproj/xcshareddata/xcschemes/TealiumBraze.xcscheme @@ -29,8 +29,6 @@ shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/BrazeTrackerTests.swift b/Tests/BrazeTrackerTests.swift index 6ebec7d..00e74e1 100644 --- a/Tests/BrazeTrackerTests.swift +++ b/Tests/BrazeTrackerTests.swift @@ -8,7 +8,14 @@ import XCTest @testable import TealiumBraze -@testable import TealiumSwift +#if COCOAPODS +//@testable import TealiumSwift +#else +//@testable import TealiumCore +//@testable import TealiumTagManagement +import TealiumRemoteCommands +#endif + class BrazeTrackerTests: XCTestCase { @@ -27,7 +34,7 @@ class BrazeTrackerTests: XCTestCase { func testInitializeIsNotCalledWithoutApiKey() { let expect = expectation(description: "test initialize") - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", payload: [ "command_name": "initialize", ])?.description { @@ -44,7 +51,7 @@ class BrazeTrackerTests: XCTestCase { func testInitializeCalledWithApiKey() { let expect = expectation(description: "test initialize") - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", payload: [ "command_name": "initialize", "api_key": "test123" @@ -63,7 +70,7 @@ class BrazeTrackerTests: XCTestCase { func testChangeUserIdentifierCalledSuccess() { let expect = expectation(description: "test initialize") let userIdentifier = "tealium-ios-test-user" - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", payload: [ "command_name": "initialize,useridentifier", "user_id": userIdentifier @@ -81,7 +88,7 @@ class BrazeTrackerTests: XCTestCase { func testChangeUserIdentifierNotCalled_userIdentifierKeyMissing() { let expect = expectation(description: "test user identifier") - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", payload: [ "command_name": "initialize,useridentifier" ])?.description { @@ -102,7 +109,7 @@ class BrazeTrackerTests: XCTestCase { let payload: [String: Any] = ["command_name": "initialize,useralias", "user_alias": "test_alias" ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -124,7 +131,7 @@ class BrazeTrackerTests: XCTestCase { "user_alias": "test_alias", "alias_label": "alias_label" ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -141,7 +148,7 @@ class BrazeTrackerTests: XCTestCase { func testLogCustomEventSuccess() { let expect = expectation(description: "test log event") - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", payload: [ "command_name": "initialize,lOGcustomEvent", "event_name": "test_event" @@ -159,7 +166,7 @@ class BrazeTrackerTests: XCTestCase { func testLogCustomEventNotCalled_logCustomEventNameMissing() { let expect = expectation(description: "test log event") - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", payload: [ "command_name": "initialize,lOGcustomEvent" ])?.description { @@ -183,7 +190,7 @@ class BrazeTrackerTests: XCTestCase { "key1": "value1", "key2": "value2", "key3": "value3"]] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -208,7 +215,7 @@ class BrazeTrackerTests: XCTestCase { "key1": "value1", "key2": "value2", "key3": "value3"]] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -227,7 +234,7 @@ class BrazeTrackerTests: XCTestCase { func testUserAttributesSet() { let expect = expectation(description: "test user attribute set") let dateString = Date().iso8601String - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", payload: [ "command_name": "initialize,useridentifier,userAttribute", "first_name": "first_name_test", @@ -254,7 +261,7 @@ class BrazeTrackerTests: XCTestCase { func testUserAttributesSetOnlyCallsAppboyUserAttributeKeys() { let expect = expectation(description: "test user attribute set") - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", payload: [ "command_name": "initialize,useridentifier,userAttribute", "first_name": "first_name_test", @@ -289,7 +296,7 @@ class BrazeTrackerTests: XCTestCase { "likes": ["apple", "orange"] ] ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -314,7 +321,7 @@ class BrazeTrackerTests: XCTestCase { "likes": [] ] ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -339,7 +346,7 @@ class BrazeTrackerTests: XCTestCase { "doublekey": 2.0, "stringkey": "test_string"] ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -363,7 +370,7 @@ class BrazeTrackerTests: XCTestCase { "doublekey": 2.0, "stringkey": "test_string" ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -383,7 +390,7 @@ class BrazeTrackerTests: XCTestCase { let config: [String: Any] = ["response_id": "1234"] let payload: [String: Any] = ["command_name": "initialize,unsetcustomattribute" ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -404,7 +411,7 @@ class BrazeTrackerTests: XCTestCase { let payload: [String: Any] = ["command_name": "initialize,unsetcustomattribute", "unset_custom_attribute": "attribute_key" ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -426,7 +433,7 @@ class BrazeTrackerTests: XCTestCase { "increment_custom_attribute": ["key1": 1, "key2": 2] ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -451,7 +458,7 @@ class BrazeTrackerTests: XCTestCase { "array_key3": ["value1", "value2", "value3"], ] ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -476,7 +483,7 @@ class BrazeTrackerTests: XCTestCase { "array_key3": "value3" ] ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -501,7 +508,7 @@ class BrazeTrackerTests: XCTestCase { "array_key3": "value3" ] ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -522,7 +529,7 @@ class BrazeTrackerTests: XCTestCase { let payload: [String: Any] = ["command_name": "initialize,emailnotification", "email_notification": "optedIn" ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -543,7 +550,7 @@ class BrazeTrackerTests: XCTestCase { let payload: [String: Any] = ["command_name": "initialize,emailnotification", "email_notification": "UN subscribed" ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -564,7 +571,7 @@ class BrazeTrackerTests: XCTestCase { let payload: [String: Any] = ["command_name": "initialize,pushnotification", "push_notification": "subscribed" ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -585,7 +592,7 @@ class BrazeTrackerTests: XCTestCase { let payload: [String: Any] = ["command_name": "initialize,pushnotification", "email_notification": "SUBscribed" ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -604,10 +611,10 @@ class BrazeTrackerTests: XCTestCase { let expect = expectation(description: "test log purchase") let config: [String: Any] = ["response_id": "1234"] let payload: [String: Any] = ["command_name": "initialize,logpurchase", - "currency": "USD", - "price": 12.34 + "order_currency": "USD", + "product_unit_price": 12.34 ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -627,9 +634,9 @@ class BrazeTrackerTests: XCTestCase { let config: [String: Any] = ["response_id": "1234"] let payload: [String: Any] = ["command_name": "initialize,logpurchase", "product_id": "123", - "price": 12.34 + "product_unit_price": 12.34 ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -649,9 +656,9 @@ class BrazeTrackerTests: XCTestCase { let config: [String: Any] = ["response_id": "1234"] let payload: [String: Any] = ["command_name": "initialize,logpurchase", "product_id": "123", - "currency": "USD" + "order_currency": "USD" ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -671,10 +678,10 @@ class BrazeTrackerTests: XCTestCase { let config: [String: Any] = ["response_id": "1234"] let payload: [String: Any] = ["command_name": "initialize,logpurchase", "product_id": ["123"], - "currency": "USD", - "price": [12.34] + "order_currency": "USD", + "product_unit_price": [12.34] ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -697,11 +704,11 @@ class BrazeTrackerTests: XCTestCase { let config: [String: Any] = ["response_id": "1234"] let payload: [String: Any] = ["command_name": "initialize,logpurchase", "product_id": ["123"], - "currency": "USD", - "price": [12.34], + "order_currency": "USD", + "product_unit_price": [12.34], "quantity": [5] ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -724,11 +731,11 @@ class BrazeTrackerTests: XCTestCase { let config: [String: Any] = ["response_id": "1234"] let payload: [String: Any] = ["command_name": "initialize,logpurchase", "product_id": ["123"], - "currency": "USD", - "price": [12.34], + "order_currency": "USD", + "product_unit_price": [12.34], "purchase_properties": ["item1": 123] ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -751,12 +758,12 @@ class BrazeTrackerTests: XCTestCase { let config: [String: Any] = ["response_id": "1234"] let payload: [String: Any] = ["command_name": "initialize,logpurchase", "product_id": ["123", "456"], - "currency": "USD", - "price": [12.34, 1.99], + "order_currency": "USD", + "product_unit_price": [12.34, 1.99], "quantity": [1, 2], "purchase_properties": ["item1": 123] ] - if let brazeResponse = HttpHelpers.httpRequest(commandId: "braze", + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", config: config, payload: payload )?.description { @@ -773,4 +780,60 @@ class BrazeTrackerTests: XCTestCase { } wait(for: [expect], timeout: 5.0) } + + func testDisableSDK() { + let expect = expectation(description: "sdk is disabled") + let config: [String: Any] = ["response_id": "1234"] + let payload: [String: Any] = ["command_name": "enablesdk", + "enable_sdk": false] + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", + config: config, + payload: payload + )?.description { + let remoteCommandResponse = TealiumRemoteCommandResponse(urlString: brazeResponse) + if let response = remoteCommandResponse { + remoteCommand.remoteCommandCompletion(response) + XCTAssertEqual(1, brazeTracker.disableCallCount) + } + expect.fulfill() + } + wait(for: [expect], timeout: 3.0) + } + + func testReenableSDK() { + let expect = expectation(description: "sdk is reenabled") + let config: [String: Any] = ["response_id": "1234"] + let payload: [String: Any] = ["command_name": "enablesdk", + "enable_sdk": true] + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", + config: config, + payload: payload + )?.description { + let remoteCommandResponse = TealiumRemoteCommandResponse(urlString: brazeResponse) + if let response = remoteCommandResponse { + remoteCommand.remoteCommandCompletion(response) + XCTAssertEqual(1, brazeTracker.reEnableCallCount) + } + expect.fulfill() + } + wait(for: [expect], timeout: 3.0) + } + + func testWipeData() { + let expect = expectation(description: "wipe data is called") + let config: [String: Any] = ["response_id": "1234"] + let payload: [String: Any] = ["command_name": "wipedata"] + if let brazeResponse = HttpTestHelpers.httpRequest(commandId: "braze", + config: config, + payload: payload + )?.description { + let remoteCommandResponse = TealiumRemoteCommandResponse(urlString: brazeResponse) + if let response = remoteCommandResponse { + remoteCommand.remoteCommandCompletion(response) + XCTAssertEqual(1, brazeTracker.wipeDataCallCount) + } + expect.fulfill() + } + wait(for: [expect], timeout: 3.0) + } } diff --git a/Tests/HttpTestHelpers.swift b/Tests/HttpTestHelpers.swift new file mode 100644 index 0000000..adfb43f --- /dev/null +++ b/Tests/HttpTestHelpers.swift @@ -0,0 +1,56 @@ +// +// HttpTestHelpers.swift +// TealiumBraze +// +// Created by Jonathan Wong on 8/8/19. +// Copyright © 2019 Jonathan Wong. All rights reserved. +// + +import Foundation + +struct RemoteCommandResponsePayload: Codable { + var config: [String: String] + var payload: [String: String] +} + +class HttpTestHelpers { + class func httpRequest(commandId: String, payload: [String: String]) -> URLRequest? { + let url = "tealium://\(commandId)?request=" + + let response = RemoteCommandResponsePayload(config: ["response_id": "00000"], payload: payload) + + let encoder = JSONEncoder() + let json = try? encoder.encode(response) + + if let json = json, let encodedString = String(data: json, encoding: .utf8)?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: "\(url)\(encodedString)") { + return URLRequest(url: url) + } + + return nil + } + + class func httpRequest(commandId: String, config: [String: Any], payload: [String: Any]) -> URLRequest? { + let url = "tealium://\(commandId)?request=" + let remoteCommandrc = ["config": config, "payload": payload] as [String: Any] + let json = try! JSONSerialization.data(withJSONObject: remoteCommandrc, options: .prettyPrinted) + if let encodedString = String(data: json, encoding: .utf8)?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: "\(url)\(encodedString)") { + print(encodedString) + return URLRequest(url: url) + } + + return nil + } + + class func httpRequestDescription(commandId: String, config: [String: Any], payload: [String: Any]) -> String? { + let url = "tealium://\(commandId)?request=" + let remoteCommandrc = ["config": config, "payload": payload] as [String: Any] + let json = try! JSONSerialization.data(withJSONObject: remoteCommandrc, options: .prettyPrinted) + if let encodedString = String(data: json, encoding: .utf8)?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let url = URL(string: "\(url)\(encodedString)") { + print(encodedString) + return URLRequest(url: url).description + } + + return nil + } + +} diff --git a/Tests/Info.plist b/Tests/Info.plist new file mode 100644 index 0000000..64d65ca --- /dev/null +++ b/Tests/Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + + diff --git a/Tests/MockBrazeCommandRunner.swift b/Tests/MockBrazeTracker.swift similarity index 92% rename from Tests/MockBrazeCommandRunner.swift rename to Tests/MockBrazeTracker.swift index 1bdcd0d..cb5155c 100644 --- a/Tests/MockBrazeCommandRunner.swift +++ b/Tests/MockBrazeTracker.swift @@ -1,5 +1,5 @@ // -// MockBrazeCommandRunner.swift +// MockBrazeTracker.swift // RemoteCommandModulesTests // // Created by Jonathan Wong on 11/16/18. @@ -8,7 +8,7 @@ import Foundation @testable import TealiumBraze -@testable import TealiumSwift +//@testable import TealiumSwift class MockBrazeTracker: BrazeTrackable { @@ -33,6 +33,9 @@ class MockBrazeTracker: BrazeTrackable { var logPurchaseWithQuantityWithPropertiesCallCount = 0 var registerPushTokenCallCount = 0 var pushAuthorizationCallCount = 0 + var disableCallCount = 0 + var reEnableCallCount = 0 + var wipeDataCallCount = 0 func initializeBraze(apiKey: String, application: TealiumApplication, launchOptions: [AnyHashable: Any]?) { initializeBrazeCallCount += 1 @@ -150,4 +153,20 @@ class MockBrazeTracker: BrazeTrackable { pushAuthorizationCallCount += 1 } + func enableSDK(_ enabled: Bool) { + if enabled { + reEnableCallCount += 1 + } else { + disableSDK() + } + } + + func disableSDK() { + disableCallCount += 1 + } + + func wipeData() { + wipeDataCallCount += 1 + } + }